Design enterprise authentication. Covers OAuth 2.0, OIDC, JWTs, session management, passwordless auth, SSO, and choosing between authentication patterns for different application types.
Authentication Architecture Patterns is a guide to the structural decisions that define how systems verify identities across distributed environments. It addresses when and why to choose one approach over another—ranging from single sign-on to federated identity, from token-based flows to zero-trust access. This page focuses on the *how* of authentication: the protocols, flows, data formats, and failure modes that underpin identity systems in modern applications.
Selecting the right flow depends on the user experience requirements, client types, and security constraints. Each flow defines the sequence of steps between user, client, and identity provider, and its implementation must account for edge cases.
Use when clients have full control over user credentials and require no user interaction beyond login. Common in mobile apps, IoT devices, and CLI tools.
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=alice&password=secret&scope=profile email offline_access
The identity provider responds with:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJh bGljZSIsImV4cCI6MTcxMjM0NTYwMCwiaWF0IjoxNzEyMzQ1MjAwLCJpc3MiOiJhY3RpdmUiLCJzdWIiOiJh bGljZSJ9.XYq1rKj9W0j5Qh6a9N4r3u1h8o5vZg5ZmFk5s1b2kC8",
"refresh_token": "f45d3e2b1a0c9b8d7c6e5f4a3b2c1d0e",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "profile email offline_access"
}
Key failure modes:
invalid_grant error when the user credentials are incorrect or expired.invalid_scope when requested scopes are not supported.invalid_client if the client ID is missing or malformed.Use for public clients—mobile apps, SPAs, and browser-based apps—where the client cannot keep secrets secure.
GET /authorize?
client_id=spa-app-123
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
&response_type=code
&scope=profile email
&state=abc123
&code_challenge=7m2J6yqkCkVn5x0dZ1YwU3eCp0sYbPZxN5sQ7oQaJ1c
&code_challenge_method=S256
HTTP/1.1
Host: auth.example.com
After user authentication, the provider redirects to:
https://app.example.com/callback?code=abc123xyz&state=abc123
The client then exchanges the code using:
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=abc123xyz
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
&code_verifier=7m2J6yqkCkVn5x0dZ1YwU3eCp0sYbPZxN5sQ7oQaJ1c
Critical details:
code_challenge_method must be S256 or plain; S256 is preferred for security.code_verifier must be exactly the same as the one used in code_challenge.code_verifier is missing or mismatched, the provider returns invalid_code_verifier error.state parameter must be validated: a mismatched state value indicates a CSRF attack or replay.Use when the client needs the access token immediately after login, with minimal round trips—ideal for SPAs and static web apps.
GET /authorize?
client_id=spa-app-123
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
&response_type=token id_token
&scope=profile email
&state=abc123
HTTP/1.1
Host: auth.example.com
The redirect returns:
https://app.example.com/callback#
access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJh bGljZSIsImV4cCI6MTcxMjM0NTYwMCwiaWF0IjoxNzEyMzQ1MjAwLCJpc3MiOiJhY3RpdmUiLCJzdWIiOiJh bGljZSJ9.XYq1rKj9W0j5Qh6a9N4r3u1h8o5vZg5ZmFk5s1b2kC8
&token_type=Bearer
&expires_in=3600
&id_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJh bGljZSIsImV4cCI6MTcxMjM0NTYwMCwiaWF0IjoxNzEyMzQ1MjAwLCJpc3MiOiJhY3RpdmUiLCJzdWIiOiJh bGljZSJ9.XYq1rKj9W0j5Qh6a9N4r3u1h8o5vZg5ZmFk5s1b2kC8
&state=abc123
Common pitfalls:
access_token and id_token into memory.id_token is a JWT that must be validated: verify signature, aud, iss, exp, nbf, iat, and nonce.response_type=token, the id_token is not returned—leading to missing claims.When a user authenticates once but accesses multiple services, the architecture must coordinate identity across boundaries.
Use when integrating with enterprise systems—especially legacy applications and identity providers like Okta, Azure AD, or Shibboleth.
The identity provider issues a SAML response as an XML document:
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="_a1b2c3d4e5f6"
Version="2.0"
IssueInstant="2024-03-15T12:00:00Z"
Destination="https://app.example.com/saml/acs">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://idp.example.com</saml:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<!-- Signature data -->
</ds:Signature>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion ID="_a1b2c3d4e5f6g7h8i9j0" IssueInstant="2024-03-15T12:00:00Z" Version="2.0">
<saml:Issuer>https://idp.example.com</saml:Issuer>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified">[email protected]</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2024-03-15T12:15:00Z" Recipient="https://app.example.com/saml/acs"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2024-03-15T11:59:00Z" NotOnOrAfter="2024-03-15T12:15:00Z">
<saml:AudienceRestriction>
<saml:Audience>https://app.example.com</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AttributeStatement>
<saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname:basic">
<saml:AttributeValue>[email protected]</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="givenName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname:basic">
<saml:AttributeValue>Alice</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>
The service provider validates:
Response and Assertion.Audience matches EntityID.NotOnOrAfter and NotBefore constraints.NameID and SubjectConfirmationData for freshness.Failure modes:
Status code urn:oasis:names:tc:SAML:2.0:status:AuthnFailed indicates authentication failure.Recipient mismatch leads to InvalidRecipient error.NameID format mismatch causes attribute mapping errors.SubjectConfirmationMethod must be urn:oasis:names:tc:SAML:2.0:cm:bearer for SSO to work correctly.Use when applications need identity, profile, and session management, and want to leverage a common identity layer.
An OIDC provider exposes a discovery document at /.well-known/openid-configuration:
{
"issuer": "https://auth.example.com",
"authorization_endpoint": "https://auth.example.com/authorize",
"token_endpoint": "https://auth.example.com/token",
"userinfo_endpoint": "https://auth.example.com/userinfo",
"jwks_uri": "https://auth.example.com/jwks",
"response_types_supported": ["code", "code id_token", "id_token", "token id_token"],
"subject_types_supported": ["public", "pairwise"],
"id_token_signing_alg_values_supported": ["RS256", "ES256"],
"scopes_supported": ["openid", "profile", "email", "address", "phone"],
"claims_supported": ["sub", "name", "email", "email_verified", "picture"],
"grant_types_supported": ["authorization_code", "refresh_token", "implicit"]
}
Clients use this to discover endpoints and validate tokens.
The id_token is a JWT with claims:
{
"iss": "https://auth.example.com",
"sub": "[email protected]",
"aud": "spa-app-123",
"exp": 1712345600,
"iat": 1712345200,
"auth_time": 1712345100,
"nonce": "abc123xyz",
"acr": "urn:mace:incommon:iap:tier1",
"amr": ["pwd", "mfa"]
}
Critical validation steps:
iss, aud, and exp.iat is within 5 minutes of current time.nonce for replay protection.jwks_uri.acr and amr for multi-factor authentication.Common configuration mistakes:
aud is missing or incorrect—causing invalid_audience error.issuer is not a valid URL or does not match the iss claim.id_token_signed_response_alg is set to none but the client expects a signed token.subject_type is pairwise but sub is not unique across relying parties.Tokens are the currency of authentication. How they are issued, stored, and refreshed determines system resilience and user experience.
Use when clients need long-lived sessions and want to reduce token leakage.
The refresh token flow includes:
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=f45d3e2b1a0c9b8d7c6e5f4a3b2c1d0e
&scope=profile email offline_access
The response returns a new access_token, a new refresh_token, and updates the refresh_token in the database.
Key points:
refresh_token must be rotated: the old one is invalidated and marked as used.refresh_token can be rotated, reuse, or reuse_and_rotate.refresh_token is often stored in a database or Redis with a last_used timestamp and expires_in field.refresh_token that has already been used, the provider returns invalid_grant with refresh_token_revoked.Use when clients want to bind a token to a device or session.
token_binding_id in the token request, and the provider returns a token_binding claim in the id_token.device_id claim.Failure modes:
device_id mismatch leads to invalid_device error.token_binding_id is not recognized—causing invalid_token_binding.token_binding is missing or expired.token_binding_id is not renewed after a session update.Tokens are validated on every request. The following conditions cause failure:
exp claim is in the past.nbf (not before) claim is in the future.iat (issued at) is too far in the past.iss (issuer) does not match the expected value.aud (audience) does not match.nonce is not present or mismatched.acr (authentication context class) does not satisfy required level.amr (authentication methods) includes at least one method from a required set.Common errors:
invalid_token: generic error when token is malformed, expired, or invalid.invalid_claims: when one or more claims are invalid.token_revoked: when the token has been invalidated.token_expired: when exp is before current time.When multiple systems need to trust each other’s identities, a federation pattern must be established.
Use when users authenticate with one provider but services are hosted by another.
issuer, jwks_uri, authorization_endpoint, and token_endpoint.The RP validates the IdP’s signature using its jwks_uri and checks the iss claim in the received token.
Key failure modes:
iss mismatch between expected and actual issuer.jwks_uri is unreachable or returns invalid keys.aud claim is not present or does not match the RP’s client_id.sub (subject) is not unique or is not properly mapped.auth_time is too old, indicating stale sessions.Use when a service needs to authenticate on behalf of a user to another service.
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/json
{
"grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
"subject_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJh bGljZSIsImV4cCI6MTcxMjM0NTYwMCwiaWF0IjoxNzEyMzQ1MjAwLCJpc3MiOiJhY3RpdmUiLCJzdWIiOiJh bGljZSJ9.XYq1rKj9W0j5Qh6a9N4r3u1h8o5vZg5ZmFk5s1b2kC8",
"subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
"requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
"scope": "orders:read orders:write",
"actor_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJh bGljZSIsImV4cCI6MTcxMjM0NTYwMCwiaWF0IjoxNzEyMzQ1MjAwLCJpc3MiOiJhY3RpdmUiLCJzdWIiOiJh bGljZSJ9.XYq1rKj9W0j5Qh6a9N4r3u1h8o5vZg5ZmFk5s1b2kC8",
"actor_token_type": "urn:ietf:params:oauth:token-type:jwt"
}
The response includes a new access token, optionally with a refresh_token.
Critical details:
subject_token must be valid and issued by a trusted provider.actor_token is used to authenticate the actor (the service calling the token endpoint).requested_token_type can be urn:ietf:params:oauth:token-type:access_token, urn:ietf:params:oauth:token-type:refresh_token, or urn:ietf:params:oauth:token-type:jwt.scope is applied to the new token.Failures:
invalid_subject_token: when the subject_token is malformed or expired.invalid_actor_token: when the actor_token is invalid.unsupported_subject_token_type: when the subject_token_type is not recognized.unsupported_requesting_token_type: when the requested_token_type is not supported.Authentication architecture is not a one-time design—it is the continuous work of aligning identity across systems, managing tokens, and handling the subtle failures that arise when users log in, devices authenticate, and services trust one another.
This page was rewritten on 16 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy