By AndyPublished
JWT vs SAML: Tokens, Assertions and Single Sign-On
In practice: SAML remains the standard for enterprise web SSO into SaaS applications, and every serious identity provider supports it. JWT-based OpenID Connect is the default for new applications, mobile and single-page apps, and anything that also needs to call APIs. Many organisations run both.
JWT vs SAML Token: Format Compared
A SAML assertion and an OIDC ID token carry almost the same information. Here is an abbreviated SAML 2.0 assertion, with namespaces and most of the signature trimmed:
<saml:Assertion ID="_a75adf55" IssueInstant="2026-09-24T09:00:00Z" Version="2.0">
<saml:Issuer>https://idp.example.com/saml</saml:Issuer>
<ds:Signature>
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#_a75adf55">...</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>kJ3x...</ds:SignatureValue>
</ds:Signature>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">ada@example.com</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData InResponseTo="_req42" NotOnOrAfter="2026-09-24T09:05:00Z"
Recipient="https://app.example.com/saml/acs"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2026-09-24T08:59:30Z" NotOnOrAfter="2026-09-24T09:05:00Z">
<saml:AudienceRestriction><saml:Audience>https://app.example.com</saml:Audience></saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2026-09-24T09:00:00Z" SessionIndex="_s1"/>
<saml:AttributeStatement>
<saml:Attribute Name="groups"><saml:AttributeValue>engineering</saml:AttributeValue></saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>And the decoded payload of an equivalent OpenID Connect ID token:
{
"iss": "https://idp.example.com",
"sub": "00u1a2b3c4",
"aud": "app-client-id",
"iat": 1790240400,
"exp": 1790240700,
"auth_time": 1790240400,
"nonce": "n-0S6_WzA2Mj",
"email": "ada@example.com",
"groups": ["engineering"]
}The ID token is then signed as a JWS and serialised as header.payload.signature. The fields map closely:
| SAML assertion | JWT / OIDC claim |
|---|---|
| <Issuer> | iss |
| <Subject><NameID> | sub |
| <AudienceRestriction><Audience> | aud |
| <Conditions NotBefore> | nbf |
| <Conditions NotOnOrAfter> | exp |
| <Assertion IssueInstant> | iat |
| <Assertion ID> | jti |
| <AuthnStatement AuthnInstant> | auth_time (OIDC) |
| <AuthnContextClassRef> | acr (OIDC) |
| <SubjectConfirmationData InResponseTo> | nonce (OIDC, roughly equivalent) |
| <AttributeStatement> | Custom or standard claims (email, name, groups) |
Each JWT claim is described in JWT claims explained. The validation rules are the same idea on both sides: right issuer, right audience, inside the time window, signature valid.
JWT vs SAML Authentication: The Full Comparison
| Aspect | SAML 2.0 | JWT (via OpenID Connect) |
|---|---|---|
| What it is | A full federation protocol (SAML 2.0, OASIS, 2005) plus its assertion format | A token format (RFC 7519); the protocol is usually OpenID Connect or OAuth 2.0 |
| Encoding | XML, Base64-encoded when sent through the browser | JSON, Base64url-encoded, three dot-separated segments |
| Signature | XML Signature (XML-DSig) over a canonicalised XML element | JWS (RFC 7515) over the exact encoded header and payload bytes |
| Encryption | XML Encryption: EncryptedAssertion | JWE (RFC 7516), rarely used for ID tokens |
| Key distribution | X.509 certificate in SAML metadata XML | JWKS endpoint advertised by the OIDC discovery document |
| Typical size | Several KB; too large for an HTTP header | Usually under 1 KB; designed for headers and URLs |
| Transport | Browser redirects and auto-submitting POST forms | Token endpoint responses, then Authorization headers |
| Primary use | Enterprise web SSO | Consumer and enterprise sign-on, mobile and SPA apps, API access |
| API and mobile support | Poor: built for browser-to-web-app flows | Native: tokens are sent directly to APIs |
SSO With JWT vs SAML: How the Flows Differ
SAML SP-initiated SSO
- ·The user opens the application (the service provider). It builds an
AuthnRequestand redirects the browser to the identity provider, usually with the HTTP-Redirect binding. - ·The user authenticates at the IdP.
- ·The IdP returns an HTML page containing an auto-submitting form that POSTs a Base64-encoded
SAMLResponseto the application’s Assertion Consumer Service (ACS) URL. - ·The application verifies the XML signature, checks audience, recipient, time conditions and
InResponseTo, then creates its own session, typically a cookie.
SAML also supports IdP-initiated SSO, where the user starts from a portal tile and the IdP posts an unsolicited response. It is convenient but removes the request binding that protects against replayed and injected responses.
OpenID Connect SSO
- ·The application redirects the browser to the provider’s
/authorizeendpoint withscope=openid, astate, anonceand a PKCE challenge. - ·The user authenticates; the browser comes back with a short-lived authorisation code.
- ·The application exchanges the code at the token endpoint over a direct back-channel call and receives an ID token (a JWT) and usually an access token.
- ·The application verifies the ID token against the provider’s JWKS and creates its session.
The structural difference: in SAML the token travels through the browser, so its signature is the only protection. In the OIDC code flow the token comes from a server-to-server call over TLS, which removes a whole class of injection problems. The access token from the same flow can then be used to call APIs, which SAML has no native answer for. The OIDC side is covered in JWTs in OAuth 2.0 and OpenID Connect.
Security: XML Signatures vs JWS
Both formats have a history of implementation bugs, and they differ in kind.
- ·SAML: XML Signature signs one element inside a larger document, after canonicalisation. That creates XML Signature Wrapping attacks, where an attacker moves the signed element and inserts an unsigned one that the application reads instead. XML parsers add XXE and entity-expansion risks, and comment handling in
NameIDhas caused authentication bypasses in several libraries. - ·JWT: the signature covers the exact bytes of the header and payload, so there is no wrapping problem. The classic flaws are in header trust instead: accepting
alg: none, algorithm confusion between RSA and HMAC, and unvalidatedkidorjkuvalues. See the none algorithm vulnerability and JWT attacks and vulnerabilities.
Validating a SAML Assertion vs a JWT
The checks a relying party must run are close to identical, which is a useful way to see that the two formats solve the same problem. For each item, the SAML check is on the left and the JWT check on the right.
- ·Signature: verify the XML signature with the IdP certificate from metadata, and confirm the signed element is the one you read / verify the JWS with the key from the JWKS matching
kid, using a pinned algorithm. - ·Issuer:
Issuerequals the configured IdP entity ID /issequals the configured issuer URL, exactly. - ·Audience: your SP entity ID appears in
AudienceRestriction/ your client ID appears inaud. - ·Time window: now is between
NotBeforeandNotOnOrAfter/ now is beforeexpand not beforenbf, with a small clock-skew allowance on both. - ·Binding to your request:
InResponseTomatches the AuthnRequest you sent andRecipientmatches your ACS URL /noncematches the one you stored before redirecting. - ·Replay: remember assertion IDs until they expire and reject repeats / the code flow makes ID token replay much harder, and
jtican be tracked where needed.
The JWT side of this list is covered claim by claim in the JWT verification guide, and the time checks, including clock skew, in common JWT errors. On the SAML side, the most important habit is to read attributes only from the element whose signature you verified, never by searching the whole document.
Using JWT and SAML Together
The two are not mutually exclusive, and mixed estates are common:
- ·Identity brokering: a broker such as Keycloak or a hosted identity platform accepts SAML from a customer’s corporate IdP and issues OIDC ID tokens and JWT access tokens to your applications. Your apps only ever see JWTs.
- ·SAML bearer grant: RFC 7522 lets a client exchange a SAML 2.0 assertion at an OAuth token endpoint for an access token, which may be a JWT.
- ·Token exchange: RFC 8693 defines token type identifiers for both SAML 1.1 and SAML 2.0 assertions alongside JWTs, so a security token service can convert between them.
Where JWT and SAML Are Used Today
- ·SAML: workforce SSO into SaaS products, where enterprise customers expect a SAML option from Okta, Microsoft Entra ID, Google Workspace or ADFS; higher-education and research federations; many government and legacy line-of-business systems.
- ·JWT / OIDC: consumer sign-in (Google, Apple, Microsoft accounts), mobile and single-page apps, B2B SaaS built in the last decade, API authorisation, and service-to-service identity.
If you are building a new B2B application, the pragmatic answer is usually to implement OIDC yourself and support SAML through a broker or identity platform, because some enterprise customers will require it. If you only need to call APIs, SAML is the wrong tool. To inspect an ID token or access token from either route, paste it into the jwtdecode.app decoder, which decodes it in the browser without sending it anywhere.
JWT vs OAuth vs SAML
The three sit at different layers. SAML is a federation protocol for authentication with its own XML token. OAuth 2.0 is an authorisation framework for API access and does not define authentication at all. JWT is a token format used by OpenID Connect (for authentication) and by many OAuth deployments (for access tokens). A modern stack typically pairs OIDC and OAuth with JWTs; SAML sits alongside for enterprise SSO. JWT vs OAuth covers the second half of that picture.
Summary
- ·SAML is a complete SSO protocol with XML assertions; JWT is a token format, used for SSO through OpenID Connect.
- ·SAML assertions are signed with XML-DSig and delivered through browser POSTs; JWTs are signed with JWS and fit in HTTP headers.
- ·The claims map almost one-to-one: Issuer to iss, NameID to sub, Audience to aud, NotOnOrAfter to exp.
- ·SAML remains the enterprise SSO standard; OIDC with JWTs is the default for new, mobile and API-driven applications.
- ·Brokers, the SAML bearer grant (RFC 7522) and token exchange (RFC 8693) let the two coexist.