Access and accounts Required
Check every step of single sign-on
For login through another provider with OAuth or OpenID Connect, use the authorization code flow with PKCE and check state, nonce and the ID token.
How to do it
Register exact redirect addresses with the provider, never wildcards. Send a random state and nonce and compare them on return. Verify the ID token's signature, issuer, audience and expiry as in verify every token. Link a login to an existing account only by the provider's stable user ID. Never link by an email the provider has not verified. Follow RFC 9700 for the details. For SAML, use a maintained library and reject unsigned assertions. See also connect single sign-on per organisation.
Example
// Node with openid-client: PKCE, state and nonce are checked on return
const tokens = await client.authorizationCodeGrant(config, callbackUrl, {
pkceCodeVerifier: session.codeVerifier, expectedState: session.state, expectedNonce: session.nonce,
});
const user = await findUserByProviderId(tokens.claims().iss, tokens.claims().sub);
# Python with Authlib: the state and the ID token are checked here
token = oauth.example.authorize_access_token()
claims = token["userinfo"]
user = find_user_by_provider_id(claims["iss"], claims["sub"])
How to check
Return to the callback with a changed state, a reused code and an ID token for another client. Each login fails. Change the redirect address in the login request to https://evil.example.net. The provider refuses it.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers security testing playbook: https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts/single-sign-on.