OpenID Connect vs SAML, which one do you build when a customer asks for SSO? Usually OpenID Connect (OIDC) first, and SAML as well once a customer’s contract or identity provider requires it. Microsoft’s decision guide for Entra ID tells new SaaS the same: if unsure, default to OpenID Connect. OpenID Connect is JSON tokens on top of OAuth 2.0; SAML 2.0 is signed XML.

What we are comparing, and for whom: SAML vs OIDC vs OAuth and one customer request

SAML, OIDC and OAuth are three standards doing two jobs. SAML 2.0 and OpenID Connect prove who the user is, which is what single sign-on needs. OAuth 2.0 grants an app access to an API on a user’s behalf. OpenID Connect is the identity layer built on top of OAuth 2.0.

Single sign-on is one part of your login surface, and the whole surface, from passwords to sessions, is laid out in the authentication checklist. This page covers the part that starts when a customer’s IT team wants their staff to sign in with the company account.

In that exchange your app is the service provider, in SAML’s terms, or the relying party, in OpenID Connect’s. The customer’s directory (Okta, Microsoft Entra ID, Google Workspace and the like) is the identity provider. OpenID Connect and SAML are the two standards that answer the customer’s request; OAuth sits underneath OpenID Connect.

StandardWhat it doesData formatWho maintains itWhat it is for
SAML 2.0Passes signed statements about a user from the identity provider to your appXMLOASIS Security Services Technical Committee; core specification dated March 2005Browser single sign-on into web apps (the Web Browser SSO profile)
OpenID ConnectAdds an identity layer to OAuth 2.0 so your app can verify who signed inJSON; the ID token is a JWTOpenID Foundation; published in early 2014, Core 1.0 with errata set 2 dated December 15, 2023Sign-in for web, mobile and JavaScript clients
OAuth 2.0Lets an app obtain limited access to an HTTP service, on a user’s behalf or its ownNo fixed token formatIETF, RFC 6749, October 2012Granting API access, not proving who is present

The sources are OpenID Connect Core, the OASIS SAML 2.0 technical overview and RFC 6749. Two more names come up in the same conversations: Kerberos, covered with the mix-ups below, and SCIM, which provisions users rather than signing them in and appears in the JIT section.

What the customer means by the request, what SSO costs and what it changes for people already signed in are covered in a customer asked you to add SSO to your SaaS, and where the request sits among a buyer’s other demands is in the login line on a first enterprise customer’s requirements list. Every protocol behavior below is taken from the specifications and the identity providers’ own documentation, not from an integration built for this page.

OpenID Connect vs SAML: what differs when your app is the one being logged into

OpenID Connect vs SAML comes down to format and delivery. OpenID Connect sends a signed JSON token that your server fetches, with keys published for automatic rotation. SAML 2.0 posts signed XML through the browser, checked against a certificate someone must replace before it expires. Build OpenID Connect first unless a customer names SAML.

The table below is written from your app’s side of the login: what it receives, checks and stores for OIDC and SAML 2.0.

From your app’s sideOpenID ConnectSAML 2.0
What arrivesAn ID token: a JSON Web Token signed by the providerA signed XML assertion inside a SAML response
How it arrivesYour server receives it directly from the provider’s token endpointThe browser posts it to your assertion consumer service (ACS) URL
What you validateIssuer, audience (your client ID), expiry, the nonce if you sent one, and the signature with the provider’s keys (a code-flow client may rely on the direct TLS connection instead)Signature against the certificate you stored, issuer, audience, destination and recipient, time window, InResponseTo, no reuse
What you configure per customerIssuer, client ID, client secretProvider entity ID, SSO URL, signing certificate, attribute mapping
Key rotationKeys come from the provider’s published key set (jwks_uri); an unfamiliar key ID sends your app back to fetch itYour side updates the stored certificate when the provider rotates it; Entra ID’s default certificate lasts three years
Single-page and mobile appsListed under “Choose OpenID Connect (OIDC) if you” in Microsoft’s guide”Challenging” in Microsoft’s comparison table
Who asks for itCustomers with modern identity systemsEnterprise customers that require SAML, legacy providers that lack OIDC, procurement rules that mandate it
ProvisioningAccount creation at first sign-in (JIT) is your code; SCIM is a separate protocolSame: JIT is your code, SCIM is separate

