In SP-initiated SSO the user starts at your application, which sends them to their company’s identity provider to sign in. In IdP-initiated SSO the user starts at the identity provider (typically a portal of app tiles in Okta or Microsoft Entra ID), and the IdP sends a signed assertion to your application without your app having asked for one. SP-initiated is the safer and more common default for SaaS, and IdP-initiated is mostly a SAML expectation that enterprise customers raise because they like having a tile on their portal.
If a customer’s IT team has asked you to “add a tile in our IdP portal”, this post explains what that request means, what it costs you in security, and how to give them the experience they want without accepting the riskiest version of it.
What is SP-initiated SSO?
In an SP-initiated flow, the service provider (your application) begins the sign-in. A user opens your app or follows a bookmark, your app notices they have no session, and it redirects them to their identity provider. With SAML that redirect carries an authentication request, and the IdP later returns an assertion that refers back to it. With OpenID Connect it is a standard authorization request, and the response is tied to the state and nonce values your app generated.
Because your app created the request, it can check that the response answers that request and not some other one. That is the property that makes the flow robust, and it is why SP-initiated login works the same way across SAML and OIDC. Our SSO implementation guide shows the flow end to end.
What is IdP-initiated SSO?
In an IdP-initiated flow, the user starts at the identity provider. They sign in to the company portal, click your app’s tile, and the IdP posts a SAML assertion straight to your application’s assertion consumer service, the endpoint that receives SAML responses. Your app never sent a request, so the assertion has nothing to refer back to.
The OASIS SAML 2.0 specification supports this as an “unsolicited response” in its Web Browser SSO profile, which covers it in section 4.1.5 (Unsolicited Responses). OpenID Connect has no direct equivalent of an unsolicited response, but OpenID Connect Core 1.0, section 4 defines “initiating login from a third party”: the IdP or portal sends the user to a login initiation endpoint on your app (the request carries the issuer, iss), and your app then starts a normal SP-initiated flow. Your app should validate any target_link_uri it receives, so the endpoint cannot be used as an open redirect.
What are the security tradeoffs?
The core problem with accepting unsolicited SAML responses is that your application has no way to confirm the user wanted to sign in to it. Without a request to match against, it cannot tell a genuine tile click from a response an attacker obtained or replayed, or from one delivered to a victim’s browser by a malicious page, a form of login cross-site request forgery (CSRF).
If a customer insists on IdP-initiated SAML, you can reduce the risk with these checks, all of which are part of normal SAML validation but matter more here:
- Require a signed assertion, verified against the customer’s registered certificate (the Web Browser SSO profile requires assertions delivered over the POST binding to be signed), and verify the signature on the response as well when one is present.
- Reject an unsolicited response that carries an
InResponseTovalue, because the profile says unsolicited responses must not contain one. - Check the
AudienceandRecipientvalues so an assertion meant for another application is rejected. - Enforce a short validity window and track assertion IDs to reject replays.
- Accept the flow only from the specific customer connections that need it, and not as a global default.
- Do not trust a
RelayStatevalue that arrives unsolicited as a redirect target without validating it.
Even with those checks, the safer design is to avoid accepting unsolicited assertions at all, which leads to the next section.
What do you tell a customer who asks for a tile?
You can usually give them the tile without the risky flow. There are two common patterns:
- A tile that is just a link. Most IdP portals support a bookmark-style app: clicking the tile opens your app’s SP-initiated login URL, ideally with a parameter that names the customer’s connection (an organization slug, or
kc_idp_hint=<alias>in Keycloak, described in choosing an identity provider with kc_idp_hint) so the user lands at the right IdP without a chooser. The user experience is the same, one click from the portal, and your app still creates the request. - Third-party initiated login with OIDC. The tile opens a login initiation endpoint on your app that immediately starts a normal SP-initiated OIDC flow. This is the pattern the OpenID Connect specification describes for exactly this need.
Accept real IdP-initiated SAML only when a customer’s tooling cannot do either, and then enable it per connection with the checks above.
Which flow do enterprise customers actually use?
Both, and the split follows what their IdP and procurement checklist emphasise. Day-to-day, most sign-ins to a SaaS product are SP-initiated, because people open the app directly or follow a link from an email or a bookmark. IdP-initiated usage tends to come from portal-first companies, where employees are trained to launch everything from a single dashboard, and it shows up on security questionnaires as a feature checkbox. We have not seen a reliable public statistic on the exact split, so treat any specific percentage you read with caution.
The most useful position for a B2B product is to support SP-initiated as the default for both SAML and OIDC, offer a portal tile that deep-links into it, and treat true IdP-initiated SAML as an opt-in exception.
How does this relate to domain routing and your own IdP?
SP-initiated login raises a follow-up question: how does your app know which customer’s IdP to send a user to? Usually by asking for an email address and routing on its domain, which is a separate topic from the flow direction itself. Whichever way the user arrives, it helps to have one identity provider of your own that your applications trust, with each customer’s IdP connected to it as an upstream source. That way the flow choices above are configured once at the hub, not in every application, which is the idea behind enterprise SSO that survives IdP changes. For the protocol background, see SAML vs OIDC, and for the role definitions see SP vs IdP.
Skycloak delivers this hub pattern through managed Keycloak, so you can keep your applications on one issuer and decide per application and per connection whether to accept IdP-initiated SAML.
Frequently asked questions
Which flow should a SaaS product use by default?
SP-initiated, because your application creates the request and can match the response to it. Offer IdP-initiated SAML only as an opt-in exception for customers whose tooling requires it.
Is IdP-initiated SSO secure?
It can be made reasonably safe with strict signature, audience, recipient and replay checks, but it is weaker than SP-initiated SSO because your application cannot tie the response to a request it made. Many security teams prefer to avoid it where an alternative exists.
Does OpenID Connect support IdP-initiated SSO?
Not as an unsolicited token response. OpenID Connect defines third-party initiated login, where a portal sends the user to your app’s login initiation endpoint and your app starts a normal authorization code flow.
Why do enterprise customers ask for IdP-initiated SSO?
Mostly for convenience and habit: employees launch applications from a portal of tiles. A tile that deep-links to your SP-initiated login gives the same experience.
Can I support both flows?
Yes. A common approach is SP-initiated by default, with IdP-initiated SAML enabled only on the customer connections that require it.
What is the SAML assertion consumer service?
It is the endpoint on the service provider that receives SAML responses from the identity provider. In an IdP-initiated flow the identity provider posts an unsolicited assertion directly to it.