SAML Decoder
Paste a SAML blob from a browser trace and read it — both bindings auto-detected, assertion semantics extracted, entirely on this device.
Paste a SAML message to decode it. Nothing you paste leaves this device.
Assertion semantics
Issuer, conditions, audience and attributes appear here.
Decoded XML
The decoded SAML document appears here.
Message
- Type
- —
- Issuer
- —
- Destination
- —
- InResponseTo
- —
- ID
- —
- IssueInstant
- —
- Status code
- —
- Second-level status code
- —
- Status message
- —
- Assertions
- —
Signature
No XML signature in this document
This page reports that a signature is present and how it is described. It never checks whether the signature is valid.
Press ? for shortcuts · Never stored between visits
Decoding runs entirely in this tab. There are no third-party requests on this page, no uploads and no analytics.
Do it offline:$
How to use it
- Paste the parameter, or the entire IdP URL — the SAMLRequest or SAMLResponse value is lifted out and percent-decoded, and any RelayState or SigAlg beside it is listed as seen.
- Check the transport badge. It is read from the bytes themselves, and the picker beside it pins a binding if you disagree; nothing changes silently underneath you.
- Work the semantics panel: message kind, issuer, subject, validity window against your clock, audience and every attribute statement. Subject and attribute values stay hidden behind their own controls until asked for.
- Switch to the document view for the indented XML, copy either panel, or download it. A share link carries the built-in sample unless you confirm otherwise.
Copy a SAMLRequest or SAMLResponse out of a browser trace and paste it whole, query string and all. Both transports are recognised on sight: the POST form field, and the redirect parameter that is compressed before encoding. You get the document pretty-printed beside the parts that decide a login — issuer, subject, validity window, audience and attribute statements, read entirely on this device.
Examples
https://idp.example.org/saml2/sso?SAMLRequest=fZJPT8MwDMW%2FSpR716z7H62VyiZEpQHVVjhwQVnrbZGapMQujG%2BP1oEYB3a1309%2Bz%2FYclakbmbZ0sGt4awGJHU1tUXaNmLfeSqdQo7TKAEoq5Sa9X8moJ2TjHbnS1fwCuU4oRPCkneUsW8b8VfW3UTmohjDajcWkP41mAzXcjspxNYHpbiY4ewaP2tmYRz3BWYbYQmaRlKWYRyIaB2IQiGEhZrI%2FkkK8cLYEJG0VddSBqEEZhrpqenBUpqmh5%2Fw%2BPFmNQkTHWfrjaeEstgb8Bvy7LuFpvfrl8RcvnQlViZzl3%2FFvtK203V9Pvj2LUN4VRR7kj5uCJ%2FOTC9ll8sk%2FkwyQqhSpeXgpnp%2FP9qAMZMvc1br8ZLfOG0XXXZwqugp2nVQ2p90igSXO0rp2HwsPiiDm5FvgYXKe%2Bfc7ki8%3D&RelayState=%2Fdashboard<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="_a1b2c3d4e5f60718293a4b5c6d7e8f90"
Version="2.0"
IssueInstant="2026-03-04T09:15:00Z"
Destination="https://idp.example.org/saml2/sso"
AssertionConsumerServiceURL="https://sp.example.com/acs"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST">
<saml:Issuer>https://sp.example.com/metadata</saml:Issuer>
<samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" AllowCreate="true"/>
</samlp:AuthnRequest>The badge lands on redirect: 424 characters of Base64 hiding 562 bytes of compressed markup. RelayState is listed as seen and left alone. No signing element exists, which for a request is ordinary.
response.post — a signed Response, pasted from the form field of an ACS POSTResponse · issuer https://idp.example.org/metadata · InResponseTo _a1b2c3d4e5f60718293a4b5c6d7e8f90
Status urn:oasis:names:tc:SAML:2.0:status:Success
NameID SYNTHETIC-SUBJECT-0001 · Format urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
Conditions 2026-03-04T09:15:02Z → 2026-03-04T09:20:07Z · Audience https://sp.example.com/metadata
AuthnStatement 2026-03-04T09:15:05Z · urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport · SessionIndex _x0000000000000000000000000000003
Attribute urn:oid:0.9.2342.19200300.100.1.3 (mail) = ada@sp.example.com
Attribute https://example.org/claims/groups = engineering, oncall
Signature assertion scope · http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 · digest http://www.w3.org/2001/04/xmlenc#sha256 · 1 embedded certificateEverything a login turns on, in one panel. Subject and attribute values arrive hidden and are shown here revealed. The signing element wraps the assertion, not the whole message — a distinction named, never scored.
authnRequest.redirect after a form decoder ran over it — every + is now a spaceBase64 payload carries spaces where "+" characters belong — a form decoder turned every "+" into a space. Re-copy the raw SAMLRequest or SAMLResponse value straight from the query string, before any form decoding.Nothing is guessed. The spaces are put back as plus signs and the blob re-run through both pipelines; only when that succeeds does this message appear. The culprit is a form decoder sitting between the wire and your clipboard, so the fix is to re-copy from the raw query string.
encryptedResponse.post — a Response whose assertion is encryptedResponse · issuer https://idp.example.org/metadata
Status urn:oasis:names:tc:SAML:2.0:status:Success
1 assertion is encrypted (<EncryptedAssertion>) — this tool does not decrypt, so no semantics are shown for the encrypted content.The envelope still reads: kind, issuer and status survive encryption. What was sealed with the service provider's key stays sealed, and the panel says so rather than printing empty rows.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
The redirect parameter is raw DEFLATE
SAML 2.0 Bindings §3.4.4.1 compresses before encoding and omits the zlib wrapper, so tools expecting a header refuse a valid parameter. The bare stream is what the specification mandates.
Prefixes carry no meaning
samlp:, saml2p:, ns0: or no prefix at all — matching is by namespace URI and local name, so one document written three ways yields identical readings. A test pins all three together.
NotOnOrAfter excludes its own instant
At exactly that timestamp the assertion has already lapsed (SAML 2.0 Core §2.5.1.2). Verifiers usually permit some clock drift; if the window holds only because of that allowance, it is said aloud.
Doctypes are never expanded
External entities are never fetched, internal ones never substituted: the declaration passes through as one opaque token, so entity-expansion attacks have nothing to act on.
Nothing is kept after you leave
An assertion routinely carries a name, an address and group memberships, so this route stores nothing between visits and loads no code from elsewhere. Reload, and the panel is empty.
Common errors
Base64 payload carries spaces where "+" characters belong — a form decoder turned every "+" into a space. Re-copy the raw SAMLRequest or SAMLResponse value straight from the query string, before any form decoding.- Something between the wire and your clipboard treated the value as form data, where a plus sign means a space. Take it from the raw request line, before any decoding step touches it.
SAML payload is not valid Base64 at position 22 of the payload — a SAMLRequest or SAMLResponse value is Base64 (RFC 4648 §4); re-copy the raw parameter value.- The counted offset marks the first character that cannot belong to the alphabet. Usually the paste swept up a quotation mark or an ampersand, or stopped short of the closing padding.
Base64 decoded to text that is neither XML nor raw DEFLATE — it is not a SAML message. Decode it at /base64-decode to see what it is.- Both transports were attempted and both landed on something that is not markup — usually a neighbouring parameter grabbed by mistake, which the linked tool identifies in one step.
Root element <note> is not a SAML 2.0 protocol message or assertion — SAML elements live in urn:oasis:names:tc:SAML:2.0:protocol or urn:oasis:names:tc:SAML:2.0:assertion. General XML lives at /xml-formatter.- Well-formed markup from some other vocabulary still decodes and still prints, indented; only the semantics panel has nothing to say. The named root element tells you what arrived.
Input is larger than the 512 KB limit for this tool.- Messages of this protocol are kilobyte-scale; half a megabyte means a log file went into the box. The paste is declined entire, because a truncated parameter decompresses into confident nonsense.
FAQ
What is the difference between the POST and redirect bindings?
They differ in one step. An ACS form field carries the document Base64-encoded and nothing more; a redirect parameter is squeezed through raw DEFLATE first so it survives a URL, and its signature rides beside it as separate query parameters instead of inside the markup. Which one you hold is read off the bytes.
Can this page tell me whether a SAML signature is valid?
No, and it is built not to. You get whether a signing element exists, whether it wraps the message or the assertion, which algorithms it names, and whether a certificate is embedded. Checking the maths needs canonicalisation and reference resolution against a trusted key — a different job, and faking it would be worse than silence.
Why is my assertion unreadable?
Look for an EncryptedAssertion or EncryptedID element. Identity providers often encrypt to the service provider's public key, and only the holder of the matching private key can open it — your service provider, not a web page. Kind, issuer and status still read normally, and the panel names what it cannot show.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Decode again now, though decoding already follows your typing.
- ⌘/Ctrl + S
- Download the decoded document; the browser save dialog is suppressed.
- ⌘/Ctrl + C
- Copy the panel you are in, unless you selected something.
- ⌘/Ctrl + Shift + C
- Copy that panel whatever the selection.
- t
- Advance the colour theme, ignored while typing or composing.
- ? or ⌘/Ctrl + /
- Open the shortcut overlay and its browser-conflict list.
- Esc
- Dismiss the topmost dialog; pasted text survives untouched.