SAML
SAML 2.0
How SAML single sign-on works, and the validation rules a service provider must get right, including the errata that changed them.
SAML 2.0 (Security Assertion Markup Language) is the OASIS standard, approved in 2005, that most enterprise single sign-on still runs on. An identity provider (IdP) authenticates the user and sends a signed XML assertion through the user's browser to a service provider (SP), which validates it and creates a session. The standard is split across several documents: Core (assertions and protocols), Bindings (how messages travel), Profiles (how they combine for a use case), and the approved errata, which changed some of the rules quoted below.
SAML's flexibility and its reliance on XML Signature make it easy to validate incorrectly. This page concentrates on what an SP must check.
Assertions, protocols, bindings, profiles
- Assertion
- An XML statement from an issuer about a subject. It contains an
<Issuer>, usually a<ds:Signature>, a<Subject>(the user's<NameID>and how the SP should confirm that the presenter is that subject),<Conditions>(validity window, audience), and statements: an<AuthnStatement>(when and how the user authenticated) and often an<AttributeStatement>. - Protocol
- Request and response messages. For SSO: the SP's
<samlp:AuthnRequest>and the IdP's<samlp:Response>, which carries one or more assertions. - Binding
- How a message is carried over HTTP. The three browser bindings are described below.
- Profile
- A combination of the above for one use case. The one that matters most is the Web Browser SSO Profile (Profiles §4.1).
The browser bindings
| Binding | How the message travels | Typical use | Signing |
|---|---|---|---|
| HTTP-Redirect | XML is DEFLATE-compressed, base64-encoded, URL-encoded and put in the SAMLRequest or SAMLResponse query parameter of a 302 redirect (Bindings §3.4.4.1). | Sending the AuthnRequest to the IdP; logout messages. | The XML signature is removed and the query string is signed instead, with SigAlg and Signature parameters over SAMLRequest=…&RelayState=…&SigAlg=…. |
| HTTP-POST | XML is base64-encoded into a hidden form field, SAMLRequest or SAMLResponse, which the browser auto-submits (Bindings §3.5.4). | Delivering the Response to the SP's Assertion Consumer Service. | XML Signature inside the message. |
| HTTP-Artifact | The browser carries only a small reference (SAMLart); the receiver fetches the real message over a direct back-channel call (Bindings §3.6). | Keeping assertions out of the browser entirely. | The artifact resolution exchange MUST be mutually authenticated, integrity protected and confidential (Profiles §4.1.4.4). |
The Web Browser SSO profile forbids the Redirect binding for the IdP's response, because responses typically exceed URL length limits (Profiles §4.1.2, MUST NOT). When a Redirect or POST message is signed, its Destination attribute MUST contain the URL it was sent to, and the recipient MUST verify it matches where the message arrived (Bindings §3.4.5.2, §3.5.5.2).
Web Browser SSO: SP-initiated and IdP-initiated
AuthnRequest with an ID it remembers, and later requires the response's InResponseTo to match that ID.In SP-initiated SSO the user starts at the application. The SP sends an AuthnRequest (usually via Redirect) and records its ID; the IdP authenticates the user and POSTs a Response to the SP's Assertion Consumer Service (ACS) URL, with InResponseTo set to that ID. The IdP MUST make sure any ACS URL named in a request belongs to the SP it is responding to, or the response can be sent to an attacker (Profiles §4.1.4.1).
In IdP-initiated SSO, the user starts at an IdP portal and clicks an app tile; the IdP sends an unsolicited response with no InResponseTo (Profiles §4.1.5, MUST NOT contain one). The SP has no request to tie the response to, which removes a key protection:
- An attacker who obtains a valid assertion for themselves can submit it to a victim's browser (login CSRF), signing the victim into the attacker's account.
- A stolen or intercepted assertion can be replayed until it expires, unless the SP strictly enforces one-time use.
- Any
RelayStatesent with it is not tied to anything the SP issued, so an SP that redirects to it blindly becomes an open redirector.
NIST SP 800-63C-4 reflects this: at FAL2 and FAL3 "the federation transaction SHALL be initiated by the RP", and at FAL1 it SHOULD be (SP 800-63C-4 §2.2–2.3). Where you need portal-style launch, a common pattern is for the IdP tile to point at an SP URL that then starts an ordinary SP-initiated flow.
An annotated Response
A successful response as it arrives at the ACS after base64-decoding the SAMLResponse form field. Hosts are example domains; digest and signature values are elided.
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="_r8f3c1a29e04b7d6"
Version="2.0"
IssueInstant="2026-10-26T14:02:11Z"
Destination="https://sp.example.com/saml/acs"
InResponseTo="_a71e5c0d9b3f4e28">
<saml:Issuer>https://idp.example.org/saml</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion ID="_a5b9e2c47d10f3e8" Version="2.0" IssueInstant="2026-10-26T14:02:11Z">
<saml:Issuer>https://idp.example.org/saml</saml:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#_a5b9e2c47d10f3e8">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>(elided)</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>(elided)</ds:SignatureValue>
</ds:Signature>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">8c1f5e0a-3b7d-4c62-9e4a-2d9b6f1a7c30</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData
Recipient="https://sp.example.com/saml/acs"
NotOnOrAfter="2026-10-26T14:07:11Z"
InResponseTo="_a71e5c0d9b3f4e28"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2026-10-26T14:01:41Z" NotOnOrAfter="2026-10-26T14:07:11Z">
<saml:AudienceRestriction>
<saml:Audience>https://sp.example.com/saml</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2026-10-26T14:01:58Z" SessionIndex="_s4d2e9f61">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="email">
<saml:AttributeValue>jane@example.com</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>
Destinationon theResponse: the ACS URL. If present, the SP MUST check it matches where the message was received, or discard it (Core §3.2.2).InResponseTo: the ID of the SP'sAuthnRequest. It appears on theResponseand on the bearerSubjectConfirmationData.Status: anything other thanSuccessmeans no assertion should be trusted; error responses MUST NOT include assertions (Profiles §4.1.4.2).ds:Signatureinside theAssertion: an enveloped signature whose singleReferencepoints at the assertion's ownID(#_a5b9e2c47d10f3e8), as Core §5.4.2 requires.NameID: the subject. Apersistentidentifier is an opaque, stable per-SP value; prefer it over email as the account key.SubjectConfirmation Method="…:cm:bearer"withRecipient(the ACS URL),NotOnOrAfter(delivery deadline) andInResponseTo. It MUST NOT containNotBefore.Conditions: the validity window, and anAudienceRestrictionnaming the SP's entity ID. Each bearer assertion MUST contain one (Profiles §4.1.4.2).AuthnStatement: when and how the user authenticated;SessionIndexis used for single logout.
The SAML decoder base64-decodes and inflates SAMLRequest and SAMLResponse values so you can read real messages.
What the SP must validate
The Web Browser SSO profile (§4.1.4.3, as amended by Errata 05) and Core give the checks. All of them, every time:
- Signature. Verify the signatures present on the assertion(s) or the response, against the IdP's key from metadata (not from
KeyInfoin the message). With the HTTP-POST binding, every assertion must be covered by a signature: the original 2005 text required each assertion to be signed; SAML V2.0 Errata 05 (E26) replaced that with "each assertion MUST be protected by a digital signature", achieved "by signing each individual <Assertion> element or by signing the <Response> element". - The signed element is the one you use. The signature's
Referencemust point at the exactAssertion(orResponse) you read the subject and attributes from. See XML Signature Wrapping. - Encrypted assertions. If an
EncryptedAssertionuses a CBC-mode algorithm, theResponseSHOULD be signed so the ciphertext is integrity-protected before decryption (Errata 05, E93), and relying parties SHOULD require that protection. - Issuer. Each assertion's
Issueris the IdP's entity ID, and all assertions in a response come from the same IdP (Errata 05, E26). - Audience. The
AudienceRestrictionincludes your SP entity ID. The condition is valid only if you are a member of the audience (Core §2.5.1.4). - Recipient. The bearer
SubjectConfirmationData/@Recipientequals the ACS URL the response was delivered to (MUST). - Destination. If present (and it must be, if the message is signed), it equals the ACS URL.
- InResponseTo. Equals the ID of an
AuthnRequestyou sent from this browser session, and has not been used before. For unsolicited responses it must be absent. - Time.
SubjectConfirmationData/@NotOnOrAfterhas not passed, andConditionsNotBefore/NotOnOrAfterhold, with small allowed clock skew. - One-time use. For POST, the SP MUST prevent replay by keeping the IDs of used assertions until their
NotOnOrAfterpasses (Profiles §4.1.4.5).<OneTimeUse>inConditionsadditionally says the assertion MUST NOT be retained for future use (Core §2.5.1.5). - Status is
Success, and all conditions present are understood; a condition that is not understood makes the assertion Indeterminate, and an Invalid or Indeterminate assertion MUST be rejected (Core §2.5.1.1). - Session lifetime. If the
AuthnStatementhasSessionNotOnOrAfter, the SP SHOULD end its session by then.
An assertion that fails any check, or whose subject confirmation cannot be met, SHOULD be discarded and not used to establish a session (Profiles §4.1.4.3). Treat that SHOULD as a must in practice.
XML Signature Wrapping
XML Signature does not sign "the document". It signs whatever element its Reference URI points to, located by ID. A SAML library therefore does two separate things: the signature module finds the referenced element and verifies it, and the business logic finds an assertion and reads the user from it. If those two lookups can return different elements, an attacker can move the genuinely signed assertion somewhere the business logic does not look (inside an extension or wrapper element) and insert their own unsigned assertion where it does.
#a1 still verifies after the attacker relocates it. An SP that then reads "the first assertion" uses the forged one.The attack class was analysed in depth by Somorovsky and colleagues in "On Breaking SAML: Be Whoever You Want to Be" (USENIX Security 2012), who found critical wrapping vulnerabilities in 11 of the 14 SAML frameworks they examined. Variants include duplicate IDs, assertions nested inside other assertions, and comments or namespace tricks that make two parsers disagree.
Defenses:
- Use a maintained SAML library; do not hand-roll XML signature handling.
- Have the signature step return the element it verified, and read the subject and attributes only from that element, never by a separate search of the document.
- Validate the message against the SAML schema and reject documents with duplicate
IDvalues or more assertions than you expect. - Follow Core §5.4: exactly one
Reference, pointing at the root of the signed assertion or message; reject transforms other than enveloped-signature and exclusive canonicalization (verifiers MAY reject others, and if they do not, MUST ensure no content is excluded from the signature, §5.4.4). - Take the IdP's signing key from configured metadata, never from the certificate embedded in the message.
- Prefer SHA-256-based signature algorithms. SAML Core (2005) names
rsa-sha1as the algorithm processors should support, which reflects its age; it is not a reason to accept SHA-1 today.
RelayState
RelayState is an opaque value the SP can send with its request and get back unchanged with the response, typically to remember which page the user wanted. The bindings say it MUST NOT exceed 80 bytes and SHOULD be integrity-protected by its creator, for example with a checksum or by using a random value as a key to server-side state (Bindings §3.4.3, §3.5.3). The profile adds that the SP SHOULD reveal as little of the original request in it as possible (Profiles §4.1.3.1).
The practical rule: never put a raw URL in RelayState and redirect to whatever comes back. Store the target server-side under a random key, or validate the returned value against an allow-list of your own paths.
Checklist
- SP-initiated flows only where possible; if IdP-initiated is enabled, strict replay protection and safe
RelayStatehandling. - IdP metadata (entity ID, signing certificates, endpoints) configured from a trusted source and refreshed on rotation.
- Signatures required on every assertion or on the response; the verified element is the one consumed.
- Audience, Recipient, Destination, InResponseTo, time window and one-time use all checked.
- Accounts keyed on a persistent
NameIDfrom a specific IdP, not on an email attribute. - Encrypted assertions accompanied by a signed response when CBC algorithms are in use.
- For new applications, consider OpenID Connect; see the comparison.
Sources
- Assertions and Protocols for the OASIS Security Assertion Markup Language (SAML) V2.0, OASIS. OASIS specification (cited, brief quotations).
- Bindings for the OASIS Security Assertion Markup Language (SAML) V2.0, OASIS. OASIS specification (cited, brief quotations).
- Profiles for the OASIS Security Assertion Markup Language (SAML) V2.0, OASIS. OASIS specification (cited, brief quotations).
- SAML V2.0 Errata 05, OASIS. OASIS specification (cited, brief quotations).
- NIST SP 800-63C-4: Digital Identity Guidelines, Federation and Assertions, NIST. Public domain (U.S. government work).
- On Breaking SAML: Be Whoever You Want to Be (Somorovsky et al., USENIX Security 2012), USENIX. Cited for facts; not reproduced.