Okta, Microsoft Entra ID and Google each document both. Okta’s app integration wizard offers “OIDC - OpenID Connect” and “SAML 2.0” as sign-in methods, Microsoft’s guide says Entra ID “fully supports both protocols”, and Google Workspace acts as a SAML identity provider for custom apps while Google’s own sign-in conforms to the OpenID Connect specification. Among SAML alternatives for a B2B login, OpenID Connect is therefore the one all three already speak.

The rule comes from Microsoft’s decision guide for SAML and OpenID Connect, in close to its words: OIDC suits new, cloud-native SaaS and customers with modern identity; SAML is a requirement-driven choice for enterprise customers, compliance or procurement mandates, or legacy identity providers that support only SAML; support both when your customer base spans both; and when unsure, default to OIDC for new SaaS (the exact sentence is in the FAQ). On which is more secure, the guide’s answer is that both protocols are secure; in my reading, the difference is how much checking your own code has to get right, and SAML asks for more of it.

My addition to the rule: if the auth provider under your app already offers SAML, turn it on rather than write it. Supabase Auth, for one, supports SAML 2.0 single sign-on for any identity provider compatible with the protocol; it is disabled by default, is set up with the Supabase CLI, and Supabase Auth’s SAML SSO page lists the plans that include it. Checking the ID token as a JWT, including its signature and expiry, is a subject of its own: JWT security.

OpenID vs OAuth: why OAuth on its own is not a login

OpenID vs OAuth is identity against access. OAuth 2.0 issues an access token that says what the bearer may call on an API, not who is sitting at the keyboard. OpenID Connect adds what a login needs: an ID token with standard claims about the user.

oauth.net’s note on OAuth and authentication puts it in one line: “OAuth 2.0 is not an authentication protocol.” The access token is addressed to the API, not to your app: the client “is the authorized presenter of that token, and the audience is in fact the protected resource”, and the token “will generally be usable long after the user is no longer present.”

OpenID Connect closes that gap on top of OAuth 2.0. It adds the ID token addressed to your app, required claims for the issuer, the subject, the audience, the expiry and the issue time, a userinfo endpoint that returns more claims about the signed-in user, and discovery, so your app can look up a provider’s endpoints from its issuer. When you compare OAuth vs OpenID Connect this way, the answer to “which one” is usually both: OpenID Connect runs over an OAuth flow, and in the authorization code flow it returns the ID token alongside an OAuth access token.

The difference between SAML and OAuth is the same split: SAML 2.0 signs a user in, OAuth 2.0 grants API access, so asking which is better has no general answer. In my reading, one app can use SAML for staff sign-in and OAuth for its public API at the same time.

“Sign in with Google” is OpenID Connect: Google’s documentation says its OAuth 2.0 implementation for authentication “conforms to the OpenID Connect specification, and is OpenID Certified.” Whether that button is what your customer meant by SSO is a question the SSO request article answers. OAuth for machine clients, API keys and service tokens is at API authentication best practices.

Kerberos vs OAuth, and OAuth vs Okta: two category mix-ups

Kerberos vs OAuth compares two protocols that rarely meet: Kerberos issues tickets that prove identity on a network, while OAuth grants API access across the internet. A SaaS does not implement Kerberos for its customers. OAuth vs Okta compares a standard with a vendor whose product speaks OAuth, OpenID Connect and SAML.

RFC 4120 describes Kerberos as a way of “verifying the identities of principals” on “an open (unprotected) network”, working as “a trusted third-party authentication service” that issues tickets. In my reading it stays inside the customer’s own network; when their directory signs staff into your app, it speaks SAML or OpenID Connect outward, so Kerberos is not on your build list.

Okta, for its part, is a company. Its developer docs call OAuth 2.0 and OpenID Connect “industry standard protocols for user authentication and authorization” and say Okta’s identity solutions are based on them, and its wizard also creates SAML 2.0 integrations.

How SAML works: the protocol, the request, the assertion and the checks

SAML is the half of this comparison a JavaScript developer is least likely to have met, and in my reading it is where most of the build effort goes. The five parts below follow the order the messages travel: the flow, the request and response, the assertion, the metadata that sets it all up, and the checks your side must make.

The SAML protocol and the SAML authentication flow, step by step

