How to Threat Model an SSO / Identity Provider Integration

Adding single sign-on feels like handing authentication to someone better at it. The identity provider stores the passwords, enforces MFA, detects suspicious logins and disables people when they leave. Your application just receives a message saying "this is alice@customer.com" and lets her in.

That last step is the problem. SSO moves the login to the identity provider, but the decision to believe it stays in your code. Every SSO integration adds a handful of new code paths that answer the most sensitive question your application asks: who is this? If any of them answers wrongly, an attacker can sign in as anyone without going anywhere near the identity provider.

The short version: draw the browser, your application and each identity provider as separate trust zones, and treat the login response as untrusted input because it travels through the browser. Then model the four places SSO integrations really fail: validating the response, linking it to an account, deciding which identity provider is allowed to speak for which users, and what happens to sessions after access is revoked.

What the identity provider does, and what it doesn't

Before anything else, write down where the line sits. Teams tend to assume the identity provider covers more than it does, because "we use SSO" sounds like a complete answer in a security questionnaire.

The identity provider's jobStill entirely yours
Checking the user's password and MFAVerifying that the response really came from that identity provider, for your application, just now
Telling you who the user isDeciding which local account that identity maps to
Stopping new logins for disabled usersEnding the sessions, refresh tokens and API keys your application already issued
Its own availability and securityWhat your application does when the identity provider is down, or compromised
Group and role information, if configuredWhat those groups are allowed to do inside your application

Most real SSO vulnerabilities live in the right-hand column. The identity provider did its job perfectly; the application believed something it shouldn't have.

Draw the login as the flows it really is

On most architecture diagrams, SSO is a single arrow from "App" to "Okta" or "Entra ID" labelled auth. That arrow hides exactly the detail a threat model needs. In a data flow diagram, draw three elements and the flows between them:

  • The user's browser, as an external entity outside every trust boundary. The attacker controls a browser too.
  • Your application (the service provider in SAML, the relying party in OpenID Connect).
  • Each identity provider, as an external entity in its own trust zone. In a B2B product that is often dozens of them, one per customer.

Then draw the login itself. The application redirects the browser to the identity provider. The identity provider sends a response back through the browser: a signed SAML assertion posted to your callback, or an authorization code in a redirect URL. With OpenID Connect's authorization code flow there is one more flow, a direct server-to-server call where your application exchanges the code for tokens.

The flows that pass through the browser are the ones to stare at. They cross from an untrusted zone into your application carrying the claim "this is who the user is." Anything on them can be replayed, modified, swapped or forged, and the only thing standing between that and an account takeover is the validation code in your callback handler.

Validating the response: where SAML and OIDC break

SAML and OpenID Connect fail in different ways, but the underlying threat is the same: the application accepts a login response it should have rejected.

SAML is XML with digital signatures, and the history of SAML vulnerabilities is largely a history of applications checking a signature and then reading data the signature didn't cover. Signature wrapping attacks move the signed assertion somewhere harmless and insert an unsigned, forged one where the application looks for it. Comment-injection bugs disclosed across several SAML libraries in 2018 let an attacker register user@victim.com<!---->.evil.com and have some parsers read only the part before the comment. In 2024, a signature-bypass flaw in the widely used ruby-saml library (CVE-2024-45409) affected, among others, GitLab's SAML login. The questions to ask:

  • Is an unsigned response or assertion ever accepted, even in a "test" configuration?
  • Does the code read the user's identity from exactly the element the signature covers?
  • Are audience, recipient, destination and expiry checked, so an assertion issued for another application, or last week, is rejected?
  • Is each assertion ID accepted only once, and does an unsolicited (IdP-initiated) login get treated with more suspicion than one your application asked for?
  • Is the SAML library one you keep up to date, rather than hand-rolled XML parsing?

OpenID Connect builds on OAuth 2.0 and uses JSON tokens, which avoids XML's problems but brings its own. The current guidance is collected in the OAuth 2.0 Security Best Current Practice (RFC 9700), and most of it maps directly onto threat model questions:

  • Is the ID token's signature verified with the identity provider's published keys, and are unexpected algorithms (including none) rejected?
  • Are issuer, audience, expiry and nonce all checked, not just decoded?
  • Is the state parameter tied to the user's browser session, so an attacker can't log a victim into the attacker's account (login CSRF)?
  • Are redirect URIs registered and matched exactly, with no wildcards an attacker could satisfy?
  • Is PKCE used, and is the deprecated implicit flow, which puts tokens directly in the URL, avoided?

Account linking: the email claim is not an identity

Once the response is valid, the application has to decide which local account it belongs to. This is where many integrations that validate tokens perfectly still fall over.

The tempting implementation is to look up the user by email address. But an email claim says what address the identity provider has on file, not that the person controls it. In 2023, researchers described a pattern they called nOAuth: some multi-tenant applications using Microsoft's identity platform matched users on the email claim, which in that setup could be set by the administrator of any directory, including one the attacker created. Setting it to a victim's address was enough to sign in as the victim.

The safer rule is simple to state: identify an SSO user by the identity provider's issuer plus its stable, unique subject identifier, never by email or display name alone. The risky moments are the ones that create links between identities:

  • Auto-linking. An existing password account is silently attached to whichever SSO identity arrives with the same email. Whoever controls that claim now owns the account.
  • Just-in-time provisioning. A first SSO login creates an account automatically. Which tenant does it join, and with what role? If the answer comes from the email domain, who verified that the tenant owns the domain?
  • Role and group mapping. If groups from the identity provider become admin rights in your application, then whoever administers the customer's directory administers your application too. That's often intended. Write it down so it's a decision rather than a surprise.

