The only guide you'll ever need for SAML.
SAML stands for Security Assertion Markup Language. It's an open standard (XML-based) for exchanging authentication and authorization data between parties, specifically between an identity provider and a service provider.
The core problem SAML solves: How can App B trust that you've already logged into App A, without App B ever seeing your password?
SAML enables Single Sign-On (SSO): log in once, access many applications. No repeated passwords. No app-by-app accounts. Centralized control.
Click any step to expand the detail. This is SP-initiated flow (most common).
app.salesforce.com/dashboard without being logged in.AuthnRequest.302 Redirect to the browser pointing at the IdP's SSO URL, with the AuthnRequest embedded in the query string.https://idp.okta.com/sso/saml?SAMLRequest=PHNhbWxwOi...&RelayState=/dashboardRelayState is a bookmark, it remembers where the user was trying to go, so after login they land in the right place.Click any card to see a concrete example.
alice@company.com_abc123def456... (opaque, stable)email, firstName, lastName, groups, department, role. These drive authorization inside the SP.https://app.salesforce.comhttps://company.okta.com/app/samlhttps://app.salesforce.com/sso/saml/acs: The IdP will POST the SAMLResponse only to this whitelisted URL.InResponseTo + NotOnOrAfter fields prevent this.Here's a simplified (but real) SAML assertion. Every element has a purpose.
<!-- The SAML Response wrapper --> <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="_unique-response-id" InResponseTo="_request-id-from-sp" <!-- ties to AuthnRequest --> IssueInstant="2024-01-15T14:30:00Z" Status="Success"> <saml:Issuer>https://idp.okta.com/saml</saml:Issuer> <!-- who made this --> <!-- THE CORE ASSERTION --> <saml:Assertion ID="_unique-assertion-id" IssueInstant="2024-01-15T14:30:00Z"> <!-- WHO this assertion is about --> <saml:Subject> <saml:NameID Format="emailAddress"> alice@company.com </saml:NameID> <saml:SubjectConfirmation Recipient="https://app.salesforce.com/acs" <!-- must match ACS URL --> NotOnOrAfter="2024-01-15T14:35:00Z"/> <!-- expires in 5 min --> </saml:Subject> <!-- WHEN it's valid --> <saml:Conditions NotBefore="2024-01-15T14:29:55Z" NotOnOrAfter="2024-01-15T14:35:00Z"> <saml:AudienceRestriction> https://app.salesforce.com <!-- only valid for this SP --> </saml:AudienceRestriction> </saml:Conditions> <!-- HOW they authenticated --> <saml:AuthnStatement AuthnInstant="2024-01-15T14:30:00Z"> <saml:AuthnContext> PasswordProtectedTransport <!-- login method --> </saml:AuthnContext> </saml:AuthnStatement> <!-- USER ATTRIBUTES --> <saml:AttributeStatement> <saml:Attribute Name="email"> <saml:AttributeValue>alice@company.com</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="groups"> <saml:AttributeValue>admins</saml:AttributeValue> <saml:AttributeValue>engineering</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> <!-- DIGITAL SIGNATURE (IdP's private key) --> <ds:Signature>...</ds:Signature> </saml:Assertion> </samlp:Response>
slack.com, click "Sign in with SSO"InResponseTo to match, the SP can't verify it triggered the request. This opens potential for unsolicited assertion attacks. Disable IdP-initiated if you don't need it.
A binding is how SAML messages are transported. Think of it as the envelope type for the XML letter.
People confuse these constantly. Here's the clear breakdown:
| Dimension | SAML 2.0 | OAuth 2.0 | OIDC |
|---|---|---|---|
| Primary purpose | Authentication + SSO | Authorization (API access) | Authentication (on top of OAuth) |
| Format | XML | JSON / Tokens | JWT (JSON) |
| Era | 2005 โ Enterprise | 2012 โ Web/API | 2014 โ Modern Web |
| Typical use | Corporate SSO, legacy apps | "Login with Google" API access | Consumer apps, SPAs, mobile |
| Mobile friendly | โ (browser-centric) | โ | โ |
| Carries user attributes | โ Rich | โ (not its job) | ~ (ID Token) |
| Complexity | High (XML, certs) | Medium | Medium-Low |
| Where you'll see it | Salesforce, Workday, enterprise apps | API integrations, social login | Auth0, Google Sign-In, modern apps |
Audience matches its own Entity ID, an assertion meant for App A could be used to log into App B.