The SAML protocol moves a signed statement about a user between three parties: the browser, your app and the customer’s identity provider. Your app sends the browser to the provider with a request, the user signs in there, and the browser posts the signed response back to your app. The two servers need not connect directly.

SAML is an OASIS standard built from assertions, protocols, bindings and profiles. The way SAML is used by a SaaS is the Web Browser SSO profile, and the protocol messages inside it are the request and the response described in the next part. On the networking side there is nothing special: in the redirect and POST bindings the browser carries every SAML message, so the only SAML servers are two HTTPS endpoints, the provider’s sign-on URL and your assertion consumer service. In my reading, that means no VPN and no firewall rule between your servers and the customer’s.

The SAML workflow for a login that starts at your app, from the specification’s own walk-through:

  1. 01 The user opens your app without a session, and your app remembers the page they wanted
  2. 02 Your app redirects the browser to the identity provider sign-on URL with a SAMLRequest
  3. 03 The identity provider checks for its own session and asks the user to sign in if there is none
  4. 04 The identity provider builds a signed assertion, wraps it in a SAML response, and returns a form that posts itself
  5. 05 The browser posts the SAMLResponse to your assertion consumer service URL
  6. 06 Your app validates the signature and the conditions, creates its own session, and sends the user to the saved page

A SAML authentication example: a person at a customer that uses Okta opens your login page and types their work email. Your app looks up that customer’s connection, sends the browser to Okta with a request, the person signs in at Okta, and the browser posts the response to your ACS URL, where your app checks it and lands them in that customer’s workspace. Okta’s own guidance is that your app only asks for an identifier at this point, never a password.

Login can also start at the provider. The user clicks your app’s tile in their dashboard, and the provider posts an assertion nobody asked for; there is no request, so the first two steps above never happen. OWASP’s SAML Security Cheat Sheet calls this unsolicited response “inherently less secure by design due to the lack of login CSRF protection”, and lists not allowing it as a best practice, though not required; if you allow it, validate any RelayState URL against an allowlist and detect replays.

The SAML request and the SAML response

A SAML request is a short XML message from your app asking the identity provider to authenticate a user; it carries an ID, a timestamp and your app’s entity ID as issuer. A SAML response is the provider’s XML reply, posted to your assertion consumer service URL, with a status, the request ID it answers, and the signed assertion.

The request (AuthnRequest) goes out by redirect, as a SAMLRequest query parameter compressed with DEFLATE, or by POST. The specification’s example request also carries an AssertionConsumerServiceIndex attribute for your assertion consumer service. Signing it is optional unless the provider insists; Microsoft Entra ID, for example, “can be configured to enforce the requirement of signed authentication requests.”

The response (Response) is sent back by POST, base64-encoded in a hidden form field named SAMLResponse. It carries a Status, a Destination, an InResponseTo that must equal your request’s ID, and the assertion. The signature can sit on the response, on the assertion or on both: OWASP’s rule for your side is to “Ensure each Assertion or the entire Response element is signed”, and Google Workspace, by default, signs only the assertion unless the admin ticks “Signed response”.

The skeleton below keeps the element names as the specification spells them and drops every real value:

<!-- Request: your app to the identity provider -->
<samlp:AuthnRequest ID="..." Version="2.0" IssueInstant="..." AssertionConsumerServiceIndex="...">
  <saml:Issuer>your-app-entity-id</saml:Issuer>
  <samlp:NameIDPolicy Format="..." />
</samlp:AuthnRequest>

<!-- Response: the identity provider to your ACS URL -->
<samlp:Response ID="..." InResponseTo="(your request ID)" Destination="(your ACS URL)">
  <saml:Issuer>provider-entity-id</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
  </samlp:Status>
  <saml:Assertion ID="..."> signed; see the next section </saml:Assertion>
</samlp:Response>

To read one while debugging, base64-decode it, and for the redirect binding also inflate it. My working rule is to decode on your own machine, never in a web decoder, whenever the message comes from a real login.

The SAML assertion: claims, the NameID, and why people call it a SAML token

A SAML assertion is the signed XML statement inside the response that says who the user is. Its working parts are the issuer, the subject with its NameID, the conditions that limit when and where it is valid, the authentication statement, and the attributes. People call it a SAML token, but it is not a JWT.

