PreSignUp_ExternalProvider gaps in AWS Cognito

PreSignUp_ExternalProvider gaps in AWS Cognito

AWS Cognito lets a single user pool register multiple external OIDC and SAML identity providers. Those providers can feed the hosted UI or a custom login page that still uses Cognito hosted SSO endpoints. The dangerous part is not the login page. It is the moment Cognito turns claims into a user record.

The first federated login is the point where the claim becomes state. If validation misses that step, the account is already in the pool and the damage has shifted from prevention to cleanup.

Where first-login checks are the only thing standing between an IdP claim and a user record

Federated sign-in does not follow the same path as native username and password authentication. Cognito performs the OIDC code flow, fetches claims from the identity provider, merges them with the configured attribute mapping, and then moves towards user creation. Several trigger types never see that path at all.

That matters because the first login is not a harmless probe. If the external identity is accepted once, the user object exists and can stick around until somebody removes it by hand.

The federated sign-in path that skips the usual Cognito trigger chain

Cognito does not call the usual custom authentication challenge, migrate user, custom message, or custom sender triggers during federated sign-in. The trigger chain is thinner than many setups assume. Validation that sits in the wrong place simply never runs.

PreSignUp_ExternalProvider is the gate before persistence. InboundFederation_ExternalProvider is also part of the inbound federated path and fires before the record write on every federated sign-in. Those are the points where domain, issuer, and attribute checks still matter.

What breaks when validation sits in the wrong trigger

PostConfirmation_ConfirmSignUp comes after confirmation, which includes auto-confirm on first federated login. By then, the user record already exists. PreAuthentication_Authentication only runs on later logins, so it misses the first one entirely. PostAuthentication_Authentication runs after a successful authentication, which is good for audit and useless for blocking the session.

That is the common failure pattern. The check exists, but in the wrong room.

Checks in PostConfirmation, PreAuthentication, or PostAuthentication arrive too late

A domain allowlist in PostConfirmation does not stop persistence. A group or issuer check in PreAuthentication does not protect the initial federated account. PostAuthentication can show that something happened, but it cannot stop it.

Once the user is created in the pool, there is no automatic rollback. Manual deletion becomes part of the response, and that leaves a small window where the account can still be used.

Attribute mapping and JIT provisioning can carry bad identity data straight through

Attribute mapping is convenient and slightly dangerous. Cognito takes the mapped claims and uses them to shape the user object. If the IdP sends an email, domain, display name, or custom attribute that should not be trusted, the mapping can move it into the pool before later checks notice.

JIT provisioning makes the same mistake feel tidy. The account appears automatically, which is handy until the external claim is wrong, unauthorised, or deliberately chosen to look valid. At that point, the problem is not sign-in failure. It is a durable record with bad identity data attached.

Closing the gap with controls that fire on every federated login

The boundary belongs in the federated trigger path, not in downstream authentication events. Domain checks, issuer checks, and attribute checks need to run in PreSignUp_ExternalProvider and again in InboundFederation_ExternalProvider if the pool accepts repeated federated updates.

A single pass is brittle. If the first login is clean but later claims drift, the second path needs the same scrutiny. That is the part many setups miss because the first account already looks legitimate.

Put domain, attribute, and issuer checks into PreSignUpExternalProvider and InboundFederationExternalProvider

PreSignUp_ExternalProvider should block creation when the issuer is unexpected, the email domain is outside policy, or mapped attributes do not meet the pool’s rules. InboundFederation_ExternalProvider should repeat the same decisions before each federated write. That keeps one accepted claim from becoming a permanent account and stops later claim changes from quietly rewriting the identity.

Keep the checks boring and strict. Hard-code allowed issuers, validate email domains against a short list, and reject attributes that are missing, malformed, or pulled from fields that should never drive authorisation. If a claim is only safe after a separate trust decision, do not map it into the user record at all.

Verify cleanup, logging, and rollback plans for accounts that already slipped through

The pool will not clean up for you. If a bad federated account lands, deletion has to be handled manually or by your own automation. Logging needs to show which trigger accepted the identity, which claims were mapped, and why the record was allowed to persist.

Rollback is awkward once the account exists. Disable access, delete the user, review any sessions or tokens already issued, and check whether the account touched anything with broader rights. A forceful password reset can also create a non-SSO path if the account was not meant to have one. That is the sort of tidy little surprise nobody wants in an incident report.

If federated identity is allowed into a Cognito pool, the first trigger that runs before persistence matters more than the rest.

Tags:

Related posts

Weekly Tech Digest | 06 Jul 2026

Stay updated with the latest in tech! This digest covers AI ethics, auto industry shifts, and the impact of politics on technology, exploring today's pressing issues.

wolfCOSE zero-allocation parsing in embedded C

wolfCOSE looks sensible only if you care about what your firmware actually has to carry. I like that, because on small targets the wrong crypto feature can cost more than the message itself, and there...

restic | v0.19.1

restic v0 19 1: safer FUSE mounts and mountpoint checks, robust backup source and exclude handling, clearer CLI JSON output, Windows SFTP deletion fixes