skip to content

SP- and IdP-Initiated SSO

SP-initiated login against an unsolicited IdP-initiated response: what AuthnRequest asks for and what InResponseTo proves. Interviewers ask which direction your integration actually supports.

part ofFederated identityoverview, primer and where to startread it →
on this pageshow

questions

5

In SAML 2.0 web single sign-on, what makes a login SP-initiated rather than IdP-initiated?

level: juniorimportance: must knowfreq 50%

answer

  1. which end sends the first message
  2. request first, or response alone
  3. AuthnRequest exists in one direction only
  4. unsolicited response quotes no request
  5. only one direction survives a deep link

basics

~20 s

SP-initiated login starts at the service provider, which sends the browser to the identity provider carrying an AuthnRequest message. IdP-initiated login starts at the identity provider, which sends an unsolicited Response the service provider never asked for.

solid answer

~50 s

SP-initiated means the login begins at the service provider. A reader follows a citation into a loan-request page, the service provider has no session for that browser, so it builds a `<samlp:AuthnRequest>`, names itself in `<saml:Issuer>`, stores the request's `ID`, and sends the browser to the identity provider's single sign-on endpoint. The identity provider authenticates the reader and returns a `<samlp:Response>` to the service provider's assertion-consumer endpoint carrying `InResponseTo` equal to that `ID`. IdP-initiated means the login begins at the identity provider: the reader picks the service from a portal and the identity provider sends an **unsolicited** `<samlp:Response>`. No `<AuthnRequest>` was ever sent, so the response MUST NOT carry `InResponseTo`. The direction decides whether the service provider can match the answer to a question it asked, and what it can ask for in the first place.

code

xml · 14 lines
xml
<samlp:AuthnRequest
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    ID="_a4f1c9e2b7d3"
    Version="2.0"
    IssueInstant="2026-09-19T09:14:05Z"
    Destination="https://idp.university.example/sso"
    AssertionConsumerServiceURL="https://loans.example/acs"
    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST">
  <saml:Issuer>https://loans.example/sp</saml:Issuer>
  <samlp:NameIDPolicy
      Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
      AllowCreate="true"/>
</samlp:AuthnRequest>

go deeper

for a junior

Recall which end starts each direction: SP-initiated begins at the application with an AuthnRequest, IdP-initiated begins at the identity provider with a response nobody asked for.

for a middle

Explain what the request carries that the unsolicited case cannot — a stored ID, a requested identifier format, a requested authentication strength — and that the answer quotes that ID back in InResponseTo.

for a senior

Show that one endpoint can serve both and that accepting unsolicited logins is a deliberate policy switch, not a default. Say what your own integration actually supports and why.

for a principal

Frame the direction as a commitment to counterparties: supporting unsolicited logins widens what you will accept from partners you do not run, and that choice is easier to make than to withdraw later.

