AWS Cognito PreSignUp_ExternalProvider: Durable Unauthorised Account Creation via Federated Login
AWS Cognito can persist a federated user record before later controls ever see the session. In a multi-SSO pool, that detail matters more than the login page in front of it. If validation sits in the wrong Lambda trigger, an external identity can become a stored account even when the sign-in should never have been accepted.
Cognito federated login before user persistence with AWS Cognito PreSignUp_ExternalProvider
Federated sign-in in a Cognito user pool is not a single, uniform path. The first login, a returning login, and the token minting step do not all pass through the same trigger sequence, so controls placed on one path do not cover the others.
Federated sign-in can create a user record before you get a second chance
A federated identity can reach the pool through hosted UI or a custom login page, but the persistence step still happens inside Cognito’s federated flow. Once the user object is written, there is no automatic rollback mechanism. Blocking the session after that point leaves the record in place.
That makes account creation the critical boundary. If the provider, issuer, or domain is not checked before persistence, Cognito can store an identity that should have been rejected. Later rejection only changes what the session can do, not whether the account exists.
CreateIdentityProvider wiring decides which external identities reach the pool
CreateIdentityProvider is the wiring step that attaches OIDC or SAML providers to the user pool. It decides which external identity sources Cognito will trust as federated inputs.
That registration is not validation. It opens the path. The decision about whether a specific issuer, domain, or tenant belongs there still has to happen in the federated sign-up trigger, not after the user exists.
Hosted UI and custom login page both hit the same federated path
Hosted UI and a custom login page both end up on the same federated sign-in route. A control that only exists in one front end leaves the other path untouched.
That matters when implementation teams treat the interface as the security boundary. It is not. The user pool receives the external identity either way, and the persistence decision sits in Cognito’s Lambda trigger chain.
First login and returning login split across different trigger orderings
The first federated login and a later return do not follow identical trigger ordering. They only share the token generation step.
That split is easy to miss when validation is added against one observed flow and assumed to cover the rest. A check that fires on a return visit does nothing for the initial account creation path, which is the one that writes the user record.
PreSignUp_ExternalProvider is the last gate before persistence
PreSignUp_ExternalProvider is the final point where Cognito still has a chance to stop federated account creation. After that trigger, the user object can already exist in the pool.
Domain and issuer checks belong in the external provider trigger
Domain checks, issuer checks, and any tenant allow-list belong in PreSignUp_ExternalProvider. That is the point where the federated identity can still be rejected before persistence.
Put bluntly, if the trigger does not inspect the external identity source, Cognito will continue. A malicious or misconfigured identity provider can then create a durable unauthorised account rather than a temporary session failure.
JIT provisioning after persistence cannot undo an account already stored
Just-in-time provisioning runs after the record has been created. It can enrich the account, map attributes, or apply downstream logic, but it cannot retract the stored user object.
That leaves a narrow but important distinction between provisioning and admission. A provisioning Lambda that spots a bad issuer late has already missed the chance to stop durable account creation. Cleanup becomes manual.
PostConfirmation and PreAuthentication only catch the session after the fact
PostConfirmation and PreAuthentication can still block activity, but they operate after the user has entered the pool. They are useful for session handling and follow-up controls, not for preventing the account from being stored.
The same limitation applies to returning federated sessions. If the user record already exists, later triggers can only react to it. They cannot turn the creation step into a denial after the fact.


