How SAML Works: Enterprise Single Sign-On and Federation

Security Assertion Markup Language (SAML) is an XML-based open standard for exchanging authentication and authorization data between parties. In practice, SAML is the protocol that powers enterprise single sign-on (SSO): when you click "Sign in with your company account" on a SaaS application and get redirected to your corporate login page, SAML is almost certainly the protocol handling that exchange behind the scenes. Defined by OASIS, SAML 2.0 (2005) remains the dominant federation protocol in enterprise environments, even as newer alternatives like OpenID Connect have gained ground in consumer-facing applications.

The Problem SAML Solves

Before federated identity, every application maintained its own user database. An employee at a company with 50 SaaS applications would have 50 separate accounts with 50 separate passwords. This creates several serious problems:

SAML solves this by federating identity: one authoritative system (the Identity Provider) manages user authentication, and all other applications (Service Providers) trust its assertions. The user logs in once and gains access to all federated applications — hence "single sign-on."

SAML Terminology

SAML introduces specific terminology that maps to real-world roles:

SAML Assertions: The Core Data Structure

A SAML assertion is an XML document containing one or more statements about a subject (the user). There are three types of statements:

A simplified SAML assertion looks like this:

<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    ID="_abc123" IssueInstant="2025-01-15T14:30:00Z" Version="2.0">
  <saml:Issuer>https://idp.example.com</saml:Issuer>
  <ds:Signature>...</ds:Signature>
  <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
        Recipient="https://app.example.com/saml/acs"
        NotOnOrAfter="2025-01-15T14:35:00Z"
        InResponseTo="_req456"/>
    </saml:SubjectConfirmation>
  </saml:Subject>
  <saml:Conditions NotBefore="2025-01-15T14:29:00Z" NotOnOrAfter="2025-01-15T14:35:00Z">
    <saml:AudienceRestriction>
      <saml:Audience>https://app.example.com</saml:Audience>
    </saml:AudienceRestriction>
  </saml:Conditions>
  <saml:AuthnStatement AuthnInstant="2025-01-15T14:30:00Z">
    <saml:AuthnContext>
      <saml:AuthnContextClassRef>
        urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
      </saml:AuthnContextClassRef>
    </saml:AuthnContext>
  </saml:AuthnStatement>
  <saml:AttributeStatement>
    <saml:Attribute Name="email">
      <saml:AttributeValue>[email protected]</saml:AttributeValue>
    </saml:Attribute>
    <saml:Attribute Name="groups">
      <saml:AttributeValue>engineering</saml:AttributeValue>
      <saml:AttributeValue>admin</saml:AttributeValue>
    </saml:Attribute>
  </saml:AttributeStatement>
</saml:Assertion>