The assertion gives the standard its name, Security Assertion Markup Language: SAML assertions “carry statements about a principal that an asserting party claims to be true.” The first two columns below follow the specification’s own example; the third column, what your app does with each part, is my working rule.

Part of the assertionWhat it holdsWhat your app does with it
IssuerThe identity provider’s entity IDMatch it to the connection stored for this customer
ds:SignatureThe provider’s signature over the assertionVerify it with the certificate on file before reading anything else
Subject and NameIDThe user’s identifier, in an agreed format such as email, persistent or transientUse it, together with the issuer, as the account key
SubjectConfirmationDataInResponseTo, Recipient, NotOnOrAfterMatch your request ID and your ACS URL, and refuse after the deadline
ConditionsNotBefore, NotOnOrAfter, AudienceRestrictionEnforce the time window and check the audience is your entity ID
AuthnStatementWhen the user authenticated, how, and a session indexRecord it with the login
AttributeStatementNamed attributes such as name, email or groupsMap only the attributes you expect, to the lowest role by default

The NameID is what people mean by a SAML ID. The specification’s formats include email address, persistent and transient; persistent identifiers “provide a permanent privacy-preserving federation”, while transient ones “are destroyed once the user session terminates”, which makes them useless as an account key. Google Workspace sends the primary email as the Name ID by default, and Entra ID issues a transient one as a value that “can’t be used to identify the authenticating user.”

Microsoft’s tooling calls attributes claims: Entra’s protocol page says the attribute statement “contains claims about the subject or user”, so a SAML claim is one attribute in that statement. The word “token” has a history too. The SAML technical overview uses it where “A SAML assertion is placed within a WS-Security token”, and in single sign-on talk a SAML token simply means the assertion; the FAQ compares it with a JWT.

The SAML user in your database needs a key that cannot collide. My working rule: key the account on the pair of identity provider and NameID, never on email alone, because two customers’ providers can each assert the same address. Map attributes to roles explicitly and keep the role model itself in one place; RBAC examples shows what that model looks like.

SAML metadata, and what a SAML metadata generator is for

SAML metadata is an XML document each side hands the other, with its entity ID, its endpoints and its signing certificate. A SAML metadata generator builds that file from a form, which is fine for a test. In production, let the SAML library produce it so it matches what the code does.

The metadata specification, an OASIS Standard dated 15 March 2005, exists because SAML “profiles require agreements between system entities regarding identifiers, binding support and endpoints, certificates and keys”. Every identity provider publishes at least one single sign-on service endpoint, and every service provider at least one assertion consumer service.

Your app produces one file for the customer and reads theirs. In my reading, taking theirs from a URL is worth insisting on, so a new certificate reaches you without a support ticket: the specification lets entities publish metadata at a well-known location and strongly recommends https URLs, and OWASP calls metadata URLs “the ideal state” of the relationship. A generator only ever needs your public certificate, so never paste a private key into an online one.

SAML security: the six checks your side has to make

SAML security on the app’s side comes down to six checks: verify the signature, confirm the signed element is the one you read, match issuer and audience to this customer, enforce the time window, refuse a response you did not request or have already seen, and harden the XML parser. A maintained library does the work.

On a cyber security review, a SAML login stands or falls on these six checks. The checks and the failures come from OWASP’s SAML Security Cheat Sheet, except the external-entity line in check 6, which comes from OWASP’s XML External Entity Prevention Cheat Sheet, and the clock allowance in check 4, which is my working rule.

The checkThe failure it stops
1. Verify the signature with the certificate you stored from the provider, ignore any key sent inside the message, and refuse a response where neither the response nor the assertion is signedA forged or modified assertion accepted as the provider’s
2. Confirm the signature’s reference covers the exact Assertion your code readsXML signature wrapping, where a valid signature sits over one element and your code reads another
3. Match Issuer and Audience to this customer’s connection, and Destination and Recipient to your ACS URLAn assertion minted for another app, or another customer, replayed against yours
4. Enforce NotBefore and NotOnOrAfter, with a small allowance for clock driftA stolen or old assertion used after its window
5. Match InResponseTo to a request you sent, and keep used assertion IDs until they expireReplay: the same response accepted twice
6. Validate against local copies of the schemas, never download schemas, and disable DTDs and external entities in the parserXML external entity (XXE) attacks and schema tricks

