Join our Newsletter — 33% off our NHI Course
Home› Guides› IdP-Initiated vs SP-Initiated SSO: Flow Security Differences
Guide Identity & Access Management (IAM)

IdP-Initiated vs SP-Initiated SSO: Flow Security Differences

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 14 November 2026 17 min read
On this page

Who starts a single sign-on flow decides which attacks the application can stop, yet most estates still accept logins that nobody at the application ever asked for. In SP-initiated SSO the application (service provider or relying party) creates a request, remembers it, and only accepts an answer that matches. In IdP-initiated SSO the identity provider pushes a response to the application unprompted, so the application has nothing to match it against. This guide compares the two flows across SAML 2.0 and OpenID Connect: the threat model of each, replay and login CSRF exposure, RelayState and target link handling, OIDC third-party initiated login, when to switch IdP-initiated off and how to do it without breaking portal users. It is written for IAM engineers, application owners and security architects. SAML message structure and validation basics are covered in the SAML Security Guide and are not repeated here.

Key takeaways

  • The difference is request correlation. SP-initiated responses carry an InResponseTo (SAML) or state and nonce (OIDC) that the application checks against what it sent; an unsolicited SAML response by definition carries none.
  • IdP-initiated SAML removes login CSRF protection. OWASP describes unsolicited responses as "inherently less secure by design due to the lack of login CSRF protection", and NIST SP 800-63C-4 says the transaction SHALL be initiated by the RP at FAL2.
  • OIDC has no unsolicited ID token. Its equivalent, third-party initiated login, only asks the RP to start its own authentication request, so state, nonce and PKCE stay in force; the risk moves to the initiation endpoint and target_link_uri.
  • RelayState and target_link_uri are redirect inputs. Validate them against an allowlist of the application's own paths, keep them short and free of sensitive state, or they become open redirects.
  • You can keep portal tiles and drop unsolicited responses. Point the portal tile at the application's login URL so the click starts an SP-initiated flow, then disable unsolicited acceptance at the SP.

How the two flows differ

  • SP-initiated SAML: the user opens the application, the SP builds an AuthnRequest with a unique ID, stores that ID in the user's pre-login session and redirects the browser to the IdP. The IdP authenticates the user and POSTs a response whose InResponseTo equals the request ID. OWASP notes that InResponseTo "helps guarantee authenticity of the response from the trusted IdP".
  • IdP-initiated SAML: the user starts at the IdP portal and clicks an application tile. The SAML 2.0 Profiles specification (section 4.1.5) says an IdP "MAY initiate this profile by delivering an unsolicited <Response> message" and that such a response "MUST NOT contain an InResponseTo attribute". The SP has no pre-login session and no request to compare.
  • SP-initiated OIDC: the RP sends an authorisation request with state (bound to a browser cookie for CSRF protection), nonce (OIDC Core: "to mitigate replay attacks") and, under current best practice, PKCE. The RP checks all three when the code comes back.
  • Third-party initiated OIDC: OIDC Core section 4 lets an OP or another party send the user to the RP's registered initiate_login_uri with iss (required), login_hint and target_link_uri (both optional). The RP then sends a normal authentication request to that issuer. The final response is still solicited.

The practical consequence: in SAML, "IdP-initiated" changes what the SP must accept. In OIDC, "third-party initiated" only changes how the flow is kicked off. For a protocol-level comparison see the SAML vs OIDC Guide.

Side-by-side comparison

PropertySP-initiated SAMLIdP-initiated SAMLOIDC (RP-initiated or third-party initiated)
Who starts the flowApplicationIdP portal or a link to the IdPRP, or a third party calling initiate_login_uri, which makes the RP start
Request correlationInResponseTo matches stored AuthnRequest IDNone; InResponseTo must be absentstate, nonce and PKCE code_verifier
Login CSRF protectionYes, via pre-login session and InResponseToNo built-in protectionYes; RFC 9700 accepts state, PKCE or nonce as CSRF protection
Replay defenceCorrelation plus assertion ID cache until NotOnOrAfterAssertion ID cache only; no correlationSingle-use code, nonce check, short exp
Response injectionUnexpected responses rejectedAny validly signed, in-window response for the SP is acceptedCode is only redeemed by the client that holds the PKCE verifier
Post-login landingSP stores the target itselfRelayState from the IdP (if agreed), untrustedRP stores the target; target_link_uri from initiator is untrusted
Fit with NIST SP 800-63C-4Meets "initiated by the RP"FAL1 only ("SHOULD be initiated by the RP")Meets "initiated by the RP"

Threat model: SP-initiated SSO

