In SAML 2.0, what does a service provider give up by accepting unsolicited IdP-initiated responses?
answer
- nothing was asked, so nothing matches
- no request means no stored state
- correlation lost, signature retained
- cannot demand context that was never requested
- branch on presence, not on lookup failure
basics
~20 sAn unsolicited Response carries no InResponseTo, so there is no stored request to match it against. It gives up correlation between answer and request, the state filed with that request, and any ability to refuse a login it never started.
solid answer
~50 sThe Web Browser SSO profile permits an identity provider to send a `<samlp:Response>` with no request behind it, and such a response MUST NOT carry `InResponseTo`. Everything inside the message still applies — the signature, the assertion and its validity conditions are checked exactly as before. What disappears is the layer above them: the service provider has no pending request to resolve, so it cannot insist that it asked before it answers. Three things go with it. It cannot bind the response to a login attempt it started, so a valid response presented at a moment of someone else's choosing is indistinguishable from a wanted one. It has no state filed beside the request, so the deep link and any requested attribute set or authentication strength are gone. And it cannot ask for anything — `<RequestedAuthnContext>`, `ForceAuthn` and `IsPassive` only exist on a request. Requiring `InResponseTo` is the switch that turns the unsolicited direction off entirely.
code
xml · 12 lines<samlp:Response
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="_b17e4d0c9a52"
Version="2.0"
IssueInstant="2026-09-19T11:02:18Z"
Destination="https://loans.example/acs">
<saml:Issuer>https://idp.university.example/idp</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
</samlp:Response>go deeper
Know that some logins arrive with no request behind them, and that such a response carries no InResponseTo because there is no request identifier to quote.
Name what is lost precisely — correlation, the state filed with the request, and the ability to ask for anything — and note that signature and assertion checks are untouched.
Make it a per-counterparty policy and show the code shape: branch on presence of the attribute, treat an unresolvable value as a hard failure, and land unsolicited logins somewhere fixed.
Weigh one partner's portal against the weaker guarantee you extend to every issuer if you enable the direction globally, and decide what an unsolicited login is permitted to reach.
## An unsolicited response is legal, not malformed The SAML 2.0 Web Browser SSO profile explicitly allows an identity provider to deliver a `<samlp:Response>` that no `<samlp:AuthnRequest>` asked for. A reader clicks the loan service in their institution's portal; the identity provider already has them authenticated; it produces a response and sends the browser to the service provider's assertion-consumer endpoint with it. Nothing is wrong with the message. Because there is no request identifier to quote, the response MUST NOT carry `InResponseTo`. So the question is never "is this valid SAML?" — it is "what does my service provider still know, and what has it stopped knowing?" ## What survives - The **signature** over the message or the assertion still establishes who produced it. - The **assertion** still names a subject, and its validity conditions still bound when and for whom it may be used. - The service provider still decides whether the sender is a party it trusts at all. An unsolicited login is not unauthenticated. It is uncorrelated, and those are different words. ## What is given up 1. **Correlation to a request.** With `InResponseTo` there is a question on file and the answer either matches it or is thrown away. Without one, any well-formed, correctly signed, still-valid response for a subject the service provider recognises is acceptable, whenever it is presented. Whoever holds such a response chooses the moment a session is created at the service provider — which is exactly the property a service provider that only supports SP-initiated login does not have. 2. **The state filed beside the request.** The deep link the reader was reaching for, the attribute set the service provider wanted, the tenant or connection it had already resolved — all of that was stored under the request `ID`. In the unsolicited case there is no key to retrieve it under and nothing was stored, so the service provider lands the reader on a default page or trusts a target the identity provider supplied. 3. **The ability to demand anything.** `<RequestedAuthnContext>`, `ForceAuthn`, `IsPassive`, `<NameIDPolicy>` and `AttributeConsumingServiceIndex` are attributes and elements of a request. With no request, the service provider takes the authentication the identity provider felt like performing, in the identifier format it felt like using. ## The switch, and where to put it | Policy | Rule at the assertion-consumer endpoint | Consequence | |---|---|---| | SP-initiated only | Reject any `<Response>` with no `InResponseTo` resolving to an outstanding request | Portal tiles at the counterparty stop working, and say so loudly | | Both directions | Branch on presence: match when present, apply unsolicited policy when absent | Correlation protects the SP-initiated half only | | Unsolicited, narrowed | Accept unsolicited only from named issuers, land on a fixed page, never follow a supplied target | Keeps the business case, removes the open-ended parts | The critical detail is that the branch must be on **presence**, not on lookup failure. "Look up the value; if nothing is found, treat the login as unsolicited" makes every failed match succeed, which is worse than not supporting the unsolicited direction and worse than not checking at all, because it looks like a check in code review. ## The loan service, concretely The inter-library loan service has one counterparty whose readers all arrive from a portal, and forty whose readers arrive by following citations. If it accepts unsolicited responses globally, the correlation check protects nobody: a response from any trusted issuer, for any subject, can be presented at any time. If it accepts them per counterparty, the forty keep the stronger path and the one gets the direction it needs. That per-counterparty decision is an integration policy; what this protocol layer gives you is the fact the decision turns on — the presence or absence of `InResponseTo`, and everything that presence was carrying. ## What an interviewer is listening for A candidate who says "IdP-initiated is less secure" has recited a slogan. A candidate who says "there is no request, so I have no state to match against, so I cannot refuse a login I did not start, and I lose the deep link and everything I would have asked for" has described the mechanism. The second answer also tends to arrive with the follow-up already handled: yes, the assertion is still signed; no, that is not the same property.
- Does accepting unsolicited responses mean the login is unauthenticated?No. The signature still establishes who produced the message and the assertion still states who the subject is and when the statement is usable. What is missing is correlation: the service provider cannot say it asked. Uncorrelated is not the same as unauthenticated, and conflating the two is how both halves of the answer get lost.
- How can a service provider support one counterparty's portal without weakening the rest?Make acceptance of unsolicited responses a per-issuer policy rather than a global setting, and narrow what an unsolicited login may do — a fixed landing page rather than a supplied target, and no elevation of anything the service provider would otherwise have requested.
- Why is "if the lookup fails, treat it as unsolicited" worse than simply not checking?Because it looks like a check. Every response that fails the match is promoted into the path that requires no match, so the code rejects nothing while reading in review as though it rejects mismatches. Branch on whether the attribute is present, and let a present-but-unresolvable value be a hard failure.
saying these in an interview costs you the question
- Says an unsolicited response is malformed or non-conformant
- Claims the assertion's signature restores the lost correlation
- Treats a failed lookup as an unsolicited login
- Thinks the service provider can still demand ForceAuthn here
- Assumes the deep link survives an IdP-initiated arrival