Federated account linking: provider-name casing
The symptom
A user who already has an email/password account signs in with Google or Apple and the app shows:
OAuthSignInException: PreSignUp failed with error SourceProviderName must match
a Provider that is configured for the User Pool.
It only happens on the link path, when the federated email matches an existing native account. Brand-new federated users never reach it.
The cause
The PreSignUp trigger (*-cognito-presignup-link) links the incoming social identity to the native account with AdminLinkProviderForUser. It reads the provider name from the prefix of the federated username Cognito hands it (Google_1094…). AdminLinkProviderForUser matches that name against the pool’s providers case-sensitively.
Whether the prefix keeps its casing depends on the pool, and the setting cannot be changed after the pool is created:
| Pool | UsernameConfiguration.CaseSensitive |
Prefix the trigger receives |
|---|---|---|
phenom-prod (us-east-1_knEL7cqS3) |
not set (case-sensitive) | Google_…, SignInWithApple_… |
phenom-staging (us-east-1_n8gO6SbP6) |
false |
google_…, signinwithapple_… |
A case-insensitive pool lowercases the whole username, prefix included. So the same Lambda code linked fine on prod and failed on staging. CloudTrail showed this directly:
2026-09-25T03:39:11Z prod src=Google ok
2026-09-25T03:31:17Z staging src=google InvalidParameterException
The fix
The linker resolves the parsed prefix against the pool’s configured provider names, ignoring case (canonicalizeProviderName in link-helpers.js, fed by a per-container cached ListIdentityProviders). On prod it is a no-op. If the lookup fails it falls back to the parsed name. The role carries read-only cognito-idp:ListIdentityProviders for this.
Both environments run the same linker code. Keep them byte-identical: diff -r the two pre-signup-link-provider/ directories under phenom-infra/environments/ before merging any change to either.
Diagnosing a recurrence
Check what provider name was actually sent, rather than inferring it:
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=AdminLinkProviderForUser \
--max-results 20 --query 'Events[].CloudTrailEvent' --output json \
| jq -r '.[]|fromjson|"\(.eventTime) \(.requestParameters.userPoolId) src=\(.requestParameters.sourceUser.providerName) err=\(.errorCode // "ok")"'
Then compare against the pool’s providers:
aws cognito-idp list-identity-providers --user-pool-id <pool> \
--query 'Providers[].ProviderName'
Tracked in phenom-infra#321.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.