SAML 2.0 Explained: The Enterprise SSO Standard, 20 Years In
Updated 2026-05-15 · 14 min read · By @guptadeepak
Key takeaways
- SAML 2.0 is an OASIS standard from 2005; the spec has not been revised in two decades and is unlikely to be.
- Three things define a SAML deployment: the bindings (how messages travel), the profile (which workflow), and the metadata exchange (how SP and IdP discover each other).
- Web Browser SSO Profile with HTTP-POST binding is what 99% of enterprise SSO deployments use; the other profiles are corner cases.
- XML Signature Wrapping (XSW), assertion replay, and audience-restriction confusion are the recurring vulnerability classes; most CVEs in SAML libraries are variants of these three.
- SAML is not deprecated and will not be this decade. New integrations skew OIDC, but install-base inertia keeps SAML required for B2B SaaS through 2030+.
- B2B SaaS should not write the SAML XML parser themselves. Use a maintained library and a CIAM (WorkOS, Auth0, Frontegg, Keycloak) that handles per-Org IdP integration.
What SAML 2.0 actually is
The SAML spec is split across five OASIS documents — Core, Bindings, Profiles, Metadata, and Security Considerations — totaling several hundred pages. In production, almost every deployment uses one tiny slice of the spec: the Web Browser SSO Profile with HTTP-POST binding, signed SAML metadata exchange, and a small subset of the attribute statements. Everything else in the spec is either historical, niche (ECP for non-browser clients), or implementation-specific extension.
The two parties in any SAML exchange:
- Service Provider (SP): the SaaS application that wants to know who the user is. Your application, from the customer's perspective.
- Identity Provider (IdP): the customer's directory — Okta, Microsoft Entra, Ping, Google Workspace, OneLogin, JumpCloud, etc. — that authenticates the user and produces a signed assertion attesting to identity and attributes.
SAML messages are XML documents. The two main message types are the SAML AuthnRequest (SP → IdP, "please authenticate this user") and the SAML Response containing one or more Assertions (IdP → SP, "here is who they are").
Bindings: how SAML messages travel
A binding is the transport mechanism for a SAML message. The spec defines several; in practice only two matter:
- HTTP-POST binding: the SAML message is base64-encoded and submitted as an HTML form
POSTto the destination URL. The user's browser auto-submits the form. This is the standard binding for SAML responses (IdP → SP). - HTTP-Redirect binding: the SAML message is compressed (deflate), base64-encoded, URL-encoded, and appended as a query parameter on a
302redirect. Used for SAML requests (SP → IdP) because requests fit in a URL; responses with signed assertions are too large.
The other bindings (HTTP-Artifact, SOAP, PAOS, URI) exist in the spec and a handful of legacy deployments use them, but a 2026 SAML integration that needs anything other than HTTP-POST + HTTP-Redirect is a niche case.
Profiles: which workflow
A profile combines bindings with a specific use case. The Web Browser SSO Profile is the entire spec, for practical purposes. It defines the SP-initiated flow:
- User attempts to access a protected SP resource.
- SP generates a SAML AuthnRequest, sends the browser to the IdP's SSO endpoint via HTTP-Redirect binding.
- IdP authenticates the user (password, MFA, passkey — SAML does not care what the IdP does internally).
- IdP generates a SAML Response containing a signed Assertion, sends the browser to the SP's Assertion Consumer Service (ACS) URL via HTTP-POST binding.
- SP validates the signature, the conditions (audience, time window), the destination, extracts the user's NameID and attributes, and creates a session.
The IdP-initiated variant skips step 1 and 2 — the user starts in the IdP's app launcher, the IdP sends an unsolicited Response to the SP's ACS URL. Many enterprise IdPs offer this for the "Okta dashboard" experience. The attack-surface tradeoff: the SP receives an assertion it did not request, so it cannot use the InResponseTo field to bind the assertion to its own AuthnRequest. Most hardened deployments disable IdP-initiated for everything except the IdP's own app launcher.
The ECP (Enhanced Client or Proxy) Profile exists for non-browser clients — desktop apps, command-line tools — that cannot do the redirect-based flow. Rare in practice.
The assertion: what's actually in it
A SAML Assertion is the authenticated payload. Stripped of XML namespaces and signatures, the relevant fields are:
- Issuer: which IdP produced this assertion. Must match the configured IdP for this connection.
- Subject → NameID: the user's identifier. Format can be
emailAddress,persistent,transient,unspecified, or a custom URI. The format matters:persistentis a stable opaque ID,emailAddressis the user's email,transientis a one-time pseudonym. Misconfiguring NameID format is the source of many "user logs in fine, but every login creates a new account" bugs. - Subject → SubjectConfirmation: typically
urn:oasis:names:tc:SAML:2.0:cm:bearer. TheRecipient,NotOnOrAfter, andInResponseTofields inside this element bind the assertion to a specific SP, time window, and request. - Conditions: time-window validity (
NotBefore,NotOnOrAfter) andAudienceRestriction(which SPs may consume this assertion). Audience confusion attacks rely on SPs not checking audience strictly. - AuthnStatement: when the authentication happened and the
AuthnContextClassRefdescribing the method (password, MFA, smart card, etc.). - AttributeStatement: the user's attributes — email, first name, last name, group memberships, roles. Attribute names are not standardized across IdPs; the SP has to map them per connection.
Every one of these fields needs strict validation. The recurring vulnerability pattern is an SP that validates the signature but does not validate one or more of: NotBefore/NotOnOrAfter (replay window), AudienceRestriction (assertion meant for a different SP), Destination (assertion delivered to the wrong endpoint), or InResponseTo (assertion not tied to the SP's own request).
Metadata: how SP and IdP discover each other
SAML metadata is an XML document each side publishes describing its endpoints, supported bindings, signing certificates, and supported NameID formats. The two documents:
- SP metadata: includes the ACS URL, the SLO (Single Logout) URL, the SP's entity ID, and its signing/encryption certificates (if the SP requires encrypted assertions).
- IdP metadata: includes the SSO endpoint, the IdP's entity ID, the IdP's signing certificate, and supported NameID formats.
In production B2B SaaS, the customer's IT admin uploads the SP's metadata XML to the IdP, then either uploads the IdP's metadata XML to the SaaS or pastes a metadata URL. The right CIAM ships this as a self-service UX (upload XML, map attributes, test, ship) so adding a new customer's IdP is a configuration step rather than an engineering ticket.
The signing certificate is the security anchor: every SAML response from this IdP must be signed by the certificate in the metadata. When the IdP rotates its signing key, the metadata changes and every SP that consumes from that IdP needs the updated metadata. The right SaaS handles this with validUntil and cacheDuration attributes in the metadata, or periodic re-fetch by URL.
XML Signature Wrapping and the security pitfalls
SAML's security model rests on XML Signature (XMLDSig). XMLDSig is more flexible than necessary for SAML, and that flexibility is the source of the worst SAML vulnerabilities.
The canonical attack class is XML Signature Wrapping (XSW). The signature in a SAML response references the assertion by ID, but the SP processor reads the assertion by XPath, by element position, or by some other means. An attacker who can get any signed assertion from the IdP can wrap it inside a forged assertion: the signature is still cryptographically valid (it covers the original assertion), but the SP reads the forged assertion containing whatever Subject the attacker wants. Somorovsky et al. demonstrated XSW against 11 of 14 major SAML implementations in 2012; new variants keep appearing.
Defense against XSW: validate that the signed fragment is the exact same fragment your code subsequently reads. Use libraries that enforce this invariant. Reject any response where the signature reference does not match the assertion the SP will consume.
Other recurring vulnerability classes:
- Assertion replay: an attacker captures a legitimate assertion (network MITM, log scraping, etc.) and replays it to the SP. Defense: enforce
NotOnOrAfter, cache assertion IDs for the validity window, reject any assertion ID seen before. - Audience confusion: an attacker captures an assertion meant for one SP and replays it to a different SP. Defense: strict
AudienceRestrictionvalidation against the SP's own entity ID, no wildcards. - Comment-injection / canonicalization bugs: XML canonicalization (C14N) for signing has had multiple parser bugs where comments or whitespace change how the document is signed vs how it's parsed. Defense: use a canonicalization-aware library, keep it updated, do not write your own.
- Signature stripping: the assertion is unsigned but the response is signed, or vice versa, and the SP validates one but reads the other. Defense: enforce that the assertion itself is signed (response-level signing is not sufficient), and that the signature covers what you read.
The pattern across all of these: the IdP produces something signed, the SP validates one thing, the SP consumes a different thing, and the attacker wins. The defense is a paranoid same-fragment, same-time-window, same-audience, same-destination check on every single response.
NameID, attribute mapping, and the per-customer setup
The hardest non-security part of running SAML in production is attribute mapping. Every IdP names attributes slightly differently. Microsoft Entra emits http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress; Okta emits email or whatever the admin configured; Google Workspace emits email by default. A B2B SaaS that hardcodes one attribute name will fail for every other IdP.
The patterns that work in production:
- Per-connection attribute mapping: each customer's SAML connection has its own
email → assertion attributemap. The customer's IT admin sets it during onboarding. The SaaS does not assume defaults. - NameID format constraints: pin the NameID format to
emailAddressorpersistentper connection. Reject responses that come back with the wrong format. - JIT provisioning from assertion attributes: on first login, create the user record from the assertion's email, first name, last name, and group memberships. On subsequent logins, look up the user by NameID (not email; NameID is the stable identifier, email may change).
Just-in-time provisioning solves first-login. For ongoing lifecycle — especially deprovisioning when an employee leaves — use SCIM Directory Sync alongside SAML SSO. The IdP pushes user-record changes via SCIM; SAML handles the login.
SAML vs OIDC: when each wins
The protocol comparison itself lives in Enterprise SSO: SAML vs OIDC, and How to Pick. The short version:
- SAML wins: when the customer's procurement team has SAML in writing in the security questionnaire (still common), when the customer's IdP only ships SAML for application SSO at their tier, when the integration is with a legacy enterprise IdP (ADFS, older Shibboleth deployments) that does SAML well and OIDC poorly.
- OIDC wins: for new integrations where the customer can pick, for SaaS-to-SaaS federation, for any mobile or SPA client that fits the OAuth 2.0 client model, and any time the developer experience of debugging the integration matters more than the install-base story.
Production B2B SaaS supports both per-Organization and lets the customer choose at IdP setup time. The CIAM products that handle this cleanly: WorkOS, Auth0 (Enterprise Connections), Frontegg, MojoAuth, SSOJet, Scalekit, and for self-hosted, Keycloak and WSO2 Identity Server.
Implementation guidance
Things that will hurt if you skip them, in rough order of how often they bite:
- Use a maintained SAML library. Do not write the XML parsing, canonicalization, or signature validation yourself. Use
passport-saml/node-saml(Node),python3-saml(Python),OneLogin.Saml2(.NET),pac4jor Spring Security SAML (JVM). For B2B SaaS that needs the per-Organization story, prefer a CIAM (WorkOS, Auth0, Frontegg, Keycloak) that handles the SP side as a product. - Validate everything on every response: signature,
NotBefore,NotOnOrAfter,Destination,AudienceRestriction,InResponseTo(for SP-initiated), assertion ID uniqueness within the validity window. - Disable IdP-initiated SSO unless a specific customer requires it. The attack surface is materially wider than SP-initiated.
- Pin signing certificates per connection. Do not accept assertions signed by any certificate in the IdP's metadata if the customer rotated keys without telling you; require the metadata to be current.
- Implement per-Organization configuration from day one. Retrofitting SAML from "global tenant SSO" to "per-customer SSO" is one of the worst refactors in B2B identity.
- Ship self-service IdP setup UX. Customer's IT admin uploads metadata, maps attributes, tests, ships. Every connection that requires your engineering involvement is a tax on enterprise sales velocity.
- Combine with SCIM for lifecycle. SAML authenticates; SCIM provisions and deprovisions. Both are required at enterprise scale.
The pattern that works: pick a CIAM that ships SAML as a primitive with per-Organization connections, self-service setup, and strict validation defaults. The pattern that fails: roll your own with a generic SAML library, expect each new enterprise customer to be a multi-week integration.
Related vendors
Auth0
Auth0 remains the safest mid-market default for B2C plus B2B Enterprise SSO when developer velocity matters more than long-run TCO. Below 50k MAU it is hard to beat. Above 500k MAU, cost and Actions-driven lock-in make alternatives like FusionAuth (self-host), Cognito (AWS-native), or Stytch plus Corbado (passkey-first) increasingly attractive.
ForgeRock
ForgeRock continues as a distinct platform within Ping Identity's portfolio in 2026, with Authentication Trees orchestration, deep on-prem deployment, and Java-heavy customization that suit large enterprise and public-sector buyers with installed deployments. For new CIAM evaluations, the post-acquisition roadmap uncertainty and the complexity of choosing between PingOne and ForgeRock Identity Cloud weigh heavily, most new buyers should evaluate PingOne first, and reach for ForgeRock only when on-prem or governance integration specifically requires it.
Frontegg
Frontegg is the strongest B2B SaaS CIAM in 2026 by Admin Portal and self-service end-customer experience, the buyer is a SaaS engineering team that needs to ship enterprise-grade IT admin features without building them, and Frontegg delivers more of that out of the box than Auth0 or WorkOS. The trade-off is narrower B2C feature coverage and a smaller ecosystem than Auth0; for B2B-first SaaS the Admin Portal alone often justifies the choice.
Keycloak
Keycloak is the de-facto open-source CIAM in 2026 and remains the right choice when data sovereignty, on-prem deployment, or zero per-MAU cost are non-negotiable. The trade-off is operational cost, running Keycloak well is closer to running PostgreSQL than running an SDK, and teams without that capacity should reach for FusionAuth (lighter ops) or a SaaS instead.
Ping Identity
Ping Identity remains the right CIAM choice for large enterprise and public-sector workloads with complex federation, on-prem requirements, or regulated-industry compliance baselines that hyperscaler CIAM cannot meet. DaVinci flow orchestration is genuinely capable for complex auth journeys. The trade-offs, opaque pricing, fragmented post-ForgeRock product family, heavy professional services, make Ping the wrong answer for everything below the enterprise-quote threshold. After the 2023 ForgeRock acquisition the combined product surface is broader but more confusing.
SSOJet
SSOJet has emerged as a credible modern CIAM for B2B SaaS that needs Enterprise SSO + SCIM without paying WorkOS or Auth0 prices, with a product surface and DX that matches the developer-first tier. The 100k MAU free tier plus per-organization billing makes the unit economics genuinely competitive. The trade-offs are a younger ecosystem and narrower B2C feature set; for B2B-first SaaS that doesn't need consumer flows, SSOJet deserves shortlisting alongside WorkOS, Frontegg, and Auth0 B2B.
WorkOS
WorkOS is the strongest B2B-first CIAM in 2026 by deliberate scope choice, every product surface assumes the buyer is selling to enterprise IT, not to consumers. AuthKit's 1M MAU free tier makes it a credible Auth0 alternative for B2B SaaS that doesn't need adaptive risk or B2C consumer flows. For pure B2B SSO, SCIM, and audit logs, WorkOS is hard to beat at any price point.
FAQ
- Is SAML 2.0 still relevant in 2026?
- Yes. SAML 2.0 dominates the enterprise SSO install base. Every major IdP (Okta, Microsoft Entra, Ping, Google Workspace, OneLogin, JumpCloud) ships SAML as a first-class integration; many large enterprises have hundreds of SAML connections configured and will not migrate them all to OIDC for years. B2B SaaS that wants to sell into enterprise needs to support SAML, even when OIDC is the team's preferred protocol for new work.
- What's the difference between SAML and OAuth?
- SAML is an authentication-and-attribute-exchange protocol; it answers 'who is this user and what do we know about them'. OAuth 2.0 is an authorization protocol; it answers 'is this client allowed to take this action on this resource'. OIDC is the OAuth 2.0 extension that adds SAML-style authentication and attribute claims to OAuth. For enterprise SSO, SAML and OIDC are the two competing answers; OAuth on its own is not an SSO protocol.
- Why does SAML use XML if everything else moved to JSON?
- Historical. SAML 1.0 shipped in 2002 when XML was the dominant interchange format, and SAML 2.0 (2005) kept it for backward compatibility. The XML choice tied SAML to XML Signature (XMLDSig) and XML Encryption (XMLEnc) — both notoriously easy to misimplement, which is the source of most SAML vulnerabilities. OIDC chose JWT (JSON Web Tokens) precisely to avoid this complexity.
- What is XML Signature Wrapping and why does it keep coming up?
- XML Signature Wrapping (XSW) is an attack class where the signature in a SAML assertion is valid, but it points at one fragment of the XML document while the SAML processor evaluates a different fragment. The mismatch lets an attacker inject a forged Subject or NameID while keeping a real signature. XSW vulnerabilities have hit nearly every major SAML implementation at least once (Microsoft, Google, Salesforce, Shibboleth, Keycloak, OneLogin, Okta). Defense: validate that the signed fragment is the same fragment your code reads, and reject assertions where they differ.
- Do I need both SAML and OIDC for B2B SaaS?
- If the buyer is enterprise, yes. The customer's IT admin will pick the protocol their IdP is configured for; you don't get to choose. Production B2B CIAM (WorkOS, Auth0, Frontegg, MojoAuth, Keycloak, SSOJet) supports both per-Organization and lets the customer decide at IdP setup time. Shipping only one protocol means losing deals where procurement requires the other in writing.
- What is IdP-initiated vs SP-initiated SSO?
- SP-initiated: the user starts at the SaaS, the SaaS redirects to the IdP. IdP-initiated: the user starts in the IdP's app launcher (the Okta dashboard, the Entra MyApps page) and clicks into the SaaS, which then gets an unsolicited SAML assertion. Most IdPs and SAML libraries support both, but IdP-initiated has a wider attack surface (the SaaS receives an assertion it did not request) and many security teams disable it. SP-initiated is the safer default.
Sources
- OASIS SAML 2.0 Core (SAMLCore), March 2005
- OASIS SAML 2.0 Bindings (SAMLBind)
- OASIS SAML 2.0 Profiles (SAMLProf)
- OASIS SAML 2.0 Metadata (SAMLMeta)
- OASIS SAML 2.0 Security Considerations (SAMLSec)
- On Breaking SAML: Be Whoever You Want to Be (Somorovsky et al., USENIX Security 2012) — the canonical XML Signature Wrapping paper