Then use a maintained library and keep it patched. Okta’s developer docs make the same call: “The easiest way to implement SAML is to use an open-source SAML toolkit.”

That last step matters more than it looks. On Sep 10, 2024, an advisory was published in the SAML-Toolkits/ruby-saml repository; the ruby-saml advisory in the GitHub Advisory Database, “SAML authentication bypass via Incorrect XPath selector”, rated Critical, says ruby-saml versions before 1.12.3, and from 1.13.0 before 1.17.0, “does not properly verify the signature of the SAML Response.” Per the advisory, “An unauthenticated attacker with access to any signed saml document (by the IdP) can thus forge a SAML Response/Assertion with arbitrary contents”, which “would allow the attacker to log in as arbitrary user within the vulnerable system”; the patched versions are 1.12.3 and 1.17.0, and the entry also references an advisory for omniauth-saml. The lesson I take from it: check 1 is the one control on this page a small team should not write itself, and “use a maintained library” includes keeping it patched, because the library’s version is part of your login.

The endpoint that receives assertions is also one more public endpoint that has to refuse bad input. In my June and July 2026 audits, 11 of the 21 third-party apps had unauthenticated endpoints doing privileged work, and 7 of the 21 third-party apps had confirmed cross-user or cross-tenant authorization failures, where a logged-in user could read or write another customer’s data. Those 21 apps are a selected set I audited, not a random sample, so the counts are not a rate for AI-built apps in general. SSO changes who signs in, never what they may do once inside; that ground belongs to broken access control.

What is JIT provisioning, and how just-in-time provisioning works with Okta

JIT provisioning, short for just-in-time, creates a user’s account the first time a valid login arrives from the customer’s identity provider, using the attributes it carries. It never removes anyone: a person disabled in Okta keeps their account and any live session in your app until something else ends it.

Okta’s just-in-time provisioning docs describe the same idea from Okta’s own side, where Okta JIT provisioning is used to “automatically create a user profile when a user first authenticates”, including through inbound SAML, and the setting that turns it on reads “Create and update users on login”. The page describes creating and updating accounts only; in my reading, removal is not part of the mechanism, in Okta or in your app.

When your app does the same for a customer’s staff, three decisions are yours. My working rule for each:

  • Which provider may create users in which tenant: bind it to the connection the assertion arrived on, never to the email domain inside the message.
  • The default role: the lowest one, with anything higher granted in your app or from an attribute you map on purpose.
  • What a later login changes: decide whether a new name, email or group from the provider overwrites your copy, and log it when it does.

The gap is removal. A person the customer disables stays in your database, and a session they already hold keeps working until it expires or your app ends it; sessions and global sign-out come under the question what is active session management, and removing the account and its data under the account deletion feature. In my reading SCIM is what closes that gap, and whether to buy or build it is the SSO request article’s question; the FAQ below sets out the difference. What first sign-in means for staff who already have password accounts is covered in that article’s section on people already signed in, so this section stays with the code.

Integrating with Okta, and how to test Okta authentication before the customer does

Integrating with Okta is rehearsed in a free Okta org before any customer is involved: create the org, add an OIDC or SAML app, enter your URLs, map attributes, assign a test user, sign in from both directions, then unassign the user and watch what your app does.

In my reading Okta is a common identity provider for an enterprise customer to name, which makes it a good one to rehearse against. Everything here happens in a browser. Okta’s developer site offers the Okta Integrator Free Plan, free, to “Build, test, and manage integrations”; access “automatically expires after 90 consecutive days of inactivity.”

  1. 01 Sign up for the Okta Integrator Free Plan and open the Admin Console
  2. 02 Under Applications, click Create App Integration, choose Classic experience, and pick OIDC - OpenID Connect or SAML 2.0 as the sign-in method
  3. 03 For OIDC, set the Sign-in redirect URI to your callback URL, then copy the Client ID and Client secret into your app
  4. 04 For SAML, enter your ACS URL as the Single sign-on URL and your entity ID as the Audience URI (SP Entity ID), choose the Name ID format, add attribute statements, and load the signing certificate from the Sign On tab into your app
  5. 05 Assign a test user to the app integration
  6. 06 Sign in from your own login page, then again from the app tile on the Okta dashboard
  7. 07 Unassign the test user in Okta and record what your app does with the account and any open session