Critical fields include: the Issuer (identifies the IdP), the Subject (identifies the user), the Conditions (restrict the assertion's validity window and intended audience), and the XML digital signature that proves the assertion was issued by the IdP and has not been tampered with.

SP-Initiated SSO Flow

The most common SAML flow is SP-initiated SSO, where the user starts at the Service Provider. This is what happens when you visit a SaaS application and it redirects you to your company's login page.

SP-Initiated SAML SSO User (Browser) Service Provider Identity Provider 1. GET /dashboard 2. 302 Redirect to IdP + AuthnRequest 3. GET IdP SSO URL (AuthnRequest in query string) 4. Login form (if no session) 5. POST credentials + MFA 6. HTML form with hidden SAMLResponse (auto-submit) 7. POST SAMLResponse to SP ACS URL 8. Set session cookie + redirect to /dashboard AuthnRequest Authentication SAMLResponse

Here is the step-by-step breakdown:

  1. User accesses the SP — The user navigates to the application (e.g., https://app.example.com/dashboard). The SP detects there is no active session.
  2. SP generates AuthnRequest — The SP creates a SAML AuthnRequest XML document specifying its entity ID, the desired assertion consumer service (ACS) URL, and a request ID. It redirects the user's browser to the IdP's SSO endpoint with this request encoded in the query string (HTTP-Redirect binding) or as a hidden form field (HTTP-POST binding).
  3. Browser contacts the IdP — The user's browser follows the redirect to the IdP. The AuthnRequest tells the IdP which SP is requesting authentication and where to send the response.
  4. IdP authenticates the user — If the user does not already have a session at the IdP, the IdP presents a login form. The user enters their credentials and completes any required MFA challenges. If the user already has an active IdP session, this step is skipped — this is what makes SSO seamless.
  5. IdP generates SAMLResponse — After successful authentication, the IdP constructs a SAMLResponse containing a signed assertion with the user's identity and attributes. The IdP returns an HTML page containing an auto-submitting form with the SAMLResponse as a hidden field.
  6. Browser POSTs to the SP's ACS — The auto-submitting form sends the SAMLResponse to the SP's Assertion Consumer Service URL via HTTP POST.
  7. SP validates the assertion — The SP verifies the XML signature against the IdP's known certificate, checks that the assertion is not expired, confirms the audience restriction matches its own entity ID, and validates the InResponseTo field matches the original request ID.
  8. SP creates a session — If validation passes, the SP creates a local session for the user, sets a session cookie, and redirects to the originally requested resource.

IdP-Initiated SSO Flow

In IdP-initiated SSO, the user starts at the Identity Provider — typically a portal page listing all available applications. The user clicks on an application icon, and the IdP sends a SAMLResponse directly to the SP without a preceding AuthnRequest.

This flow is simpler but less secure. Because there is no AuthnRequest, there is no request ID for the SP to validate in the InResponseTo field, which means the SP cannot tie the response to a specific request. This opens the door to replay attacks where an attacker captures a SAMLResponse and submits it later. To mitigate this, SPs must carefully enforce assertion validity windows and track consumed assertion IDs.

IdP-initiated SSO is also vulnerable to unsolicited response attacks where an attacker who can generate or obtain a valid assertion for one SP might try to use it at another SP. The AudienceRestriction element in the assertion prevents this if the SP validates it correctly.

SAML Bindings: How Messages Travel

SAML is transport-agnostic — the specification defines "bindings" that map SAML messages onto standard transport protocols. The two most common bindings are:

HTTP-Redirect Binding

The SAML message is deflated (compressed), Base64-encoded, URL-encoded, and sent as a query parameter in an HTTP 302 redirect. This is typically used for AuthnRequests because they are small. The URL looks like:

https://idp.example.com/sso?SAMLRequest=fZJNT8MwDI...&RelayState=%2Fdashboard&SigAlg=...&Signature=...

There is a practical limitation: URLs have length limits (around 2048 characters in some browsers and servers), so this binding is unsuitable for large messages like assertions with many attributes.

HTTP-POST Binding

The SAML message is Base64-encoded and embedded as a hidden field in an HTML form that auto-submits via JavaScript. This is the standard binding for SAMLResponses because assertions can be large. The IdP returns an HTML page like:

<form method="POST" action="https://app.example.com/saml/acs">
  <input type="hidden" name="SAMLResponse" value="PHNhbWxwOl..." />
  <input type="hidden" name="RelayState" value="/dashboard" />
  <noscript><input type="submit" value="Continue" /></noscript>
</form>
<script>document.forms[0].submit();</script>

The <noscript> fallback ensures the flow works even without JavaScript — the user just has to click a button.

Other Bindings

SAML also defines an Artifact binding where only a short reference (artifact) is passed through the browser, and the SP contacts the IdP directly via a back-channel SOAP call to resolve the full assertion. This is useful when assertion size is a concern or when you want to avoid exposing the assertion to the user's browser. SOAP binding, Reverse SOAP (PAOS), and URI binding also exist but are rarely used in modern deployments.

XML Signature and Security

SAML assertions are digitally signed using XML Signature (XMLDSig) to ensure integrity and authenticity. The IdP signs the assertion (or the entire response) using its private key, and the SP verifies the signature using the IdP's public key obtained from metadata exchange.

XML signatures in SAML can appear at two levels:

Best practice is to sign at the assertion level (or both), because if only the response is signed, an attacker who can inject content into the response outside the assertion could tamper with it without invalidating the signature.

XML Signature Wrapping Attacks

The most notorious class of SAML vulnerabilities is XML Signature Wrapping (XSW). These attacks exploit the disconnect between which XML elements are covered by the signature and which elements the application logic processes.

XML Signature Wrapping Attack Legitimate SAMLResponse <Response> <Assertion ID="A1"> <Subject>[email protected]</Subject> <Signature> Reference URI="#A1" ✓ </Signature> </Assertion> </Response> Signature valid, user = jane SP reads Assertion #A1 Wrapped (Attacked) Response <Response> <Assertion> (FORGED) <Subject>[email protected]</Subject> </Assertion> <Assertion ID="A1"> (ORIGINAL) <Subject>[email protected]</Subject> <Signature Ref="#A1"> ✓ </Assertion> </Response> Sig valid on #A1, but SP reads FIRST assertion: [email protected]

The attack works like this: the signature covers a specific XML element identified by a Reference URI attribute. The attacker takes a legitimately signed assertion and moves it to a different location in the XML tree, then inserts a forged assertion where the application expects to find it. The signature still validates (it covers the original assertion, which is still present in the document), but the application processes the forged assertion.

There are several variants of XSW attacks, numbered XSW1 through XSW8 in security research, each exploiting different aspects of how XML parsers and signature validators traverse the document. Defenses include:

Metadata Exchange

Before an IdP and SP can exchange SAML messages, they must exchange metadata — XML documents that describe each party's endpoints, certificates, and capabilities. This is how trust is bootstrapped.

SP metadata typically includes:

IdP metadata typically includes:

Metadata can be exchanged manually (download XML file, upload to the other party) or dynamically via well-known URLs. Many IdPs publish their metadata at a URL like https://idp.example.com/saml/metadata. Dynamic metadata exchange reduces configuration errors but introduces a new trust dependency: the metadata URL must be served over TLS and the SP must verify the certificate to prevent metadata injection attacks.

SAML vs. OpenID Connect

SAML and OpenID Connect (OIDC) solve similar problems — federated single sign-on — but take fundamentally different approaches:

Aspect SAML 2.0 OpenID Connect
Data format XML JSON (JWT)
Transport HTTP Redirect/POST, SOAP REST/HTTP
Built on XML Schema, XMLDSig, XML Encryption OAuth 2.0, JWT, JOSE
Primary use Enterprise SSO Consumer + enterprise SSO
Mobile support Poor (XML is heavy) Excellent (JSON is lightweight)
Specification age 2005 2014
Discovery Metadata XML .well-known/openid-configuration

SAML remains dominant in enterprises with existing IdP infrastructure (especially ADFS, PingFederate, and Shibboleth), regulated industries that have invested heavily in SAML-based compliance tooling, and B2B SaaS where customers demand SAML support. New applications increasingly support both protocols, and OIDC is generally preferred for greenfield development due to its simplicity and better mobile support.

Single Logout

SAML defines a Single Logout (SLO) mechanism that allows a user to log out of all SPs simultaneously by initiating logout at any one SP or at the IdP. The logout process sends LogoutRequest messages to all SPs that have active sessions for the user.

In practice, SLO is fragile and often partially implemented. Problems include:

Many organizations address this by setting short session timeouts on SPs and relying on the IdP session as the primary control point, rather than implementing full SLO.

Assertion Encryption

While SAML assertions are always transmitted over TLS, the assertion passes through the user's browser (in the HTTP-POST binding). A sophisticated attacker who has compromised the browser or intercepted the TLS connection could read the assertion contents. SAML supports assertion encryption using XML Encryption, where the IdP encrypts the assertion with the SP's public key from its metadata.

Encrypted assertions look like this in the response:

<saml:EncryptedAssertion>
  <xenc:EncryptedData>
    <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
    <ds:KeyInfo>
      <xenc:EncryptedKey>
        <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
        <xenc:CipherData><xenc:CipherValue>...</xenc:CipherValue></xenc:CipherData>
      </xenc:EncryptedKey>
    </ds:KeyInfo>
    <xenc:CipherData><xenc:CipherValue>...</xenc:CipherValue></xenc:CipherData>
  </xenc:EncryptedData>
</saml:EncryptedAssertion>

The SP decrypts the assertion using its private key, then validates the signature on the contained assertion as usual. While encryption adds defense in depth, it also adds complexity — key management, certificate rotation, and ensuring the SP can handle encrypted assertions all require careful implementation.

NameID Formats

The NameID element in a SAML assertion identifies the subject (user). SAML defines several formats:

The choice of NameID format has privacy implications. Persistent and transient formats protect user privacy by preventing SPs from correlating identities, while email-based NameIDs make correlation trivial.

Real-World SAML Configuration

Setting up a SAML integration between an IdP and SP typically involves these steps:

  1. Exchange metadata — The SP administrator downloads the IdP's metadata XML (or enters the IdP's metadata URL). The IdP administrator downloads the SP's metadata XML or manually enters the SP's entity ID and ACS URL.
  2. Configure attribute mapping — Define which IdP attributes map to which SP fields. For example, the IdP might send mail as the email attribute, but the SP expects email. This attribute mapping is a common source of SSO configuration errors.
  3. Configure NameID — Agree on the NameID format and which IdP attribute to use as the NameID value.
  4. Test the integration — Perform an SP-initiated login flow and verify that the assertion contains the expected attributes with correct values.
  5. Certificate rotation planning — SAML signing certificates eventually expire. Plan for certificate rotation: the IdP publishes a new certificate in its metadata before the old one expires, and SPs must update their trusted certificates. This is a frequent source of outages when not planned properly.

Security Considerations

Beyond XML Signature Wrapping attacks, SAML implementations must defend against several other threats:

SAML in the Network Stack

SAML operates at the application layer but depends on the entire network stack for secure operation:

Relevant RFCs and Standards

See It in Action

Major SAML Identity Providers operate on networks routed via BGP. You can explore their infrastructure using the god.ad BGP Looking Glass:

See BGP routing data in real time

Open Looking Glass
More Articles
How TLS/HTTPS Works: Securing the Internet's Traffic
Certificate Transparency: How CT Logs Secure the Web's PKI
How Firewalls Work: Packet Filtering, Stateful Inspection, and Beyond
What is Cross-Site Scripting (XSS)?
What is Cross-Site Request Forgery (CSRF)?
What is Server-Side Request Forgery (SSRF)?