Why does the SAML HTTP-POST binding show the user a page that submits itself, and what is on that form?
answer
- browsers cannot POST on their own
- a page whose only job is submitting
- hidden control, name fixed by the binding
- base64 of the XML, no compression
- SAMLResponse plus an optional RelayState
basics
~20 sA browser will not originate a cross-site POST on its own, so the sender returns a page holding a form aimed at the recipient's endpoint and submits it by script. The form carries the base64-encoded SAML message in a hidden control named SAMLRequest or SAMLResponse.
solid answer
~40 sThe HTTP-POST binding, `urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST`, has to get a message from one server to another through a browser that only follows redirects and submits forms. Since there is no way to ask a browser to POST somewhere by itself, the sender returns an ordinary page whose form `action` is the recipient's endpoint, `method` is POST, and whose hidden control is named exactly `SAMLRequest` or `SAMLResponse` with the base64-encoded XML as its value. An optional second hidden control named `RelayState` may ride along, capped at 80 bytes by the binding. A script submits the form on load, and a `noscript` button lets the user do it manually. The flash of a near-empty page is that form being posted.
code
xml · 6 lines<form method="POST" action="https://register.example/sso/acs">
<input type="hidden" name="SAMLResponse"
value="PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6..."/>
<input type="hidden" name="RelayState" value="drw-4417-rev14"/>
<noscript><input type="submit" value="Continue"/></noscript>
</form>go deeper
Recall the shape: a page arrives, a hidden field named SAMLRequest or SAMLResponse holds base64 XML, and a script posts the form to the other party's endpoint. That is the whole mechanism.
Explain why the binding exists at all — a browser will not originate a cross-site POST — and name what the binding fixes: the control names, the base64 encoding with no compression, and the optional 80-byte RelayState control.
Show you can debug it from the wire: a mistyped control name, a GET where a POST was expected, base64 whitespace that one binding tolerates and the other forbids, and a resubmitted form arriving twice.
The judgment call is which binding each message direction uses across a set of partners, and what you standardise on when their length limits and encoders differ. Uniformity is worth more here than per-partner optimisation.
## What a binding is, and what this one has to solve A SAML **binding** is the rule for putting a SAML protocol message onto a concrete transport. It is neither the message nor the profile. The **Web Browser SSO profile**, `urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser`, says which messages flow between which parties; a binding says how each one physically travels. That profile has an awkward constraint at its centre: the two servers exchanging messages frequently have no direct connection to each other, so every message rides in the user's browser. A browser is a cooperative courier with exactly two habits a server can rely on. It follows a redirect by itself, and it submits a form. What it will never do is originate a cross-site POST unprompted. The HTTP-POST binding, `urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST`, is built on the second habit: to make the browser POST a message to the recipient's endpoint, the sender returns an ordinary HTML page containing a form aimed at that endpoint plus a small script that submits it on load. The blank flash the user sees — often captioned "please wait" — is that page. ## What is actually on the page - The form's `action` is the recipient's endpoint URL and its `method` is `POST`. - One hidden control is named **exactly** `SAMLRequest` when a request is being sent, or `SAMLResponse` when a response is. These names are fixed by the binding; they are not a local convention, and they are case-sensitive. - That control's value is the **base64 encoding (RFC 2045) of the XML message**. No compression is applied — this is the single largest mechanical difference from the Redirect binding. - If the sender is carrying state through the round trip, a second hidden control named `RelayState` holds it. At the binding level its value must not exceed **80 bytes**; what it means and who is allowed to trust it is a different subject entirely. - A `noscript` submit button, so the exchange still completes where scripting is off. The browser then sends an ordinary `application/x-www-form-urlencoded` POST body containing those same parameter names. ## POST against Redirect, on the points that matter here | | HTTP-POST | HTTP-Redirect | |---|---|---| | Encoding of the message | base64 of the XML | DEFLATE, then base64, then URL-encoding | | Where the message sits | a form control in a POST body | a query-string parameter | | Practical length budget | effectively none | whatever the shortest intermediary allows | | How a signature travels | enveloped inside the XML, untouched by the binding | detached, as separate `SigAlg` and `Signature` query parameters | | What the user sees | a page that submits itself | a redirect, with no visible page | ## Why a response almost always arrives this way A `<Response>` carrying a signed assertion is a large document, and the parts that make it large — a signature value, an embedded certificate — are high-entropy, so they barely compress. After encoding, such a message essentially precludes the Redirect binding on length grounds alone, which is why the binding specification prefers POST where a message contains signed content. There is a second, quieter reason. On this binding the sender does not have to do anything about signing at all: an enveloped XML signature sits inside the XML and is carried inside the base64 blob unchanged, so the binding neither knows nor cares that it is there. The Redirect binding cannot do that and must define a separate, detached signature over the query string instead. ## What goes wrong, and how it looks 1. **A mistyped control name.** `samlResponse`, `SAML_Response` or `saml-response` do not exist. The recipient sees a POST with no SAML parameter in it and rejects the whole request as malformed, which reads to an operator like "the identity provider sent nothing". 2. **The wrong binding aimed at the endpoint.** If the endpoint receives a GET whose query string carries `SAMLResponse`, the sender used HTTP-Redirect against an endpoint that expects HTTP-POST. Nothing about the message is wrong; the transport is. 3. **Base64 line breaks.** RFC 2045 base64 permits line breaks, and most POST-side parsers tolerate them. On the Redirect binding whitespace must be removed, so a sender that reuses one encoder for both bindings can work on one and fail on the other. 4. **The back button and resubmission.** Because the page really did submit a form, going back can prompt the user to resubmit it, and the recipient may then receive the same message twice. Deciding what to do with a repeat is the receiving implementation's problem, not the binding's. The habit worth forming is to read the exchange as bytes: which parameter name, which encoding, which HTTP method. Almost every binding-level failure is visible in exactly those three facts.
- What happens if the hidden control is named samlResponse instead of SAMLResponse?The recipient looks for `SAMLRequest` or `SAMLResponse` and finds neither, so it sees a POST with no SAML message in it and rejects the request. The names are fixed by the binding and case-sensitive; there is no fallback matching.
- Why does this binding not compress the message the way HTTP-Redirect does?Compression exists on the Redirect binding to fight a URL length ceiling. A POST body has no comparable practical limit, so compressing would buy nothing but processing cost and one more place for two implementations to disagree.
- What does the user see if scripting is disabled in the browser?The page stops at the form instead of submitting it, and the `noscript` button — conventionally labelled something like "Continue" — lets the user post it manually. The exchange still completes; it simply needs one click.
saying these in an interview costs you the question
- Says the POST binding compresses the message like Redirect does
- Thinks the hidden control can be named whatever the sender likes
- Believes base64 in the form hides the message from the user
- Calls the self-submitting page an implementation quirk rather than the binding
- Treats a GET carrying SAMLResponse as the same binding