From ae8d345836f070d7d0a55c0618c6a652931dbf62 Mon Sep 17 00:00:00 2001 From: deepshekhardas Date: Tue, 18 Aug 2026 19:55:37 +0530 Subject: [PATCH 1/4] fix(external): use email_address_not_provided instead of 500 when provider omits email (fixes #2583) --- internal/api/external.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/api/external.go b/internal/api/external.go index 14bdfe087b..acf352fdd3 100644 --- a/internal/api/external.go +++ b/internal/api/external.go @@ -182,7 +182,7 @@ func (a *API) internalExternalProviderCallback(w http.ResponseWriter, r *http.Re userData := data.userData if len(userData.Emails) == 0 && !emailOptional { - return apierrors.NewInternalServerError("Error getting user email from external provider") + return apierrors.NewUnprocessableEntityError(apierrors.ErrorCodeEmailAddressNotProvided, "Error getting user email from external provider") } userData.Metadata.EmailVerified = false From be4f1ab800c69f3a8a83405ba4e083ff904becb2 Mon Sep 17 00:00:00 2001 From: deepshekhardas Date: Tue, 18 Aug 2026 19:57:35 +0530 Subject: [PATCH 2/4] fix(identity): update last_sign_in_at on subsequent external sign-ins (fixes #2563) --- internal/api/external.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/api/external.go b/internal/api/external.go index acf352fdd3..8ed87ff9d6 100644 --- a/internal/api/external.go +++ b/internal/api/external.go @@ -384,7 +384,9 @@ func (a *API) createAccountFromExternalIdentity(tx *storage.Connection, r *http. user = decision.User identity = decision.Identities[0] + now := time.Now() identity.IdentityData = identityData + identity.LastSignInAt = &now if terr = tx.UpdateOnly(identity, "identity_data", "last_sign_in_at"); terr != nil { return 0, nil, terr } From 0258f0428eba6cb4e855619d7b805929c9f52a85 Mon Sep 17 00:00:00 2001 From: deepshekhardas Date: Tue, 18 Aug 2026 19:59:45 +0530 Subject: [PATCH 3/4] fix(hooks): send_email payload site_url should use GOTRUE_SITE_URL (fixes #2558) --- internal/api/mail.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/api/mail.go b/internal/api/mail.go index 9a42651c42..6cc48151d4 100644 --- a/internal/api/mail.go +++ b/internal/api/mail.go @@ -838,7 +838,7 @@ func (a *API) sendEmail(r *http.Request, tx *storage.Connection, u *models.User, Token: otp, EmailActionType: params.emailActionType, RedirectTo: referrerURL, - SiteURL: externalURL.String(), + SiteURL: config.SiteURL, TokenHash: params.tokenHashWithPrefix, } if params.emailActionType == mail.EmailChangeVerification { From 2f1cf35f6a76c6439d6a56f9c52aadb2c9088956 Mon Sep 17 00:00:00 2001 From: deepshekhardas Date: Tue, 18 Aug 2026 20:02:57 +0530 Subject: [PATCH 4/4] fix(admin): generateLink email_change_new hashed_token must match stored token (fixes #2538) --- internal/api/mail.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/api/mail.go b/internal/api/mail.go index 6cc48151d4..39c2af64dc 100644 --- a/internal/api/mail.go +++ b/internal/api/mail.go @@ -258,7 +258,8 @@ func (a *API) adminGenerateLink(w http.ResponseWriter, r *http.Request) error { if params.Type == "email_change_current" { user.EmailChangeTokenCurrent = hashedToken } else if params.Type == "email_change_new" { - user.EmailChangeTokenNew = crypto.GenerateTokenHash(params.NewEmail, otp) + hashedToken = crypto.GenerateTokenHash(params.NewEmail, otp) + user.EmailChangeTokenNew = hashedToken } terr = tx.UpdateOnly(user, "email_change_token_current", "email_change_token_new", "email_change", "email_change_sent_at", "email_change_confirm_status") if terr != nil {