SAML (Security Assertion Markup Language) authentication is an open standard that lets a user sign in once at an identity provider (IdP) and then access separate web applications, called service providers (SPs), without giving each app a password. The IdP sends the app a digitally signed XML message, called a SAML assertion, confirming who the user is. SAML 2.0, maintained by OASIS, is the version in use today.
SAML at a glance (2026 verdict)
| Question | Answer |
| What does SAML do? | Transfers a verified identity and user attributes from an IdP to an app, enabling enterprise single sign-on (SSO) |
| Authentication or authorization? | Primarily authentication. The app makes the authorization decision from the attributes SAML delivers |
| Current version | SAML 2.0, published by OASIS in 2005 |
| Best fit | Browser-based enterprise and B2B SaaS logins, government and university federations |
| Poor fit | Native mobile apps, API access, machine-to-machine and AI-agent access (use OAuth 2.0 or OIDC) |
| Implementation difficulty (editorial rating) | Moderate when you use an established IdP and a maintained library. High if you write your own XML signature validation |
| Security reality | The standard is sound, but library bugs are real: several SAML libraries shipped critical authentication bypasses in 2025 |
How Does SAML Work?

Read more in detailed: What Is SAML? How SAML Works, How SAML Is Used, and Where It Breaks
The SP-initiated SAML flow. The service provider and identity provider never talk directly; every message passes through the browser.
SAML works through a trust relationship set up in advance, followed by a browser-based message exchange at each login. The IdP and the SP never talk directly during login. Every message travels through the user’s browser.
Before any login (one-time setup): the IdP and SP exchange SAML metadata files. Metadata contains each party’s entity ID (a unique name, usually a URL), endpoint URLs, and the IdP’s X.509 signing certificate.
SAML authentication flow example: Microsoft Entra ID to Salesforce
This is the SP-initiated flow, the most common pattern. Microsoft Entra ID (formerly Azure AD) is the IdP and Salesforce is the SP.
- The user opens Salesforce. Salesforce sees no active session and recognizes the user’s company is configured for SAML.
- Salesforce creates an AuthnRequest. This XML message has a unique ID, a timestamp, and the Assertion Consumer Service (ACS) URL where the response must go.
- The browser carries the request to Entra ID. Salesforce redirects the browser to the IdP’s SSO URL with the request attached.
- Entra ID authenticates the user. It prompts for credentials and MFA, or skips the prompt if the user already has an IdP session.
- Entra ID builds a SAML Response. The response contains a signed assertion with the user’s identifier, attributes (email, groups), and validity window.
- The browser posts the response to Salesforce’s ACS URL. An auto-submitting HTML form sends it.
- Salesforce validates the response and creates a session. If any check fails, login fails. The checks are listed in the 9-point checklist below.
The user types a password only at the IdP. Salesforce never sees or stores it.
What is the difference between SP-initiated and IdP-initiated SAML?
| SP-initiated | IdP-initiated | |
| Where the user starts | The app’s URL or login page | The IdP dashboard (clicking an app tile) |
| AuthnRequest sent? | Yes | No |
| Response contains InResponseTo? | Yes, linked to the original request | No, the response is unsolicited |
| Security trade-off | The SP can confirm it asked for this response | The SP cannot tie the response to a request, which raises replay and login-CSRF risk |
| Recommendation | Default choice | Support only if required, with strict replay protection |
For More Infromation: What Is a SAML IdP? Providers, Examples, and 2026 Security Checks
Why does the request use a redirect but the response use a POST?
SAML defines transport methods called bindings. The AuthnRequest is small, so it is compressed, encoded, and placed in the URL query string (HTTP-Redirect binding). The signed response is too large for a URL, so it is sent in a hidden form field (HTTP-POST binding). A third option, HTTP-Artifact, sends only a reference and lets the SP fetch the full message server-to-server.
Measured in our lab test (method below):
| Message | Raw XML size | Size as sent |
| Minimal AuthnRequest | 450 bytes | 348 characters after DEFLATE and Base64 (fits in a URL) |
| Signed Response with one assertion and one attribute | 3,770 bytes | 5,028 characters after Base64 (sent via POST) |
Production responses with more attributes, group lists, or an embedded certificate chain are larger.
What Is a SAML Assertion?
A SAML assertion is the signed XML statement inside the SAML Response that tells the SP who the user is and under what conditions that claim is valid. The SAML 2.0 core specification defines three statement types an assertion can carry:
| Statement type | What it says | How often it is used |
| Authentication statement | The user authenticated at this time, using this method (password, MFA) | In almost every SSO assertion |
| Attribute statement | Facts about the user: email, name, department, groups, roles | Very common |
| Authorization decision statement | Whether the user may perform an action on a resource | Rare; OASIS itself describes it as rudimentary |
For More Information: What Is a SAML Assertion? Structure, Example, and Validation (2026)
What is a SAML token?
“SAML token” is an informal name for a SAML assertion. The term comes from web services security standards, where a SAML assertion is carried as a security token. In SSO discussions, “SAML token,” “SAML assertion,” and “assertion” refer to the same object.
What does a real SAML assertion example look like?