Multi-tenant SSO: which identity provider speaks for whom

In a B2B product, each customer usually connects its own identity provider. That turns one integration into many, and introduces a threat that single-tenant diagrams never show: one customer's identity provider asserting identities that belong to another customer.

An identity provider will sign whatever its administrator configures. If Tenant A's identity provider sends a perfectly valid assertion for ceo@tenant-b.com, the signature checks out. The only defence is your application binding each SSO connection to a tenant, and accepting from that connection only the identities that belong to that tenant. It's the identity-layer version of the cross-tenant question in our multi-tenant SaaS guide, and it deserves the same scrutiny.

The SSO configuration screen belongs on the diagram for the same reason. Whoever can change a tenant's identity provider URL or signing certificate can redirect every login for that tenant to infrastructure they control. Treat it like a password-reset flow for the whole organisation: restrict it, require re-authentication, log every change and notify the other admins.

Sessions that outlive access

SSO is usually sold on offboarding: disable someone in the identity provider and they lose access everywhere. In practice, disabling them stops new logins. Everything your application issued after the last one lives on:

  • A session cookie valid for 30 days.
  • A mobile app refresh token that never expires.
  • Personal API keys created while the user still had access.
  • A password login that still works because SSO was added later and never enforced.

Each is a way back in after the identity provider says no. The last one also undoes MFA, because the identity provider was the thing enforcing it. The controls are well known: enforce SSO per tenant once it's configured, keep sessions short or re-check with the identity provider periodically, act on SCIM or webhook deprovisioning events, and revoke application-issued tokens when an account is disabled. Single logout protocols exist but are unreliable in practice, so don't let the model depend on them. A deliberate, audited break-glass account for when the identity provider is down is fine; an accidental one is a backdoor.

When the identity provider itself is the threat

Finally, the identity provider is an external entity, and external entities can be compromised. In 2023, attackers who got into Okta's customer support system took session tokens from troubleshooting files customers had uploaded. Several customers, including security companies, detected the follow-on activity themselves.

You can't prevent that from inside your application, but you can decide how much a stolen identity provider session is worth. Step-up authentication for sensitive actions, alerts on unusual admin activity, and a short session lifetime all limit the damage. For the wider question of how much to trust a vendor that sits this close to everything, see our guide to threat modeling third-party vendor integrations.

The STRIDE sweep for an SSO integration

With the browser, the identity providers and the callback on the diagram, run STRIDE across the login flows and the account and session logic behind them:

CategoryThe SSO version of the question
SpoofingCan a forged, unsigned, wrapped or replayed response be accepted? Is the user identified by issuer and subject, or by an email claim someone else can set? Can one tenant's identity provider assert another tenant's users?
TamperingWho can change a tenant's SSO configuration or signing certificate? Can redirect URIs or the relay state be manipulated to send codes or users somewhere else?
RepudiationAre SSO logins logged with the identity provider, issuer and subject, not just an email? Are SSO configuration changes logged and attributable to a person?
Information disclosureDo tokens or assertions end up in URLs, logs or analytics? Do login error messages reveal which tenants exist or which emails have accounts?
Denial of serviceWhat happens when a customer's identity provider is down? Is there an audited break-glass path, or does everyone, including your support team, get locked out?
Elevation of privilegeDo identity provider groups map to admin rights? Does just-in-time provisioning assign a role or tenant from attacker-influenced claims? Can a password login bypass the MFA the identity provider enforces?

Modeling it as an attack tree

An attack tree shows how many separate paths lead to the same outcome. Put "sign in as an admin of another customer's tenant" at the root. Branches might include: forge or replay a SAML assertion the application fails to validate; configure your own tenant's identity provider to assert the victim's email; register a directory account with the victim's email and rely on email-based linking; use a password login that predates SSO enforcement; reuse a session or API key from an admin who has since left; or change the victim tenant's SSO settings through a compromised admin account.

Each of those has a different control, and most are cheap: a well-maintained library, issuer-and-subject identity, connection-to-tenant binding, SSO enforcement, token revocation on deprovisioning, re-authentication on configuration changes. The tree makes it obvious when one branch has been left wide open while effort went into the others.

Common mistakes

  • Drawing SSO as one arrow. The browser-carried response is the most attacker-controllable flow in the login and disappears entirely from a one-arrow diagram.
  • Treating "we use an identity provider" as the control. The identity provider authenticates the user. Your callback decides whether to believe it.
  • Matching on email. It's mutable, sometimes unverified, and sometimes set by someone other than the user.
  • Leaving password login on after SSO goes live. It quietly bypasses MFA and offboarding for every user who still has a password.
  • Modeling the first identity provider only. The second protocol, the second customer's identity provider or the new "Sign in with" button each change the model. Add them to your re-threat-modeling triggers.

SSO is one of the best security investments a product can make, and nothing here argues against it. It argues for modeling it honestly: as an external party making claims through an untrusted channel, followed by a series of decisions your application makes on its own. Put those decisions on the diagram and most SSO vulnerabilities become easy to spot in review.

Customer-managed SSO is a standard requirement in B2B SaaS, and identity assurance matters most where accounts reach money or health records; see threat modeling for fintech and healthcare. To start from a pre-labelled diagram, see the free data flow diagram template.

Put the whole login on the diagram

Model the browser, your application and every customer's identity provider in ThreatTree, draw the trust boundaries between them, sweep each login flow with STRIDE, and build the attack tree under "sign in as another tenant's admin" — so the branch nobody closed is the first thing you see.

Get started free

Not ready to sign up? Get new threat-modeling guides by email instead.