What Is a SAML Assertion? Structure and Signatures

Guilliano MolaireGuilliano Molaire11 min read

A SAML assertion is a signed XML statement that an identity provider (IdP) sends to a service provider (SP) to say who a user is, how and when they signed in, and which attributes (such as email or group membership) apply to them. The service provider trusts the assertion because the IdP’s signature covers it, so it can create a session without ever seeing the user’s password. A SAML response is the envelope that carries the assertion across the browser, and the distinction between the two matters for security, as the sections below explain.

This guide walks through what is inside an assertion, how it differs from a response, what a service provider has to check before it accepts one, and where those checks have gone wrong in practice. It ends with how Keycloak handles assertions when it acts as the IdP and when it acts as the SP.

What is a SAML assertion?

SAML 2.0 is an OASIS standard from 2005 for exchanging authentication and authorization data between organizations. Its central idea is that one party, the asserting party, makes claims about a subject, and another party, the relying party, decides whether to act on them. The OASIS SAML 2.0 Core specification defines an assertion as a package of information that supplies zero or more statements made by a SAML authority.

In single sign-on, the asserting party is the IdP (for example Microsoft Entra ID, Okta or Keycloak) and the relying party is the SP (the application the user wants to reach). The assertion typically makes three kinds of statements:

  • Authentication statement: the user authenticated at a particular time, by a particular method.
  • Attribute statement: the user has these attributes, such as email, givenName or groups.
  • Authorization decision statement: the user may or may not access a resource. This one is rarely used in modern SSO, and most deployments carry authorization data as attributes instead.

If you are choosing between SAML and OpenID Connect for a new integration, our comparison of SAML and OIDC covers the trade-offs. The closest OIDC equivalent of an assertion is the ID token, which we describe in ID token vs access token.

What does a SAML assertion look like?

The following assertion is shortened and annotated. Real assertions carry namespaces, a full signature block and often more attributes, but the structure is the same.

<saml:Assertion ID="_a75adf55" Version="2.0" IssueInstant="2026-10-15T09:00:00Z">

  <saml:Issuer>https://idp.example.com/realms/acme</saml:Issuer>

  <ds:Signature>
    <!-- Signature over this Assertion element, referenced by ID="_a75adf55" -->
  </ds:Signature>

  <saml:Subject>
    <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
      jane@acme.example
    </saml:NameID>
    <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
      <saml:SubjectConfirmationData
        Recipient="https://app.example.com/saml/acs"
        InResponseTo="_req_9f3c"
        NotOnOrAfter="2026-10-15T09:05:00Z"/>
    </saml:SubjectConfirmation>
  </saml:Subject>

  <saml:Conditions NotBefore="2026-10-15T08:59:30Z" NotOnOrAfter="2026-10-15T09:05:00Z">
    <saml:AudienceRestriction>
      <saml:Audience>https://app.example.com/saml/metadata</saml:Audience>
    </saml:AudienceRestriction>
  </saml:Conditions>

  <saml:AuthnStatement AuthnInstant="2026-10-15T09:00:00Z" SessionIndex="_sess_41d2">
    <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="email">
      <saml:AttributeValue>jane@acme.example</saml:AttributeValue>
    </saml:Attribute>
    <saml:Attribute Name="groups">
      <saml:AttributeValue>finance</saml:AttributeValue>
    </saml:Attribute>
  </saml:AttributeStatement>

</saml:Assertion>

Each element answers a specific question the service provider has:

Element Question it answers
Issuer Which IdP made this statement?
Signature Did that IdP really make it, and has it been altered since?
Subject / NameID Who is the user, in the identifier format the SP asked for?
SubjectConfirmation Who may present this assertion, where, and until when? The bearer method means whoever holds it can use it, which is why the other checks matter.
Conditions During what window, and for which service provider (Audience), is the assertion valid?
AuthnStatement When did the user sign in, how, and in which IdP session (SessionIndex, which later single logout requests refer to)?
AttributeStatement What else does the IdP say about the user?

What is the difference between a SAML response and a SAML assertion?

A SAML response is the protocol message that carries the result of an authentication request. An assertion is the statement about the user inside it. The response has its own Issuer, a Status element saying whether the request succeeded, a Destination and an InResponseTo value tying it to the original request, and then one or more assertions.

<samlp:Response ID="_resp_77a1" Destination="https://app.example.com/saml/acs"
                InResponseTo="_req_9f3c">
  <saml:Issuer>https://idp.example.com/realms/acme</saml:Issuer>
  <ds:Signature><!-- optional: signs the whole Response --></ds:Signature>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <saml:Assertion ID="_a75adf55"> <!-- may carry its own ds:Signature --> ... </saml:Assertion>