Below is a trimmed assertion with valid timestamps. The numbered comments map to the validation checklist later in this guide.
Each part of a SAML assertion and the check the service provider runs on it.
<saml:Assertion ID="_7f3c9a" IssueInstant="2026-09-21T14:05:10Z" Version="2.0">
<saml:Issuer>https://sts.windows.net/tenant-id/</saml:Issuer> <!-- Check 3: expected IdP -->
<ds:Signature>...</ds:Signature> <!-- Checks 1 and 2 -->
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
jane.doe@example.com
</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData
InResponseTo="_a1b2c3"
NotOnOrAfter="2026-09-21T14:10:10Z"
Recipient="https://example.my.salesforce.com/saml/acs"/> <!-- Checks 5, 6, 7 -->
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2026-09-21T14:04:40Z" NotOnOrAfter="2026-09-21T14:10:10Z">
<saml:AudienceRestriction>
<saml:Audience>https://example.my.salesforce.com</saml:Audience> <!-- Check 4 -->
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2026-09-21T14:05:08Z" SessionIndex="_s9x2">
<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="groups">
<saml:AttributeValue>finance-readonly</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
The assertion is valid for about five minutes. A short window limits how long a stolen assertion can be replayed. To decode a real assertion for debugging, use a tool such as samltool.io and never paste production assertions into untrusted sites.
Is SAML Authentication or Authorization?
SAML is an authentication standard that also carries the data apps use for authorization. The IdP proves identity (authentication statement) and sends attributes such as groups or roles (attribute statement). The SP then decides what the user can do, for example mapping the group finance-readonly to a read-only role.
SAML’s built-in authorization decision statement exists but is rarely deployed, because richer policy languages replaced it. So the precise answer is: authentication plus attribute transfer, with authorization enforced by the application.
For Detailed Information: What Is SAML Authentication? How It Works, With Examples
Is SAML a Protocol?
SAML is more accurately a framework with four layers, one of which is a set of protocols. Calling it a “protocol” is common shorthand and not wrong, but it is incomplete.
| Layer | What it defines | Examples |
| Assertions | The content: statements about a user | Authentication, attribute, authorization decision statements |
| Protocols | Request and response message pairs | AuthnRequest/Response, LogoutRequest/Response |
| Bindings | How messages travel over a transport | HTTP-Redirect, HTTP-POST, HTTP-Artifact, SOAP |
| Profiles | Combinations of the above for a use case | Web Browser SSO profile, Single Logout profile |
“SAML SSO” usually means the Web Browser SSO profile: AuthnRequest over HTTP-Redirect, Response over HTTP-POST.
What is SAML 2.0 authentication?
SAML 2.0 authentication is SSO performed under the SAML 2.0 specification, the version OASIS approved in March 2005. SAML 1.0 (2002) and 1.1 (2003) are legacy and not interoperable with 2.0. SAML 2.0 merged SAML 1.1 with the Liberty Alliance ID-FF and Shibboleth work, which is why it became the common standard for cross-organization federation.
SAML vs OAuth vs OIDC: What Is the Difference?
SAML authenticates users to web applications. OAuth 2.0 authorizes an application to access an API on a user’s behalf and does not, by itself, authenticate anyone. OpenID Connect (OIDC) adds an identity layer on top of OAuth 2.0, making it the modern alternative to SAML for login.
| Criteria | SAML 2.0 | OAuth 2.0 | OpenID Connect |
| Primary purpose | Authentication and attribute transfer | Delegated authorization to APIs | Authentication on top of OAuth 2.0 |
| Message format | XML, signed with XML Signature | Access tokens (format not mandated; often JWT) | JSON, ID token as a signed JWT |
| Transport | Browser redirects and form POSTs | HTTP, API calls | HTTP, API calls |
| Native mobile and SPA support | Poor | Strong | Strong |
| API and AI-agent access | Not designed for it | Designed for it | Yes, via OAuth tokens |
| Typical use | Workforce SSO into SaaS, B2B enterprise customers, federations | “Allow this app to access your calendar” | “Sign in with Google,” modern app login |
| Year standardized | 2005 | 2012 | 2014 |
For more information: SAML vs OAuth: What Is the Difference and Which Should You Use in 2026?
When should you use SAML instead of OAuth or OIDC?
- Use SAML when enterprise customers require it. Many corporate IdPs and procurement checklists still list SAML 2.0 as the SSO requirement.
- Use OIDC for new consumer, mobile, or single-page apps, and for workforce SSO where the customer’s IdP supports it.
- Use OAuth 2.0 whenever software, including AI agents and integrations, needs scoped API access.
- Support both SAML and OIDC if you sell B2B SaaS: this covers nearly every customer IdP.
SAML and OAuth can also work together. RFC 7522 defines how an app can exchange a SAML assertion for an OAuth access token, letting a SAML-authenticated session call APIs.
Read More: SAML vs OIDC: Which SSO Protocol Should You Use in 2026?
Is SAML Authentication Secure?
SAML is secure when the service provider validates every response correctly. Nearly all real-world SAML compromises come from implementation flaws in validation code, not from the standard itself.
The main attack class is XML Signature Wrapping (XSW): an attacker keeps a valid signature in the document but adds a forged assertion elsewhere, and a buggy library checks the signature on one element while reading user data from another. A related 2025 technique, the parser differential, exploits two XML parsers inside the same library reading the same document differently.
Which SAML vulnerabilities were disclosed in 2025?
| Disclosure | Library | Impact | Fixed in |
| March 2025: CVE-2025-25291, CVE-2025-25292 (GitHub Security Lab) | ruby-saml (Ruby) | An attacker holding one valid signature made with the target’s SAML signing key could build their own assertions and log in as any user. Rated CVSS v3.x 9.8 (Critical) | 1.12.4 and 1.18.0 |
| May 2025: CVE-2025-47949 (advisory) | samlify (Node.js) | Signature wrapping in versions before 2.10.0 let an attacker forge a SAML Response and authenticate as any user, given any document signed by the IdP. CVSS v4.0 score 9.9 | 2.10.0 |
| December 2025: CVE-2025-66567, CVE-2025-66568 (GitLab advisory) | ruby-saml | Authentication bypass caused by an incomplete fix for CVE-2025-25292 | 1.18.0 |
| December 2025: “The Fragile Lock” (PortSwigger Research) | Multiple, incl. xmlseclibs (PHP) | New SAML bypass techniques; xmlseclibs 3.1.4 fixed a libxml2 canonicalization flaw | Varies by library |
These bugs matter because identity remains central to breaches. In the Verizon 2026 Data Breach Investigations Report, exploitation of vulnerabilities was the first access step in 31% of breaches, credential abuse fell to 13% as a first step, and credential abuse still appeared somewhere in 39% of breaches. A SAML library bypass combines both risks: it is a software vulnerability that hands an attacker a valid identity.
What must a service provider validate in every SAML response?
The 9-point SAML response check:
- Signature is valid using the IdP certificate from your stored metadata, never a certificate embedded in the incoming message.
- The signed element is the element you read. The signature’s reference ID must match the assertion you extract user data from. This single check defeats signature wrapping.
- Issuer equals the expected IdP entity ID.
- Audience equals your SP entity ID.
- Recipient and Destination equal your exact ACS URL.
- Time window: current time is within NotBefore and NotOnOrAfter, allowing only a small clock skew (commonly 1 to 5 minutes).
- InResponseTo matches a request your SP actually sent (SP-initiated flows).
- Replay protection: store each assertion ID until it expires and reject duplicates.
- Status is Success, unsigned assertions are rejected, the response contains exactly one assertion, and one XML parser is used for both verification and data extraction.
PortSwigger’s research adds a rule for authorization logic: avoid using email domain suffixes as access control, because parser discrepancies can defeat that check.
What happened when we tested these checks?
Method: We built a local IdP and SP in Python 3.12.3 using signxml 5.1.0 and lxml 6.0.2 (September 2026). The IdP signed each assertion with RSA-SHA256 and exclusive canonicalization, a 5-minute validity window, and the SP allowed 2 minutes of clock skew. We then ran ten test cases against two validators: a strict one implementing all nine checks, and a naive one that verifies the signature but reads the first assertion it finds. This is a lab reproduction with local test keys, not a capture from a production IdP. The full script is published alongside this article so you can rerun it.
| # | Test case | Result | Check that caught it |
| 1 | Valid response | Accepted as jane.doe@example.com | None needed |
| 2 | Same response submitted twice | Rejected: replay detected | 8 |
| 3 | NameID changed to admin@example.com after signing | Rejected: digest mismatch | 1 |
| 4 | IdP signed with a rotated certificate the SP did not have | Rejected: invalid signature | 1 |
| 5 | Audience sent with a trailing slash | Rejected: audience mismatch | 4 |
| 6 | Assertion issued 10 minutes earlier | Rejected: expired | 6 |
| 7 | IdP clock 4 minutes ahead of the SP | Rejected: not yet valid | 6 |
| 8 | Response answering a different request ID | Rejected: InResponseTo mismatch | 7 |
| 9a | Signature wrapping attack vs naive validator | Accepted as admin@example.com | None |
| 9b | Same attack vs strict validator | Rejected: more than one assertion | 9 |
The signature wrapping attack in test 9a needed no key and no cryptography. We copied the legitimately signed assertion, removed the signature from the copy, changed the user to admin@example.com, and placed the forged copy before the signed original. The signature still verified, because the original was untouched, and the naive validator logged us in as admin.