SP-initiated SSO is the stronger default, but it is not risk-free. Its protections hold only if the SP actually checks them, and many SAML libraries make InResponseTo validation optional or silently skip it when the session is missing.

  • Main threats: stolen assertions replayed within their validity window, assertions minted for another SP (cross-SP replay), forged responses after IdP signing key theft (MITRE ATT&CK T1606.002 SAML Tokens), and session cookie theft after login (T1539 Steal Web Session Cookie). Request correlation does nothing against a forged response that the attacker injects into a legitimate pending flow, which is why Destination, Audience and signature checks remain essential.
  • Failure modes: the SP stores the AuthnRequest ID in a cookie that is lost when the browser blocks third-party cookies or when the user has two tabs open, and the developer "fixes" the resulting errors by turning correlation off; the SP accepts a response with no InResponseTo when one was expected (this quietly turns every SP-initiated integration into an IdP-initiated one); the return URL stored before login is taken from a query parameter without validation.
  • Controls: store the pending request ID server-side keyed to a SameSite pre-login cookie; reject any response whose InResponseTo is missing or unknown; keep an assertion ID cache until NotOnOrAfter, as SAML Profiles section 4.1.4.5 requires ("The service provider MUST ensure that bearer assertions are not replayed"); validate Destination and Recipient against the ACS URL; sign AuthnRequests where the IdP supports it so the IdP can reject requests for unregistered ACS URLs.

Threat model: IdP-initiated SSO

The SP receives a signed response it did not ask for. It can verify that the IdP issued it and that it is for this SP and still in date, but not that this browser, at this moment, meant to log in.

  • Login CSRF: an attacker obtains a valid response for an account they control (for example their own low-privilege account at a shared-tenant SaaS application) and causes the victim's browser to POST it to the SP's ACS URL. The victim is silently logged in as the attacker and may upload data or enter credentials into the attacker's account. OWASP explains that the SP "has no opportunity to create a pre-login session or verify that the authentication request was intentionally initiated by the user". MITRE CAPEC-62 Cross Site Request Forgery describes the general pattern; see the CSRF Prevention Guide.
  • Replay and message insertion: without correlation, a captured response (from logs, a proxy, browser history of an auto-submitting form or a compromised endpoint) can be posted again from another browser until NotOnOrAfter, unless the SP enforces an assertion ID cache. OWASP lists replay and message insertion as the attacks the SAML Profiles 4.1.5 validation counters (CAPEC-60 Reusing Session IDs covers the general replay class).
  • RelayState open redirect: with unsolicited responses the IdP chooses the landing page through RelayState. If the SP redirects to whatever RelayState contains, the trusted login domain becomes an open redirect for phishing. See the Open Redirect Guide.
  • Failure modes: no replay cache because developers rely on correlation they do not have; RelayState used to carry tenant or role hints that the SP trusts.
  • Controls if it must stay: OWASP's three considerations: follow the SAML Profiles 4.1.5 validation, allowlist RelayState when it is a URL, and implement replay detection at response or assertion level. Add short NotOnOrAfter windows, OneTimeUse where honoured, and treat unsolicited sign-ins as a separate, monitored category.

OIDC equivalents and third-party initiated login

OpenID Connect has no profile in which the OP sends an unsolicited ID token to the RP's redirect URI. Any response that arrives without a matching state and nonce should be rejected. What OIDC offers instead is third-party initiated login (OIDC Core section 4), which gives portal-style launch without unsolicited responses.

ParameterStatus in OIDC Core section 4Security handling at the RP
issRequired; must use the https schemeAccept only issuers the RP is configured to trust. An unknown issuer must not trigger discovery or dynamic registration from the initiation endpoint. For multi-issuer RPs, also validate the iss authorisation response parameter (RFC 9207) to prevent mix-up.
login_hintOptional; free-form hint for the OPPass through only as a hint. Never use it to choose the local account or skip authentication.
target_link_uriOptional; where the RP is asked to send the user after loginThe spec says RPs "MUST verify the value of the target_link_uri to prevent being used as an open redirector to external sites". Allowlist paths on the RP's own origin.
TransportGET query parameters or auto-submitted POST formApply clickjacking defences (the spec points to frame busting and RFC 6819 section 4.4.1.9); see the Clickjacking Guide.
Unknown parametersExtensions may add parameters; clients ignore what they do not understandDo not let extension parameters alter scopes, prompt or acr_values without a server-side policy check.