## Two ends of the same exchange SAML 2.0 web single sign-on is one message exchange between two parties, carried by an ordinary browser. A **service provider** owns a protected resource and will not serve it to an unknown visitor. An **identity provider** is willing to make a signed statement about who the person at the browser is. The only structural question left is which end starts. In an **SP-initiated** login the service provider starts. A reader follows a citation into an inter-library loan request page for one specific volume. The service provider finds no session for that browser and, instead of showing a login form of its own, builds a `<samlp:AuthnRequest>`, names itself in `<saml:Issuer>`, generates an `ID` and stores it with the pending login, and hands the browser to the identity provider's single sign-on endpoint. The identity provider authenticates the reader and sends the browser back to the service provider's assertion-consumer endpoint with a `<samlp:Response>` whose `InResponseTo` attribute quotes that `ID`. In an **IdP-initiated** login nobody asked. The reader is already signed in at their institution's portal and clicks the loan service in a list. The identity provider produces a `<samlp:Response>` and sends the browser to the service provider's assertion-consumer endpoint with it. There was no request, so there is no request identifier to quote, and the specification is explicit that `InResponseTo` MUST NOT be present when the response was not generated in answer to a request. ## What the request carries, and what is therefore missing the other way The attributes of `<AuthnRequest>` are the service provider's entire side of the conversation — everything it gets to say before the identity provider takes over: - **`ID`** — unique, generated and stored by the service provider; the answer must quote it back. - **`IssueInstant`** and **`Version`** — when the message was produced, and that it is a SAML 2.0 message. - **`Destination`** — the endpoint this message is intended for. - **`AssertionConsumerServiceURL`** together with **`ProtocolBinding`**, or the mutually exclusive **`AssertionConsumerServiceIndex`** — where the answer should be delivered and how. - **`AttributeConsumingServiceIndex`** — which set of attributes about the person the service provider wants. - **`<NameIDPolicy>`** with its `Format` and `AllowCreate` — what kind of identifier for the person is acceptable, and whether the identity provider may mint a new one. - **`<RequestedAuthnContext>`** — how strongly the service provider wants that person authenticated. - **`ForceAuthn`** and **`IsPassive`** — whether to authenticate afresh, and whether to do so without showing anything. In an IdP-initiated login none of that is sent, so none of it can be asked for. The service provider takes what arrives. ## What actually changes for the service provider | | SP-initiated | IdP-initiated | |---|---|---| | First message on the wire | `<AuthnRequest>` from the service provider | `<Response>` from the identity provider | | `InResponseTo` on the `<Response>` | present, equal to the request's `ID` | MUST NOT be present | | Stored state at the service provider | a pending request keyed by that `ID` | none | | The deep link the reader wanted | held with the pending request, echoed through `RelayState` | only whatever the identity provider chose to put in `RelayState` | | Authentication demands | expressible with `<RequestedAuthnContext>`, `ForceAuthn`, `IsPassive` | none — nothing was asked | Both directions are legitimate. Both end at the same assertion-consumer endpoint, and the same code path can serve both: the service provider branches on whether `InResponseTo` is present. Present means it must match an outstanding request; absent means the login is unsolicited, and accepting it at all is a policy decision the service provider makes deliberately rather than by omission. ## Why the direction is the first thing an interviewer asks Most engineers have only ever integrated one direction, and they tend to describe it as though it were the protocol. A candidate who says "the app redirects you to the identity provider with a request" has described SP-initiated only, and will be surprised the first time a business-to-business counterparty announces that its portal will simply post an assertion at them. A candidate who says "the identity provider sends us the user" has described IdP-initiated only, and has probably never stored a request identifier in their life. For the loan service the practical difference is mundane and decisive. In the SP-initiated case the reader lands on the volume they clicked, because the service provider knew what they were reaching for before the detour started. In the IdP-initiated case the reader arrives at the service cold: the service provider knows who they are and nothing about what they wanted, and must either pick a default landing page or trust a target the identity provider supplied.

  • In an IdP-initiated login, how does the reader end up on the page they actually wanted?
    Nothing in an unsolicited `<Response>` names a target by itself. The identity provider normally puts a deep link into `RelayState` and the service provider redirects there after validating the assertion. That value arrived through the browser and the enveloped signature inside the message does not cover it, so the service provider must treat it as untrusted input rather than as a destination.
  • Can one assertion-consumer endpoint serve both directions at once?
    Yes — a `<Response>` arrives there either way. The service provider branches on `InResponseTo`: present means it must match a request `ID` it generated and is still awaiting; absent means the login is unsolicited, and it applies whatever policy it has chosen about accepting logins it never started.
  • Which party decides the direction?
    Whoever holds the entry point the reader used. A link into a protected resource produces an SP-initiated login; a tile in the institution's portal produces an IdP-initiated one. The service provider cannot force the direction after the fact — it can only decide, in advance, which directions its endpoint accepts.

saying these in an interview costs you the question

  • Says both directions begin with an AuthnRequest
  • Thinks IdP-initiated means the response is unsigned
  • Believes an unsolicited response still carries InResponseTo
  • Assumes every service provider supports both directions
  • Claims the service provider picks the direction when the response arrives
open as a page

In a SAML 2.0 Response message, what does the InResponseTo attribute prove, and what must a service provider compare it against?

level: middleimportance: must knowfreq 58%

basics

~20 s

InResponseTo carries the ID of the AuthnRequest a response answers. The service provider must compare it against a request ID it generated and is still awaiting, and reject any response whose value it cannot find.

open as a page

In SAML 2.0, what does a service provider give up by accepting unsolicited IdP-initiated responses?

level: middleimportance: should knowfreq 44%

basics

~20 s

An 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.

open as a page

A SAML service provider redirects to whatever RelayState comes back with the response — what is the defect?

level: seniorimportance: should knowfreq 38%

basics

~20 s

RelayState is opaque data echoed back through the browser, not a trusted destination. A service provider that redirects to it unvalidated turns its own assertion-consumer endpoint into an open redirect to any address an attacker supplies.

open as a page

In a SAML AuthnRequest, what do ForceAuthn and IsPassive each ask the identity provider to do?

level: middleimportance: nice to knowfreq 28%

basics

~10 s

ForceAuthn="true" asks the identity provider to authenticate the person afresh instead of relying on an existing session. IsPassive="true" asks it to answer without taking visible control of the user interface.

open as a page