Production engineering guide for identity federation covering patterns, implementation strategies, and operational best practices.
Identity Federation enables a system to trust identity claims from an external identity provider (IdP), allowing users to authenticate once and access multiple services across domains. It matters when users need to sign in to a suite of applications—internal and third-party—using a single set of credentials, especially when those applications are owned by different teams or organizations.
To federate identities, a relying party (RP) must configure trust with an IdP. This involves exchanging metadata, signing assertions, and validating tokens. The process begins with the RP registering itself with the IdP.
The IdP provides a metadata document, typically at https://idp.example.com/metadata, which includes endpoints, signing certificates, and supported protocols. The RP downloads this document and configures the following:
<!-- Example of IdP metadata (simplified) -->
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
entityID="https://idp.example.com">
<md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://idp.example.com/sso/redirect"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://idp.example.com/sso/post"/>
</md:SPSSODescriptor>
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>
MIID... (PEM-encoded certificate)
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
</md:EntityDescriptor>
The RP uses this metadata to set up an identity provider configuration, including:
urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress).The RP must validate the SAML assertion by:
Audience claim against its own entity ID.IssueInstant is recent (within 5 minutes).Subject contains the expected user identifier.Failure to validate any of these leads to a SAMLResponse error:
{
"error": "SAML validation failed",
"details": {
"invalid_signature": true,
"audience_mismatch": {
"expected": "https://app.example.com",
"actual": "https://api.example.com"
},
"not_before": "2023-10-05T12:00:00Z",
"not_after": "2023-10-05T12:05:00Z",
"issue_instant": "2023-10-05T11:58:00Z"
}
}
The most common silent failure is clock skew: if the RP’s system clock is off by more than 5 minutes, assertions from a time-sensitive IdP are rejected without error logs.
The SSO flow begins when a user visits a protected resource on the RP. The RP checks for a valid session and, if missing, redirects the user to the IdP’s SSO endpoint.
GET /sso?returnUrl=https://app.example.com/dashboard HTTP/1.1
Host: idp.example.com
The IdP returns a redirect with a SAMLRequest parameter, encoded in Base64 and deflated:
HTTP/1.1 302 Found
Location: https://idp.example.com/sso/redirect?SAMLRequest=...
The RP decodes the SAMLRequest and constructs a SAMLResponse after authentication:
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="_123456789"
Version="2.0"
IssueInstant="2023-10-05T12:00:00Z"
Destination="https://app.example.com/sso/acs">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
https://idp.example.com
</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="_987654321"
IssueInstant="2023-10-05T12:00:00Z"
Version="2.0">
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
[email protected]
</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2023-10-05T12:05:00Z"
Recipient="https://app.example.com/sso/acs"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2023-10-05T11:55:00Z"
NotOnOrAfter="2023-10-05T12:05: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-format:basic">
<saml:AttributeValue>[email protected]</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="givenName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>Alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>admin</saml:AttributeValue>
<saml:AttributeValue>editor</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>
The RP validates the response and creates a session, typically by setting a signed JWT or a session cookie.
While SAML is well-suited for enterprise SSO and complex assertions, OpenID Connect (OIDC) is simpler and better integrated with web and mobile apps.
OIDC uses OAuth 2.0 as a foundation. The RP initiates login via a discovery document at /.well-known/openid-configuration:
GET /.well-known/openid-configuration HTTP/1.1
Host: idp.example.com
Accept: application/json
{
"issuer": "https://idp.example.com",
"authorization_endpoint": "https://idp.example.com/authorize",
"token_endpoint": "https://idp.example.com/token",
"userinfo_endpoint": "https://idp.example.com/userinfo",
"jwks_uri": "https://idp.example.com/jwks.json",
"response_types_supported": ["code", "id_token", "code 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", "picture", "address"]
}
The RP starts the flow with a redirect:
GET /authorize?
response_type=code
&client_id=app.example.com
&redirect_uri=https://app.example.com/callback
&scope=openid profile email
&state=xyz123
&nonce=abc456
HTTP/1.1
Host: idp.example.com
The IdP returns an authorization code, which the RP exchanges for tokens:
POST /token HTTP/1.1
Host: idp.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=abc123xyz
&redirect_uri=https://app.example.com/callback
&client_id=app.example.com
&client_secret=secret123
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "def456ghi"
}
The id_token is a JWT with claims including sub, name, email, iss, aud, exp, iat, and nonce.
The RP validates the id_token by:
jwks_uri.iss, aud, exp, iat, and nonce.sub against a user database.A common mistake is failing to validate the nonce. Without it, a replay attack allows an attacker to reuse a token across sessions.
The IdP sends user attributes in assertions. The RP must map these to its internal user model.
For example, a SAML assertion includes:
<saml:Attribute Name="department" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>Engineering</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="employeeId" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>1001</saml:AttributeValue>
</saml:Attribute>
The RP’s user model expects department and employee_id. It must map department to department and employeeId to employee_id.
The most silent failure is attribute name mismatch: a field named user_department in the IdP is not recognized by the RP because it expects department. The RP logs User not found: missing field 'department', but the actual field is user_department.
Another common issue is claim type confusion. The NameID in SAML is not the same as Subject in OIDC. A user may be identified by email in SAML but by sub in OIDC, leading to duplicate user accounts or inconsistent session state.
Single Sign-Out (SSO-Out) allows users to log out from all federated services by logging out from one.
The RP sends a logout request to the IdP:
POST /slo HTTP/1.1
Host: idp.example.com
Content-Type: application/xml
<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="_12345"
Version="2.0"
IssueInstant="2023-10-05T12:05:00Z"
Destination="https://idp.example.com/slo">
<saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
[email protected]
</saml:NameID>
<saml:SessionIndex>_987654321</saml:SessionIndex>
</samlp:LogoutRequest>
The IdP invalidates the user’s session and returns a redirect or a SAML response.
The IdP may also broadcast the logout event to other RPs via a LogoutRequest sent in parallel to all federated services.
The RP must handle the logout response and clear its session, optionally redirecting to a post-logout page.
Certificates are central to identity federation. The IdP signs SAML assertions and OIDC tokens with a private key. The RP must:
The RP validates certificate chains and checks the x509 certificate in the Signature element of a SAML response.
A common failure mode is certificate expiration: when the IdP’s signing certificate expires, the RP fails to validate assertions, even though the IdP is healthy. The RP logs SAML signature validation failed: Certificate expired, but the certificate was valid for 180 days and the IdP updated it only 10 days before expiry.
To avoid this, the RP should:
x509 certificate chains with CRL or OCSP validation.The IdP may publish a jwks.json file for OIDC:
{
"keys": [
{
"kty": "RSA",
"n": "123456789...",
"e": "17",
"alg": "RS256",
"kid": "abc123"
},
{
"kty": "RSA",
"n": "987654321...",
"e": "17",
"alg": "RS256",
"kid": "def456"
}
]
}
The RP uses the kid (Key ID) from the id_token header to select the correct public key.
nonce: replay attacks in OIDC.user_department not recognized as department.https://app.example.com vs https://api.example.com.SubjectConfirmationData: NotOnOrAfter validation fails.NameID format: email not mapped correctly.id_token: iss, aud, exp, iat not checked.sub and email not synchronized across services.Identity Federation is not a one-time setup. It requires vigilant monitoring, certificate management, and careful handling of claims and time.
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