Residual risk: anyone can link to initiate_login_uri, so a hostile page can start a login at the user's real OP. Because the user authenticates as themselves and the RP still checks state and nonce, this does not produce the account-swap login CSRF seen with unsolicited SAML. It can still be used for nuisance logins, consent phishing when combined with broad scopes, or redirects if target_link_uri is not validated. RFC 9700 adds two related requirements: clients "MUST prevent Cross-Site Request Forgery", and they "MUST NOT expose URLs that forward the user's browser to arbitrary URIs". Implicit flow responses (response_type containing token or id_token without code) are the closest OIDC gets to unsolicited delivery risk; RFC 9700 says clients SHOULD NOT use the implicit grant. For flow design detail see the OAuth 2.0 and OpenID Connect Guide.

RelayState and replay controls in practice

RelayState is where IdP-initiated deployments most often go wrong, and it matters in SP-initiated SAML too. The SAML 2.0 Bindings specification (sections 3.4.3 and 3.5.3) sets the rules:

  • Size: RelayState "MUST NOT exceed 80 bytes in length". Long URLs in RelayState are non-conformant and are a sign that the SP is round-tripping data it should hold itself.
  • Integrity: it "SHOULD be integrity protected by the entity creating the message"; because signing is impractical at 80 bytes, the specification suggests a checksum or pseudo-random value. In SP-initiated flows the best pattern is an opaque random handle that maps to a server-side record of the return path.
  • Binding to the message: section 3.5.5.2 warns there is no mechanism protecting the relationship between the SAML message and RelayState, so an attacker could swap RelayState between two valid responses. Producers and consumers "MUST take care not to associate sensitive state information" with it.
  • Disclosure: SAML Profiles section 4.1.3.1 says the SP "SHOULD reveal as little of the request as possible in the RelayState value".

Replay controls apply whichever way the flow starts:

ControlWhat to configureAttack it stops
Assertion ID cacheStore each accepted assertion ID until its NotOnOrAfter; reject repeats across all SP nodes (shared cache, not per-node memory)Replay of a captured response
Short validity windowIdP issues assertions valid for minutes, not hours; SP allows small clock skew onlyReplay of old responses from logs or browser history
Destination and Recipient matchReject a response if Destination is missing or differs from this ACS URLCross-SP replay (OWASP: "prevents cross-SP assertion replay")
Audience restrictionAudience equals this SP's entity IDAssertions minted for another application
InResponseTo enforcementRequired for every SP-initiated flow; separate code path for unsolicitedInjection of unsolicited or captured responses
RelayState allowlistExact paths or a fixed set of route names on the SP's own originOpen redirect after login

When to disable IdP-initiated SSO

Disable unsolicited response acceptance at the SP by default, and keep it only with a documented reason, an owner and an expiry date. Use these criteria:

  • Disable now: applications that hold sensitive data or admin functions; any application that must meet FAL2 or above under NIST SP 800-63C-4; multi-tenant SaaS where an attacker can easily obtain their own valid account (the login CSRF payoff is highest here); applications whose SAML library cannot keep a shared replay cache.
  • Convert, then disable: applications launched from an IdP portal or dashboard. Change the tile so it links to the application's own login URL (sometimes called a sign-on URL or bookmark launch). The click then starts SP-initiated SSO and the user still gets one-click access, usually with an invisible extra redirect.
  • Keep with compensating controls: legacy applications that only implement unsolicited responses (OWASP notes support persists "for backward compatibility (notably with SAML 1.1)"), and partner integrations where the partner's SP cannot issue AuthnRequests. Apply replay caching, short windows, RelayState allowlisting, stronger monitoring and a migration date.
  • Small vs large organisations: a small organisation with a handful of SaaS applications can usually switch every tile to SP-initiated in a day using each vendor's documented sign-on URL. A large estate needs an inventory first, because hundreds of custom SPs will have been built with different libraries and some will not handle SP-initiated at all.

Worked scenario: removing unsolicited SAML from a portal estate

A company has 140 SAML applications launched from its IdP portal. An inventory shows 120 accept unsolicited responses. Thirty of those are multi-tenant SaaS products, twelve are internally built on two different SAML libraries, and one partner benefits platform only supports IdP-initiated.

  1. Triage: the SaaS applications are checked against their vendor documentation: 27 publish an SP-initiated login URL and an option to reject unsolicited responses. Their tiles are switched to the login URL in a pilot group, then unsolicited acceptance is turned off at the SP.
  2. Internal applications: one library enforces InResponseTo when it finds a stored request ID but silently accepts responses without one. The team adds a configuration flag that rejects responses lacking InResponseTo, moves the request ID store from in-memory to the shared session store (behind a load balancer the in-memory store caused intermittent failures, which is why correlation had been disabled), and adds an assertion ID cache.
  3. Exceptions: the benefits platform keeps IdP-initiated with a two-minute assertion lifetime, a RelayState allowlist of three paths, a replay cache confirmed by the provider in writing, and a contract clause to support SP-initiated by a fixed date.
  4. Result: unsolicited-capable applications fall from 120 to 4 in a quarter, with no help desk spike, because users kept the same tiles.