</samlp:Response>

Both layers can carry an XML signature, and IdPs differ in which they sign. Some sign only the response, some only the assertion, and some both. This is why IdP configuration screens often have separate options such as “sign documents” and “sign assertions”. A service provider has to be configured to expect whichever the IdP produces, and it must read the user’s identity only from content that the verified signature actually covers. The next sections explain why that last requirement carries so much weight.

When the assertion is encrypted, it appears as an EncryptedAssertion element. The SP decrypts it with its private key, and the signature inside is verified after decryption.

How does an assertion travel from the IdP to the service provider?

In the common web browser SSO flow, the user’s browser carries the messages, and SAML defines “bindings” for how. In the SP-initiated flow, the SP sends an AuthnRequest to the IdP, usually through the browser with the HTTP-Redirect binding, and the IdP replies with a response containing the assertion. The HTTP-POST binding is the usual choice for the response, because assertions are too large for a URL: the IdP returns an HTML form containing the base64-encoded response, and the browser posts it to the SP’s assertion consumer service (ACS) URL.

The HTTP-Redirect binding works differently with signatures. Instead of an embedded XML signature, the message is deflate-compressed into a query parameter and the signature is calculated over the query string and sent in separate Signature and SigAlg parameters. The SP therefore verifies a signature over bytes of a URL, which means the way the URL is split into parameters becomes part of the security boundary.

RelayState is an opaque value the SP sends with its request and receives back unchanged, normally to remember which page the user wanted. It is not part of the signed assertion, so it must never be trusted for security decisions. The IdP-initiated vs SP-initiated SSO guide covers the flow differences, and our post on decoding a SAMLRequest shows what the request half of the exchange looks like.

Identity management as a service, on open source

Skycloak does what Auth0 and Okta do, SSO, MFA, SCIM, audit logs and enterprise federation, on an open source core. Unlimited users and applications on every plan, no charge per monthly active user, and you can export and self-host whenever you want.

How does a service provider validate a SAML assertion?

A service provider should check all of the following, and a failure in any one means rejecting the login:

  1. Signature. Verify the XML signature against the signing certificate you configured for this specific IdP, such as the one from its metadata. Do not accept a certificate embedded in the message itself, since an attacker can put in their own.
  2. What the signature covers. Confirm the signature’s Reference points at the element you are about to read, and extract the user’s identity from that verified element only.
  3. Issuer. The Issuer must be the IdP you expect.
  4. Audience. The AudienceRestriction must name your SP’s entity ID. This stops an assertion issued for one application being replayed at another.
  5. Destination and Recipient. These must match your ACS URL.
  6. Time window. The current time must fall between NotBefore and NotOnOrAfter, allowing a small clock-skew tolerance of a minute or two.
  7. InResponseTo. For SP-initiated login, it must match a request ID your SP actually issued and has not yet consumed.
  8. Single use. Remember the assertion ID until it expires and reject a second presentation, which blocks replay of a captured assertion.

The OASIS SAML 2.0 Web Browser SSO profile lists the processing rules a relying party must follow. Most teams should rely on a maintained SAML library for these steps instead of writing their own, and should keep it updated, because the failures described next were all library-level.

When does SAML assertion validation go wrong?

The recurring failure is a mismatch between what the signature verifier checks and what the code that reads the identity looks at.

In 2012, Somorovsky and colleagues presented “On Breaking SAML: Be Whoever You Want to Be” at the USENIX Security Symposium. They showed that many SAML frameworks could be tricked with XML signature wrapping (XSW). In a wrapping attack, the attacker keeps the validly signed element in the document but moves it somewhere harmless, then inserts a forged element where the application looks for the user’s identity. The signature still verifies, because the signed element is still present, and the application then reads the attacker’s forged one.

In 2018, researchers at Duo Security disclosed a different kind of mismatch affecting several SAML libraries, tracked under CVE-2017-11427 through CVE-2017-11430 among others. An XML comment inserted into the NameID value, for example jane@acme.example<!---->.attacker.example, was handled differently by the component that verified the signature and the component that read the text. An attacker who controlled an account such as jane@acme.example.attacker.example could insert a comment so that the signature still verified while the service provider read only jane@acme.example.

The pattern has continued. Keycloak’s 26.8.1 upgrading notes include a change titled “Semicolons are no longer treated as query parameter delimiters”, which explains that, because different layers of the server treated ; inconsistently, “the parameters used to process a request could differ from those used to verify its signature”. The note does not say which features were affected, but the HTTP-Redirect binding, whose signature is computed over the query string, is the kind of place where that mismatch matters. The practical conclusions are the same ones as in the checklist above: verify the signature against a pinned certificate, then read identity only from exactly the content that was verified, and keep your SAML libraries and your IdP software patched. Our guide to Keycloak SAML security and exploit mitigation goes through concrete hardening steps.