Lab test 9a: the forged assertion passes a naive validator and is rejected by a strict one.
The fix is one line of logic. With the one-assertion rule disabled, reading data only from the element the signature covers still returned jane.doe@example.com:
# Vulnerable: verifies the signature, then reads the first assertion in the document
XMLVerifier().verify(xml, x509_cert=idp_cert)
name_id = doc.find(“.//saml:Assertion/saml:Subject/saml:NameID”, NS).text
# Fixed: reads user data only from the element the signature covers
signed = XMLVerifier().verify(xml, x509_cert=idp_cert).signed_xml
name_id = signed.find(“saml:Subject/saml:NameID”, NS).text
The full script is available on GitHub so you can rerun the tests.
What Are the Most Common SAML Errors and How Do You Fix Them?
Rows marked “Lab” were reproduced in the test above. Exact error wording varies by IdP and SP.
| Error (typical wording) | Most likely cause | Fix | Lab |
| “Invalid signature” | IdP signing certificate was rotated or expired | Import the new certificate from updated IdP metadata; schedule rotations before expiry | Yes (test 4) |
| “Audience restriction failed” | SP entity ID mismatch, often a trailing slash or http vs https | Make the entity ID identical in IdP and SP configuration | Yes (test 5) |
| “Assertion is not yet valid” or “expired” | Server clock drift or a delayed submission | Sync servers with NTP; keep skew tolerance small | Yes (tests 6, 7) |
| “InResponseTo does not match” or “unsolicited response” | IdP-initiated login, or the SP’s request-tracking cookie was dropped | Enable IdP-initiated handling explicitly, or fix cookie settings (next row) | Yes (test 8) |
| Login works in one browser, fails in another | The session cookie uses SameSite=Lax, so browsers do not send it on the cross-site POST from the IdP | Set SameSite=None; Secure on the cookie used to track the SAML request | No |
| “User not found” | NameID format mismatch (email vs persistent ID) | Align the NameID format and the SP’s user-matching field | No |
| User logs in but has no permissions | Attribute names differ between IdP and SP (for example groups vs a URI-style claim name) | Map attribute names exactly in both systems | No |
| Redirect loop after login | ACS URL misconfigured or session not created after validation | Confirm the ACS URL and check SP logs for a silent validation failure | No |
What Does SAML Not Do?
- It does not create or delete accounts. SAML logs users in. Provisioning and deprovisioning need SCIM or just-in-time (JIT) provisioning, where the SP creates an account from assertion attributes on first login. Without SCIM, a departed employee’s local SP account can remain.
- It does not end existing sessions reliably. SAML Single Logout exists, but it depends on every SP responding through the browser, and one failure leaves sessions open. Short SP session lifetimes are the dependable control.
- It does not handle APIs, native mobile apps, or AI agents. These need OAuth 2.0 tokens.
- It does not replace MFA. SAML is only as strong as the IdP login behind it.
Where Is SAML Authentication Used in 2026?
| Sector | Example | Region |
| Workforce SaaS SSO | Okta, Microsoft Entra ID, Google Workspace, and PingFederate as IdPs for Salesforce, Workday, Zoom, Slack | Global |
| B2B SaaS | “Enterprise SSO” tiers requiring SAML 2.0 integration with the customer’s IdP | Global |
| Research and education federations | InCommon (US), Canadian Access Federation (Canada), Australian Access Federation (Australia), INFED (India), connected globally through eduGAIN | US, Canada, Australia, India, Europe |
| Government identity | The EU eIDAS cross-border identity network uses a SAML 2.0-based message format | Europe |
In the US, NIST SP 800-63C-4, dated July 2025, sets federal guidance for federation and assertions and supersedes SP 800-63C (2020). Its requirements are protocol-neutral, covering SAML and OIDC alike, and it adds user-controlled digital wallets to the federation model.
Frequently Asked Questions (FAQs)
Is SAML the same as SSO?
No. SSO is the outcome (one login, many apps). SAML is one standard that delivers it. OIDC and Kerberos also provide SSO.
Is SAML more secure than OAuth?
Neither is inherently more secure; they solve different problems. SAML’s XML signature processing is more complex, which is why signature wrapping bugs recur in SAML libraries. OIDC’s JSON tokens are simpler to parse and validate.
Is a SAML assertion encrypted?
Not by default. A signature proves the assertion is authentic and unchanged, but anyone who can see the browser traffic can still read its contents, including email and group attributes. SAML supports encrypting the assertion with XML Encryption (an EncryptedAssertion element) using the SP’s public key. Enable it when assertions carry sensitive attributes, and always use HTTPS for every endpoint.
Does SAML support MFA and passkeys?
Yes, because authentication happens at the IdP. Any method the IdP supports, including MFA and passkeys, works with every SAML app behind it. The assertion’s AuthnContextClassRef records how the user signed in, and an SP can request a stronger method by sending RequestedAuthnContext in its AuthnRequest. The SP should verify that the returned value meets its requirement rather than assume it.
Should you build SAML support yourself?
Build on a maintained, widely used library or an identity platform rather than writing XML signature validation. Pin library versions, monitor security advisories, and test against signature wrapping cases before release. Test 9a above shows why.
*Lab tests run in September 2026 with Python 3.12.3, signxml 5.1.0, and lxml 6.0.2 against a local IdP and SP using test keys.