Implementation and rollback

  1. Inventory: for each SAML SP and OIDC RP record the initiation modes accepted, whether InResponseTo or state and nonce are enforced, how RelayState or target_link_uri is handled, the library and version, and the owner.
  2. Measure current use: from IdP sign-in logs, split launches by portal versus direct; from SP logs, count responses with and without InResponseTo. Applications with zero unsolicited logins can be switched immediately.
  3. Pilot: change tiles to SP-initiated launch for a pilot ring of users, watch error rates for a week, then extend.
  4. Enforce at the SP: reject unsolicited responses and responses with missing correlation. Changing the IdP tile alone is not enough; an attacker does not use your portal.
  5. Harden what remains: replay cache, short lifetimes, RelayState allowlists, monitored exception list with expiry.
  6. Rollback: keep the previous SP configuration exported and versioned; reverting the tile URL restores the old launch path within minutes. Roll back a single application at a time rather than reverting the policy estate-wide. See IdP configuration backup and restore for Entra ID and Okta.

Detection and measurement

  • Log at the SP: whether each accepted response was solicited, the assertion ID, Issuer, Destination, RelayState value and the result of each check. Alert on replayed assertion IDs, responses with unknown InResponseTo, and RelayState values outside the allowlist.
  • Correlate with the IdP: every SP sign-in should match an IdP issuance event for the same user and application. Unmatched SP sign-ins can indicate forged responses; see the Golden SAML and Federation Trust Abuse Defence Guide.
  • Metrics: share of SAML SPs that reject unsolicited responses (target above 95 percent); count of approved IdP-initiated exceptions past their expiry date (target zero); share of SPs with a shared replay cache verified by test; replayed or uncorrelated responses rejected per month (non-zero is useful signal, investigate each); OIDC RPs with target_link_uri and redirect validation verified by test.

Common failure patterns

  • Changing the tile but not the SP: users now launch SP-initiated, but the SP still accepts unsolicited responses, so the attack surface is unchanged.
  • Correlation disabled to fix intermittent errors: request IDs held in per-node memory or third-party cookies fail behind load balancers or in modern browsers; the fix is a shared server-side store, not switching checks off.
  • RelayState used as a full URL with no validation: the login endpoint becomes an open redirect on a domain users trust.
  • Replay cache only in memory per node: a captured response posted to a different node is accepted.
  • Treating OIDC third-party login as unsolicited: developers add code paths that accept an ID token without state or nonce "for portal launches", recreating the SAML weakness in OIDC.

Framework mapping

FrameworkReferenceRelevance to initiation choice
NIST SP 800-63C-4FAL1, FAL2, FAL3FAL1: transaction SHOULD be initiated by the RP; FAL2: SHALL be initiated by the RP and assertions strongly protected from injection; replay protection required per RP. See the NIST SP 800-63C-4 Federation Assurance Levels Guide.
NIST SP 800-53 Rev. 5IA-8, IA-8(4), SC-23, SI-10Authenticating non-organisational users through defined federation profiles; session authenticity against CSRF and replay; validating RelayState and target_link_uri input
NIST CSF 2.0PR.AA-03Users, services and hardware are authenticated
MITRE ATT&CKT1606.002, T1539, T1550.004Forged SAML tokens; theft and reuse of post-login session cookies
MITRE CAPECCAPEC-62, CAPEC-60Login CSRF; replay of captured session material
IETFRFC 9700, RFC 9207OAuth CSRF, redirect and mix-up requirements for OIDC RPs

Practitioner checklist

  • Record the accepted initiation modes for every SAML SP and OIDC RP, with owner and library version.
  • Switch portal tiles to the application's own login URL so clicks start SP-initiated flows.
  • Configure every SP to reject unsolicited responses and responses with missing or unknown InResponseTo, unless an approved exception exists.
  • Store pending request IDs and the post-login return path server-side, shared across nodes.
  • Run a shared assertion ID replay cache until NotOnOrAfter and keep assertion lifetimes short.
  • Allowlist RelayState and target_link_uri to the application's own paths; keep RelayState under 80 bytes and opaque.
  • For OIDC, require state, nonce and PKCE on every flow, including those started via initiate_login_uri, and validate iss against trusted issuers.
  • Give each IdP-initiated exception a reason, compensating controls and an expiry date, and report the count monthly.

Standards and references

Related NHI Mgmt Group resources: SAML Security Guide · SAML vs OIDC Guide · SAML to OIDC Migration · Identity Provider and SSO Security Guide · Open Redirect Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 14 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org