The field names follow Okta’s SAML app integration wizard and its OIDC twin. Two details save time: the Single sign-on URL “is always used for Identity Provider (IdP) initiated sign-on requests”, and “Preview the SAML Assertion” shows the XML Okta will send before anyone signs in. Each test of Okta authentication in this rehearsal runs in an org you own, against your own staging app.

When a customer names Microsoft Entra ID instead, run the same rehearsal there: Entra ID documents both SAML and OpenID Connect sign-in, and its certificate page adds one more thing to note, that Entra sends an email notification 60, 30 and 7 days before the SAML certificate expires. When a security questionnaire asks whether you support SSO, this rehearsal and the seven tests below are your evidence; the forms themselves are a separate topic: security questionnaire examples.

Open source SSO: run the identity layer yourself, or buy the connection

Open source SSO means running an identity server such as Keycloak or authentik in front of your app. The server deals with each customer’s identity provider, and your app talks to it with one protocol. The software is free to run, and it becomes a production system holding every login, with patching and backups to match.

Keycloak “provides support for OpenID Connect, OAuth 2.0, and SAML”, can “authenticate users with existing OpenID Connect or SAML 2.0 Identity Providers”, and is licensed under the Apache License 2.0. authentik lists “OAuth2, SAML, LDAP, and SCIM” among the protocols it supports and comes as a “forever-free open source project”, MIT-licensed outside its enterprise directory, plus a “source available Enterprise version”.

Hosted brokers, such as WorkOS, Auth0 and Clerk, do the same job as a service. The route table below takes its license and protocol cells from each project’s own pages and license files; the “what you still build” and “fits when” columns are my reading.

RouteWhat you runWhat you still buildFits when
A SAML or OpenID Connect library inside your appNothing new; the library runs in your codeEach customer connection, the six checks’ configuration, tenant binding, roles, sessions, an admin page for connectionsOne or two customers on one protocol
An open source identity server (Keycloak, Apache License 2.0; authentik, MIT outside its enterprise directory)A server you host, patch, back up and monitorTenant binding, roles and sessions in your app, over one protocol to the serverSeveral customers on different identity providers, and someone to run it
A hosted broker (WorkOS, Auth0, Clerk and similar)Nothing; the vendor runs itTenant binding, roles and sessions, against the vendor’s APISeveral customers soon, and nobody to run an identity server

An identity server holds every login, so in my reading it needs patching, backups, monitoring and a second person who understands it, because when it is down nobody at any customer can sign in. Prices and plan gates for the hosted route are in the SSO request article.

When to pick each: OpenID Connect only, SAML as well, a broker, or not yet

Choosing takes two questions: what does the customer’s written requirement name, and how many enterprise customers are in sight. No protocol named means OpenID Connect. SAML named means SAML, through your auth provider if it offers it. Several customers on different providers means a broker or identity server. No deal attached means not yet.

Each option below has a “fits when” and a “does not fit when”. They are my working rules, except where a source is named.

OpenID Connect only

Fits when the customer’s requirement says “SSO” without naming a protocol and their identity provider supports OpenID Connect, which Okta, Entra ID and Google all do. It is also where Microsoft’s default points, as the comparison above sets out. Does not fit when the security form names SAML 2.0, or when the customer’s provider is a legacy one that lacks OIDC; both are on the guide’s “Choose SAML if you” list, beside procurement rules that mandate SAML. In my reading, supporting OpenID Connect first still leaves room to add SAML later, since the account model does not change.

SAML as well

Fits when a signed deal depends on it. My working rule is that it does not fit as a speculative build, because every connection is per-customer configuration, a certificate that expires (three years by default in Entra ID) and a support ticket when either side changes something. Okta’s SAML planning guide adds two items to that list: a self-service admin page so the customer’s IT admin can enable SAML, and a “backdoor” sign-in URL that skips the SAML redirect so a broken configuration cannot lock your own admins out. If the auth provider under the app offers SAML, as Supabase Auth does, use it.

A broker or an identity server

Fits when a second and a third enterprise customer are in sight, each on a different identity provider, and per-customer SAML configuration would otherwise become someone’s job. Does not fit when there is one customer and the broker’s per-connection price is more than the work it saves. Whichever you choose, the app still owns tenant binding, roles and sessions: the broker tells you who signed in, and your code still decides where they land and what they can do.

