SAML 2.0: the standard that invented web single sign-on
How SAML 2.0 federates identity into web apps — the IdP/SP/user roles and trust via metadata XML, SP-initiated vs IdP-initiated flows, the HTTP-Redirect/POST/Artifact bindings, the anatomy of a SAML assertion (Subject, Conditions, AuthnStatement, AttributeStatement), signing and encryption, and when SAML is still the right choice over OAuth/OIDC.
From storing identity to moving it
In the directory services article we established where identities live. Now we move them. SAML 2.0 is the first protocol in our stack — the one that took an identity sitting in a corporate directory and made it usable to log into an application the directory doesn’t own. It’s the grandparent of web federation, an OASIS standard finalized in 2005, and despite being two decades old it still authenticates a staggering share of enterprise software every day.
The problem SAML solved is the one every employee feels: you have one corporate identity, but dozens of applications, many of them SaaS running on someone else’s infrastructure. Without federation, each app needs its own password — a security and usability disaster. SAML’s answer: let one trusted system authenticate you, and let every application trust that system’s word instead of running its own login. That “word” is a signed XML document called an assertion, and understanding SAML is mostly understanding how that document is produced, carried, and verified.
The three roles and the trust between them
SAML has exactly three actors, and getting them straight makes everything else click:
- Identity Provider (IdP): the system that authenticates the user and issues assertions. It’s backed by the directory — Entra ID, Okta, ADFS, Ping. The IdP is where the password (or MFA) actually gets checked.
- Service Provider (SP): the application the user wants to reach. It outsources authentication to the IdP and consumes the assertion. Your SaaS apps are SPs.
- Principal (user): the human being authenticated, who experiences all of this as “click the app, you’re logged in.”
Trust is established with metadata XML
An SP can’t just trust any assertion that shows up — it has to know, in advance and cryptographically, which IdP to trust and how to verify its signatures. That bootstrapping happens through SAML metadata: an XML document each party publishes describing itself. Metadata contains:
- The entityID — the party’s unique identifier (usually a URL).
- The endpoints — where to send and receive SAML messages (e.g., the SP’s Assertion Consumer Service URL).
- The signing certificate(s) — the public key the other side uses to verify signatures.
- Supported bindings and NameID formats.
Setting up a SAML integration is, at bottom, exchanging metadata: the IdP and SP import each other’s metadata XML, and from that moment each knows the other’s identity, endpoints, and public keys. This pre-established, certificate-based trust is exactly why an SP can believe an assertion without ever contacting the user’s directory directly — the trust was wired up ahead of time.
sequenceDiagram accTitle: Establishing SAML trust via metadata exchange accDescr: Before any login happens, the identity provider and service provider exchange metadata XML. The IdP shares its metadata containing its entityID, SSO endpoint, and signing certificate. The SP shares its metadata containing its entityID, Assertion Consumer Service URL, and certificate. Each party imports the other's metadata, and from that point mutual trust is established so single sign-on can occur. participant SP as Service Provider participant IdP as Identity Provider IdP->>SP: IdP metadata (entityID, SSO URL, signing cert) SP->>IdP: SP metadata (entityID, ACS URL, cert) Note over SP,IdP: Each imports the other's metadata Note over SP,IdP: Mutual trust established — SSO can now happen
The two flows: SP-initiated vs IdP-initiated
There are two ways an SSO session can begin, and the difference matters for both UX and security.
SP-initiated SSO
The user starts at the application. This is the common, recommended flow:
sequenceDiagram accTitle: SP-initiated SAML single sign-on accDescr: The user requests a protected resource at the service provider. The SP generates an authentication request and redirects the user's browser to the identity provider. The IdP authenticates the user (password plus MFA), builds a signed SAML assertion, and posts it back through the browser to the SP's Assertion Consumer Service. The SP validates the signature and conditions, creates a session, and grants access. actor U as User (browser) participant SP as Service Provider (app) participant IdP as Identity Provider U->>SP: Request protected resource SP->>U: Redirect with AuthnRequest U->>IdP: Deliver AuthnRequest IdP->>U: Authenticate (password + MFA) IdP->>U: Signed assertion (HTTP-POST) U->>SP: POST assertion to ACS SP->>SP: Validate signature + conditions SP->>U: Session created, access granted
Reading the flow: the SP issues an AuthnRequest and redirects the browser to the IdP. The IdP authenticates the user, builds a signed assertion, and sends the browser back to the SP’s Assertion Consumer Service (ACS) URL carrying that assertion. The SP validates it and creates a local session. Crucially, the assertion travels through the user’s browser — SAML is a browser-mediated, front-channel protocol — and the SP correlates the response to the request it started, which closes off whole classes of injection attacks.
IdP-initiated SSO
Here the user starts at the IdP — a portal of app tiles — and clicks one. The IdP sends an unsolicited assertion straight to the SP’s ACS, with no prior AuthnRequest. It’s convenient (the classic “app launchpad” experience) but weaker: because there’s no request to correlate against, an assertion captured in transit is easier to replay, and the SP has less context to validate. Modern guidance is to prefer SP-initiated for anything sensitive and treat IdP-initiated as a convenience feature to enable deliberately, not by default.
Bindings: how SAML messages travel
A binding is the transport mechanism — how a SAML message is mapped onto HTTP. SAML 2.0 defines three you’ll meet:
| Binding | How it works | Typical use |
|---|---|---|
| HTTP-Redirect | Message compressed and placed in the URL query string | Sending the short AuthnRequest from SP to IdP |
| HTTP-POST | Message base64-encoded in a hidden form field, auto-submitted by the browser | Returning the assertion from IdP to SP (assertions are too big for a URL) |
| HTTP-Artifact | Browser carries only a small reference (“artifact”); the SP fetches the real assertion over a back channel | High-assurance setups that keep the assertion off the front channel entirely |
The practical pattern in the overwhelming majority of deployments is Redirect for the request, POST for the assertion: the AuthnRequest is small enough to ride in a URL, while the assertion — full of signed XML — is too large, so it comes back as an auto-submitting POST form. Artifact is rarer but valuable when you don’t want the assertion passing through the browser at all; instead the browser carries a one-time handle the SP redeems directly with the IdP, keeping the sensitive payload on a server-to-server channel.
Anatomy of a SAML assertion
The assertion is the heart of SAML — the signed note itself. It’s an XML document with four parts you should be able to recognize on sight:
<saml:Assertion ID="_a1b2c3" IssueInstant="2026-06-10T09:00:00Z">
<saml:Issuer>https://idp.example.com</saml:Issuer>
<ds:Signature>...</ds:Signature>
<saml:Subject>
<saml:NameID Format="...emailAddress">sara@example.com</saml:NameID>
<saml:SubjectConfirmation Method="...bearer">
<saml:SubjectConfirmationData
Recipient="https://sp.example.com/acs"
NotOnOrAfter="2026-06-10T09:05:00Z"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2026-06-10T08:59:00Z"
NotOnOrAfter="2026-06-10T09:05:00Z">
<saml:AudienceRestriction>
<saml:Audience>https://sp.example.com</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2026-06-10T09:00:00Z"
SessionIndex="_sess789">
<saml:AuthnContext>
<saml:AuthnContextClassRef>...PasswordProtectedTransport</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="department">
<saml:AttributeValue>Engineering</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>Each block answers a distinct question:
- Subject — who the assertion is about. The
NameIDis the identifier (here an email), andSubjectConfirmationsays how the SP can confirm the subject is the bearer, plus theRecipientandNotOnOrAfterthat scope it to this SP and this moment. - Conditions — when and for whom the assertion is valid.
NotBefore/NotOnOrAfterdefine a tight validity window (usually minutes), andAudienceRestrictionnames the exact SP the assertion is intended for — the SP must reject an assertion meant for someone else. - AuthnStatement — how the user authenticated.
AuthnInstantis when,AuthnContextClassRefdescribes the method (e.g., password over TLS, or an MFA context), andSessionIndexties to the IdP session — essential for single logout later. - AttributeStatement — what else the SP should know: attributes like department, groups, or roles, sourced from the directory, that the SP uses for authorization.
One structural subtlety worth internalizing: the assertion usually travels wrapped in a <samlp:Response> envelope, and either the response, the assertion, or both can be signed. That distinction sounds pedantic but it’s the whole ballgame for security — an SP that verifies only the response’s signature while reading the assertion’s attributes has left exactly the gap that XML Signature Wrapping exploits. The rule that prevents it is simple to state and easy to get wrong: validate the signature on the element you actually consume, and make sure that signed element is the one whose contents you trust.
Signing and encryption
SAML’s trust model is cryptographic, and it splits cleanly into two concerns.
XML Signature provides integrity and authenticity. The IdP signs the assertion (or the whole response) with its private key; the SP verifies with the IdP’s public certificate from metadata. A valid signature proves two things: the assertion really came from the trusted IdP, and not a single byte was altered in transit. Signing is, in any sane deployment, mandatory — an unsigned assertion is a note anyone could have written.
XML Encryption provides confidentiality. The IdP can encrypt the assertion (or specific attributes) with the SP’s public key, so that only the SP can read it. This matters because the assertion passes through the user’s browser, where it could be inspected; if it carries sensitive attributes (a national ID, a salary band, a health role), encryption keeps them private. Encryption is optional and used selectively — signing is about can I trust this?, encryption is about who else can read this?
The security pitfalls worth knowing
SAML’s reliance on complex XML has produced a recognizable family of attacks, all catalogued in the OWASP SAML Security Cheat Sheet:
- XML Signature Wrapping (XSW): an attacker restructures the XML so the SP validates a legitimate signature but reads attacker-controlled content. Defended by validating that the signature actually covers the element you consume.
- Missing or partial signature validation: accepting assertions whose signature isn’t checked, or only checking the response and not the assertion. The number-one SAML implementation bug.
- Audience/Recipient confusion: failing to confirm the assertion was minted for your SP, letting an assertion for one app be replayed at another.
- Replay: reusing a captured assertion within its validity window — mitigated by short lifetimes, one-time
NotOnOrAfter, and tracking assertion IDs.
The throughline: SAML is only as secure as the rigor of the SP’s validation. The protocol is sound; most real-world failures are SPs that validate too little.
Single Logout: the hard half
SAML also defines Single Logout (SLO) — ending a user’s sessions across all federated SPs from one action. The SessionIndex in the AuthnStatement is what makes it conceivable: it ties each SP session back to the IdP session, so when the user logs out the IdP can issue LogoutRequest messages to every SP holding a session under that index. In theory, one click cleanly terminates every federated session.
In practice, SLO is notoriously unreliable. It requires every SP to implement the logout endpoints correctly, to be reachable at logout time, and to honor the request — and a single misbehaving or offline SP breaks the chain, leaving sessions alive that the user believes are closed. Many organizations therefore treat SLO as best-effort and lean on short session lifetimes and revocation at the IdP as the real control. The lesson generalizes well beyond SAML: federating login is far easier than federating logout, a theme that returns in OIDC. Distributing the start of trust is simple; coordinating its simultaneous end across independent systems is genuinely hard.
Wiring up a SAML integration in practice
Theory aside, what does standing up a SAML connection actually involve? The recognizable steps practitioners follow, in order:
- Exchange metadata: import the IdP’s metadata into the SP and the SP’s into the IdP — or hand-configure entityID, ACS URL, and certificates when a metadata URL isn’t offered.
- Choose the NameID format: decide what uniquely and stably identifies the user across systems (email, or a persistent opaque ID). Mismatched NameID is the top cause of “it authenticates, but the SP doesn’t recognize the user.”
- Map attributes: configure which directory attributes the IdP releases (department, groups, roles) and the exact names the SP expects. This attribute mapping is where most integration time actually goes.
- Set signing and encryption: ensure assertions are signed, decide whether to encrypt, and confirm both sides agree on algorithms.
- Test the edges: first login, re-login, clock skew, and — critically — certificate rotation.
The field wisdom is blunt: most “SAML is flaky” complaints trace to attribute-mapping mistakes or expired certificates, not to the protocol. Document the metadata URLs and certificate expiry dates somewhere monitored, prefer signed assertions with tight audience restrictions and short lifetimes, and validate rigorously on the SP side. Do that and SAML is boringly reliable; skip it and you’ll be debugging mysterious lockouts every certificate cycle.
When SAML is still the right choice
Newer protocols (OAuth 2.0 and OIDC, the next two articles) are lighter, JSON-based, and better suited to mobile and APIs. So is SAML legacy? No — it’s specialized, and in its specialty it’s often still the best tool:
- Enterprise workforce SSO: virtually every enterprise SaaS supports SAML, and corporate IdPs (Entra ID, Okta, Ping) speak it fluently. For employees logging into business apps, SAML is the path of least resistance and broadest compatibility.
- B2B federation: when two organizations need to let one’s employees into the other’s systems, SAML’s metadata-based, certificate-anchored trust between two enterprises is mature and well understood.
- Compliance-heavy environments: regulated sectors with deep audit requirements often have SAML deeply embedded, with established controls and assessor familiarity — switching protocols carries risk that the regulation doesn’t reward.
Where SAML is the wrong tool is equally clear: consumer login at scale, native mobile apps, and API-to-API authorization, where XML and browser redirects are clumsy. That’s precisely the space OAuth 2.0 and OIDC own. The contrast at a glance:
| Dimension | SAML 2.0 | OAuth 2.0 / OIDC |
|---|---|---|
| Data format | XML | JSON / JWT |
| Born for | Enterprise web SSO | Delegated authorization; consumer & mobile login |
| Transport | Browser redirects + POST | HTTP/REST — works for APIs and native apps |
| Sweet spot | Workforce & B2B SaaS | Consumer, mobile, single-page apps, API access |
| Enterprise footprint | Ubiquitous, deeply embedded | Dominant for anything new |
In practice large organizations run both — SAML for the established enterprise estate, OIDC for everything new — and an IAM professional has to be fluent in the trade-off rather than dogmatic about one protocol.
Recap
SAML 2.0 is federated web SSO via signed XML assertions:
- Three roles: the IdP authenticates and issues assertions, the SP consumes them, the user experiences seamless login — with trust pre-established by exchanging metadata XML (entityID, endpoints, certificates).
- Two flows: SP-initiated (start at the app, recommended) and IdP-initiated (start at a portal, convenient but weaker).
- Three bindings: HTTP-Redirect (the request), HTTP-POST (the assertion), and Artifact (back-channel for high assurance).
- The assertion carries Subject, Conditions, AuthnStatement, and AttributeStatement — and the SP’s security lives entirely in validating all of it.
- Signing gives integrity and authenticity (mandatory); encryption gives confidentiality (optional). Most SAML breaches are validation failures, not protocol flaws.
- SAML still wins for enterprise workforce SSO, B2B federation, and compliance-heavy estates; OAuth/OIDC win for consumer, mobile, and APIs.
Hands-on exercises
These are practical — do them, don’t just read them:
- Decode a real assertion. Install a SAML-tracer browser extension, log into any SAML-protected app you use, and capture the flow. Find the AuthnRequest and the assertion, base64-decode the assertion, and label its Subject, Conditions, AuthnStatement, and AttributeStatement in the live XML.
- Identify the bindings. In that same capture, confirm which binding carried the AuthnRequest and which carried the assertion. Verify it matches the “Redirect for the request, POST for the assertion” pattern — and note the
NotOnOrAfterto see how short the assertion’s life really is. - Stand up a federation. Use a public sandbox like samltest.id to play both roles: register a test SP, upload metadata, and run an SP-initiated login end to end. Then break it on purpose — change the audience or let a cert mismatch — and watch the SP reject the assertion.
- Audit a config (use case). You inherit an SP that validates only the outer response signature and accepts assertions with a 24-hour lifetime and no AudienceRestriction. List every problem and the exact change for each.
- Design a B2B onboarding (use case). A partner company needs its employees to access your app via their own IdP. Sketch the metadata exchange, the NameID format you’d choose and why, the three attributes you’d map, and how you’d handle their certificate rotation.
- Choose the protocol (use case). Pick one app you reach via SAML and check whether it also offers OIDC. Then decide which you’d choose for a brand-new internal web app versus a B2B partner integration, and justify each choice in two sentences using the comparison table above.
Three questions to test yourself
- An SP accepts a SAML assertion and reads the user’s group attributes to grant admin access — but only checks the signature on the outer response, not the assertion itself. What class of attack does this invite, and what exactly should the SP validate instead?
- A colleague enables IdP-initiated SSO for a finance application because the app-tile launchpad is convenient. What’s the security objection, and what would you recommend?
- Explain why SAML uses HTTP-Redirect for the AuthnRequest but HTTP-POST for the assertion, and what HTTP-Artifact changes about where the assertion travels.
Frequently asked questions
What is SAML 2.0?
SAML 2.0 (Security Assertion Markup Language) is an OASIS standard from 2005 for federated authentication: it lets an identity provider vouch for a user — with a cryptographically signed XML 'assertion' — so they can log into a service provider without that service ever seeing their password. It's the protocol that made enterprise web single sign-on possible and remains ubiquitous in corporate and B2B SaaS.
What is the difference between an IdP and an SP in SAML?
The identity provider (IdP) is the system that authenticates the user and issues the assertion — typically the company's directory-backed login, like Entra ID, Okta, or ADFS. The service provider (SP) is the application the user wants to use, which trusts the IdP's assertion instead of running its own login. The user (principal) authenticates once at the IdP and is admitted to many SPs.
What is the difference between SP-initiated and IdP-initiated SSO?
In SP-initiated SSO the user starts at the application, which redirects them to the IdP to authenticate and then back with an assertion — the most common and most secure flow. In IdP-initiated SSO the user starts at an IdP portal and clicks an app tile, so the IdP pushes an unsolicited assertion to the SP. IdP-initiated is convenient but more exposed to replay and is discouraged for sensitive apps.
What is a SAML assertion?
A SAML assertion is the signed XML document the IdP issues to vouch for a user. It contains a Subject (who the user is), Conditions (validity window and which SP the assertion is for), an AuthnStatement (how and when they authenticated), and an AttributeStatement (attributes like email, department, or group). The SP validates the signature and conditions, then trusts its contents to establish a session.
How do SAML signing and encryption differ?
Signing (XML Signature) proves the assertion is authentic and unaltered — the SP verifies it with the IdP's public certificate from metadata, and it's mandatory in practice. Encryption (XML Encryption) hides the assertion's contents from anyone but the intended SP and is optional, used when attributes are sensitive. Signing protects integrity and authenticity; encryption protects confidentiality.
Is SAML still relevant compared to OAuth and OIDC?
Yes, in its niche. SAML remains the default for enterprise workforce SSO and B2B federation, where mature IdPs, deep compliance requirements, and existing app support make it the path of least resistance. For consumer login, mobile apps, and API authorization, the lighter, JSON-based OAuth 2.0 and OpenID Connect have largely won — so the two coexist, each strong where the other is awkward.