How does Keycloak handle SAML assertions?

Keycloak can sit on either side of the exchange, and the settings you meet differ.

Keycloak as the IdP. You register each application as a SAML client. On the client’s settings, the Sign documents and Sign assertions switches control which layer Keycloak signs, and Client signature required controls whether Keycloak insists that the SP signs its AuthnRequest. Encryption of assertions is configured on the client’s Keys tab, using the SP’s certificate. Keycloak publishes its own signing certificates in its SAML descriptor, and the realm’s key providers decide which key is active, which is what you rotate when a certificate nears expiry. When you rotate, add a new key provider with a higher priority, keep the old key enabled so it stays in the descriptor, have each SP refresh its metadata, and only then disable the old key.

Keycloak as the SP. When a customer brings their own SAML IdP, you add it as a SAML identity provider in your realm. The settings that matter are Validate Signatures (with the IdP’s signing certificate), Want Assertions signed and Want Assertions encrypted. The Keycloak SAML service provider guide walks through that setup, and Identity Providers shows what Skycloak exposes for it.

If you offer enterprise SSO to your own customers, each of them will have a different IdP, a different choice of what to sign, and a different certificate expiry date. Skycloak runs upstream Keycloak for you, so the IdP-side signing keys and the Keycloak patching are operated for you, while your applications’ SAML libraries remain yours to keep updated; see single sign-on for what that covers.

Frequently asked questions

What is the difference between a SAML assertion and a SAML response?

The response is the protocol message that returns the outcome of an authentication request, including a status code and the InResponseTo link. The assertion is the statement about the user inside it. Either one, or both, can carry the XML signature depending on how the IdP is configured.

Should I sign the response, the assertion, or both?

Whichever your service provider verifies, and the SP must read identity only from signed content. Signing the assertion is the more robust choice for the user’s identity, because the assertion is the part the SP relies on and a signed assertion stays verifiable even if it is passed along or re-wrapped in a different response. Signing both is also common and is accepted by most SPs. What matters most is that the SP and IdP agree and that the SP enforces it.

How long is a SAML assertion valid?

The validity window is set in Conditions (NotBefore and NotOnOrAfter) and in SubjectConfirmationData, and it is usually a few minutes, since the assertion only has to survive the browser redirect. That is separate from how long the user’s session at the SP lasts, which the SP decides after it has accepted the assertion.

Can a SAML assertion be replayed?

A captured assertion that is still inside its time window could be presented again unless the SP tracks assertion IDs and rejects repeats, checks InResponseTo for SP-initiated logins, and enforces Recipient and Audience. Those checks are in the validation list above.

Does SAML encrypt the assertion by default?

No. Signing and encryption are separate. Most deployments rely on TLS to protect the assertion in transit and on the signature for integrity, and add assertion encryption when attributes are sensitive since the browser and any TLS-terminating proxy can read an unencrypted assertion.

How do I inspect a SAML assertion while debugging?

Capture the SAMLResponse form value from the browser’s network tab, base64-decode it and read the XML. For responses sent over the HTTP-Redirect binding, the value is also deflate-compressed, so you need to inflate it after decoding. Treat captured assertions as sensitive, since a bearer assertion inside its time window is a credential.

Summary

A SAML assertion is the IdP’s signed claim about a user, and the service provider’s job is to verify that signature, confirm the assertion was meant for it and still valid, and take the user’s identity only from the content the signature covered. When you configure a new SAML integration, decide up front which layer your IdP signs, check that your SP enforces audience, recipient, time window and single use, and set a calendar reminder for the signing certificate’s expiry. When you run Keycloak yourself, keep it on a current patch release.

Identity management as a service, on open source

Skycloak does what Auth0 and Okta do, SSO, MFA, SCIM, audit logs and enterprise federation, on an open source core. Unlimited users and applications on every plan, no charge per monthly active user, and you can export and self-host whenever you want.

Guilliano Molaire
Written by
Founder, Skycloak

Guilliano is the founder of Skycloak and a cloud infrastructure specialist with deep expertise in product development and scaling SaaS products. He discovered Keycloak while consulting on enterprise IAM and built Skycloak to make managed Keycloak accessible to teams of every size.

© 2026 Skycloak. All Rights Reserved. Design by Yasser SolimanKeycloak™ is a trademark of the Linux Foundation. Skycloak is not affiliated with the Keycloak project.