Not yet

Fits when the request is a checkbox on a questionnaire with no deal attached. How to tell the customer is answered in the SSO request article’s FAQ. Meanwhile, turn on enforced two-factor authentication for that customer’s admins; how to implement two-factor authentication covers it. Never claim SSO support that has not passed the seven tests below.

How to check the SSO you shipped: seven tests on your own app

An SSO integration is proven with seven tests on staging: a valid login lands in the right tenant, an unsigned response is refused, an expired one is refused, a repeated one is refused, a matching email from another customer’s provider stays out, an admin attribute does not skip permission checks, and an unassigned user loses access.

The tests run against your own staging app and a test identity provider org, such as the Okta rehearsal above, with two test connections for test 5. They hold for any SAML or OIDC library, and the evidence for each is your app’s own log line or audit entry.

  1. 01 A valid login lands in the right tenant with the lowest role, and you keep the audit entry
  2. 02 A captured test response with its signature removed, edited on your own machine, is refused, and you keep the log line
  3. 03 A response replayed after its NotOnOrAfter time, or an ID token presented after its exp time, is refused
  4. 04 The same response submitted twice is refused the second time
  5. 05 A test user from the test provider of customer A, whose email matches a user at customer B, cannot enter the tenant of customer B
  6. 06 A role attribute set to admin at the identity provider does not skip your server-side permission checks
  7. 07 A user unassigned at the identity provider loses access within the window you state, and their existing session ends by then

Any test where the bad login gets through stops the launch. Run these only against systems you own.

On a hardening sprint, we verify deliverable 1.3 by calling protected actions directly as unauthorized and underprivileged users and confirming rejection ; deliverable 1.4 is verified by running read and write tests as anonymous users, different roles, and separate tenants ; and deliverable 1.9 is verified by creating multiple sessions, revoking them, and confirming protected access stops.

Where the sprint fits

None of the 123 deliverables the Production Hardening Sprint publishes names single sign-on, SSO, SAML or OpenID Connect. Deliverable 1.1 reviews and fixes signup, login, logout, password reset, email verification, and OAuth callbacks ; deliverable 1.2 verifies expiry, refresh, and session revocation on logout and password change ; deliverable 1.7 writes a one-page matrix defining roles and their permitted actions ; and deliverable 1.11 enforces a second factor on every owner and admin account, in the application and on every provider dashboard behind it, with recovery codes stored in the owner’s vault. Formal third-party certifications and independent audit opinions are separate from the sprint deliverables. The full list, with how each deliverable is verified, is on the published scope.

Common questions about SAML, OIDC and enterprise SSO

What is replacing SAML?

For a SaaS deciding today, both standards stay in use. Microsoft’s decision guide still lists cases where you should choose SAML, such as enterprise customers that require it, beside its default to OIDC for new SaaS, and the OpenID Foundation’s own page expects that “SAML and OpenID Connect will likely coexist for quite some time.”

Is Okta OpenID or SAML?

Both. Okta’s identity solutions are built on OAuth 2.0 and OpenID Connect, and the same Okta org can also act as a SAML 2.0 identity provider; you choose the protocol each time you create an app integration.

What is the difference between jit and scim provisioning?

JIT creates or updates an account when the user signs in, and never removes one. SCIM, in RFC 7644’s words, is “an HTTP-based protocol that makes managing identities in multi-domain scenarios easier to support via a standardized service”. In my reading, the identity provider uses SCIM to create, update and deactivate users in your app ahead of and after login, so a person removed from the directory loses access without ever signing in again. Whether to build it is the SSO request article’s question.

What is the difference between a JWT and a SAML token?

A JWT, in OpenID Connect’s ID token, is signed JSON that your server receives from the provider’s token endpoint and checks with keys the provider publishes. A SAML token is an XML assertion with an embedded signature, posted through the user’s browser and checked against a certificate you stored. Both say who the user is; the format, the route and the key handling differ.

Which is better for an entra id, OIDC or SAML?

Entra ID supports both, and Microsoft’s own guide leans one way: “If unsure, default to OIDC for new SaaS development.” Pick SAML when the guide’s cases apply: enterprise customers that require SAML, compliance or procurement rules that mandate it, or a working SAML implementation you already have.