fix(identity): link an email-optional identity to a phone-only user - #2699
Open
hamodywe wants to merge 1 commit into
Open
fix(identity): link an email-optional identity to a phone-only user#2699hamodywe wants to merge 1 commit into
hamodywe wants to merge 1 commit into
Conversation
Linking an email-optional identity (for example an OIDC provider whose claim carries no email) to a confirmed phone-only user returned a spurious 422 email_not_confirmed. UpdateUserEmailFromIdentities leaves the primary email empty in that case, but the linking path still called sendConfirmation and rejected the link with EmailNotConfirmed. Guard the email-confirmation block on the resulting email being non-empty, keeping the anonymous->permanent transition outside it so a no-email link still de-anonymizes. Behaviour is unchanged when the linked identity does carry an email (verified confirms, unverified still requires confirmation). Adds TestLinkIdentityToUserEmailOptional covering the no-email regression and an unverified-email control case. Fixes supabase#2640.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Linking an email-optional identity (for example an OIDC provider whose claim
carries no email) to a confirmed phone-only user currently fails with
422 email_not_confirmed, even though there is no email to confirm.Fixes #2640.
Why it happens
In
linkIdentityToUser(internal/api/identity.go), when the target user hasno primary email the code does:
UpdateUserEmailFromIdentitiespicks the highest-ranked identity's email, and anemail-optional identity contributes none — so the primary email is still empty
after the call. Because the OIDC claim also has
email_verified = false, the!EmailVerifiedbranch runs and a confirmation email is "sent" for an addressthat does not exist, and the link is rejected with
email_not_confirmed.#634added support for providers without an email, but this linking path stillassumes an unverified email is always present.
The fix
Only run the email-confirmation logic when an email is actually present after
UpdateUserEmailFromIdentities:The anonymous→permanent transition stays outside that guard, so an anonymous
user that links a no-email identity is still de-anonymized. Behaviour is
unchanged whenever the linked identity does carry an email:
email_not_confirmed(confirmation sent)email_not_confirmed(spurious)Tests
TestLinkIdentityToUserEmailOptionalininternal/api/identity_test.go, two sub-cases:a confirmed phone-only user links an email-less OIDC identity; asserts success,
the phone is preserved, the email stays empty, and the identity is created.
case proving the fix does not over-broaden: an identity that does carry an
unverified email still returns
email_not_confirmed.Verification
go vet ./internal/api/clean,go test -c ./internal/api/(compiles the fullsuite incl. these tests) clean,
gofmtclean.internal/apitests are Postgres-backed(
-p 1 -race) and this dev machine has no Docker/Postgres/cgo, so I could notexecute the suite locally. The tests are written to the suite's existing
patterns and are intended to run on CI's Postgres matrix. Expected result there:
sub-case 1 passes with the fix and fails (
422 email_not_confirmed) ifidentity.gois reverted — i.e. genuine regression coverage — and sub-case 2passes unchanged.
than a phone-only one, because a phone-only user's empty-email phone identity
makes
UpdateUserEmailFromIdentitieskeep the empty email (its "an identityalready uses this email" early-return matches
"" == ""), so no email ispromoted and there would be nothing to confirm — which is exactly the mechanism
behind the bug this PR fixes.