An enterprise customer wants SSO: what SAML, OIDC and SCIM actually cost you
When an enterprise customer asks for single sign-on, they are asking for three separate things: authentication handed over to their identity provider (federation over SAML or OIDC), accounts that open and close by themselves (user provisioning over SCIM), and the administrative layer around both (which email domain belongs to which tenant, who is an admin, where the records live). Changing the login screen is the easy part and takes a week or two. The hard part is keeping a separate federation config alive per customer for years. Certificates expire, domains change hands, a user gets disabled in the corporate directory while their session in your app stays wide open.
It looks like a login button, it is a transfer of control
What the customer's security team wants is not convenience. They want access cut from one place when someone leaves. They want their own multi-factor policy to apply inside your product, their own session lifetime, their own records of who signed in and when. That is not a feature request. It is a request to take over part of the control surface.
The boundary matters. Authentication moves to them, authorization stays with you. Their provider tells you who the user is; you decide what that user can see in your product. If your authorization model is not settled before SSO lands, you will end up designing two systems at once while trying to map directory group names onto roles.
SAML or OIDC?
If you can only ship one, SAML is still the one that gets you through enterprise procurement. SAML 2.0, published by OASIS in 2005, has been the default in enterprise app catalogs for twenty years. OIDC is newer, built on JSON and JWTs, and noticeably nicer to work with. The difference shows up in two places that have real consequences.
The first is key management. In OIDC the provider publishes signing keys at a JWKS endpoint and your client fetches the current key itself. Nobody puts a reminder in a calendar. In SAML the signing certificate is a file exchanged by hand, and it does not renew itself when the clock runs out.
The second is IdP-initiated login. Enterprise users expect to click the app tile on their provider's dashboard and land inside your product. SAML supports this natively, because the provider can post an unsolicited response to your ACS endpoint. OIDC is request-bound by design: the flow starts with an authorization request you sent, and state and nonce are tied to that request. There is a third-party-initiated login mechanism in OIDC, but you have to build the handling yourself. That is a large part of why SaaS vendors still hand enterprise customers SAML in 2026.
Practical advice: make the protocol an implementation detail. Keep a single concept called "enterprise connection" in your product and plug SAML and OIDC providers underneath it. Tenant mapping, role mapping and account lifecycle should not care which protocol is in use.
Domain verification is the step you cannot get wrong
In a multi-tenant product, one login box serves everyone. A user types an email address, you read the domain, and you decide "this is example.com, so route the login to that customer's provider." Whoever controls that mapping controls who can sign in as that company's staff. Skip verification and what you have built is not an SSO feature, it is an account takeover mechanism.
The safe pattern is standard: generate a high-entropy random token bound to one tenant and one domain, have the customer publish it as a DNS TXT record, then resolve and compare. Three details get skipped. Re-verify on a schedule, because domains change owners and an old verification only proves who controlled the domain in the past. Keep a blocklist for shared consumer mail domains (gmail.com, outlook.com and friends). Make sure a domain can map to exactly one tenant at a time, and route the second claim through a human rather than an automatic flow.
Validate assertions with a library, then watch that library
Do not parse SAML responses yourself. XML signature validation is an area where teams that know cryptography still get it wrong. Use a mature library and confirm these checks are actually switched on: the signature verifies against a trusted certificate and you know whether the response or the assertion carries it, Audience equals your entity ID, NotBefore and NotOnOrAfter are enforced with a tight clock skew allowance, InResponseTo matches an authentication request you really sent in SP-initiated flows, and Destination and Recipient point at your endpoint. Then add replay protection: store used assertion IDs and reject the second use until the record expires. That cache has to be shared across instances. An in-process dictionary behind a load balancer protects nothing.
Picking a library does not end the responsibility. In March 2025 two authentication bypasses were published in ruby-saml (CVE-2025-25291 and CVE-2025-25292). The root cause is worth understanding: the library used two different XML parsers (REXML and Nokogiri) during signature verification, the two could interpret the same document differently, and that parser differential let an attacker mount a signature wrapping attack. Both issues were reported to the maintainers on November 14, 2024 and fixed on March 12, 2025 in versions 1.12.4 and 1.18.0. Transitive dependents such as omniauth-saml were affected too. Libraries that carry enterprise login belong at the top of your supply chain watch list.
The morning a certificate expires, nobody gets in
SAML signing certificates typically live one to three years. Microsoft Entra ID issues the certificate it generates during SAML setup with a three-year default lifetime and emails the customer's admin 60, 30 and 7 days before expiry. The odds of that email reaching you are low. If a certificate change requires a manual update on your side, one morning every employee at that customer is locked out, and your first clue is the support queue.
Three measures close most of this gap. Where the provider publishes federation metadata at a URL, pull the certificate from that URL on a schedule instead of storing an uploaded file. Model more than one trusted signing certificate per tenant so old and new overlap during a rollover. Store the expiry date as a queryable field and raise an alert, to yourself and to the customer, 30 days out. These three remove the large majority of enterprise SSO tickets.
SCIM is the standard answer to "this person left the company"
The second request always arrives right after login works: when a user is removed from the directory, close their account in your product too. The standard for that is SCIM 2.0, defined across two RFCs. RFC 7643 covers the schema (the User and Group resources), RFC 7644 covers the protocol. In practice you are being asked to expose a REST endpoint their provider knows how to talk to.
Microsoft's guide for building a SCIM endpoint states the expectations plainly: create on /Users and ideally /Groups, update with PATCH, support queries in the form filter=userName eq "...", support pagination, expose /Schemas for discovery plus /ServiceProviderConfig, and accept a single bearer token for authentication. Removal is usually not a deletion: Entra and Okta deactivate a user by sending a PATCH that sets active to false, so your offboarding logic has to trigger on that signal, not on DELETE.
Learn the timing before a customer teaches it to you. After the initial full cycle, the Entra provisioning service runs incremental cycles roughly every 40 minutes, so changes do not arrive instantly; provisioning a single user on demand lets you test without the wait. Okta's model is push-based and sends the request when the change happens. In Entra a deleted user stays soft-deleted for 30 days, and your endpoint only sees a DELETE when the permanent deletion happens. The Entra provisioning service does not read members of nested groups, only groups assigned directly. If the error rate stays high the job goes into quarantine, cycles drop to once a day, and after four weeks in quarantine provisioning is disabled altogether. A team that does not know these behaviors spends days looking in the wrong place at a "sync is broken" ticket.
The hard part of SCIM is two sources of identity, not the protocol
Writing the endpoint takes a few days. The real work comes from the same person arriving through two doors: your own invite screen and the customer's directory. Pick the matching key up front and document it. Email is convenient but it changes; externalId is stable but you still need a first match from somewhere. If you do not think through the case where two records must merge, you will be cleaning up customer data by hand later, with the same human carried on two accounts.
The second trap is deactivation that only goes skin deep. When active: false arrives, flagging the user as inactive is not enough. Revoke live sessions and refresh tokens too, or the person who left keeps working from the tab their browser never closed, and the customer finds out during an audit. Hard-deleting the user row is usually wrong as well: references from the records they created, the approvals they signed off and the audit trail need to survive.
Edge cases that show up after SSO goes live
Four of them hit almost every product. One: a per-tenant switch to enforce SSO. When the customer says "only corporate login from now on," you need to disable password login for that tenant alone. Two: the lockout scenario. Keep at least one break-glass admin account exempt from enforcement for when the provider config breaks, and log every use of it. Three: people who are not in the directory. External auditors, consultants and agencies never are, so do not close the invite path. Four: session lifetime. SAML Single Logout is fragile in practice, so do not build the customer's "I disabled that user" expectation on it. Build it on short sessions plus a check that the account is still active every time a token is refreshed.
A pricing decision: which tier does SSO belong to?
Most vendors put enterprise SSO in the top tier. The practice has a name, the SSO tax. CISA's May 2024 report on barriers to SSO adoption for small and medium-sized businesses criticizes it directly and recommends that SSO be available by default as part of the base offering; the report lists cost, technical difficulty and incomplete documentation as the main obstacles smaller organizations face.
There is a workable middle. Put login itself (the SAML or OIDC connection) in a reasonable tier, and package the administrative capabilities separately: SCIM provisioning, audit log export, per-tenant session policy, multiple connections per tenant. That split tracks your actual cost, and it avoids the look of a security feature locked behind a paywall. The second point comes up in procurement reviews more often than teams expect.
Build it, or use a ready connection?
The first SAML integration takes a few weeks. The cost is not there. It is in the tenth customer's configuration, in certificate renewals, and in triaging "login is broken" tickets with only a browser trace to go on. If identity is not a differentiator in your product, look at the enterprise connection feature of the identity service you already use (Entra External ID, Auth0, Okta Customer Identity) or at a self-hosted identity broker such as Keycloak. The question of building authentication versus buying it usually resolves itself the moment enterprise SSO arrives, because federation is the most expensive line in that decision.
Whichever route you take, three things stay yours: domain verification, mapping directory groups onto your roles, and making sure a deactivated account's session really ends. No external service makes those calls for you.
Five checks you can run this week
One: in your test environment, send an unsigned SAML response, an assertion issued for a different audience, and an expired assertion. All three should be rejected. Two: send the same valid assertion twice; if the second one goes through, you have no replay protection. Three: list the expiry dates of every enterprise customer's signing certificate in a single query. If you cannot, add that field to your data model today. Four: deactivate a test user in the directory and measure how many minutes pass before their live session actually ends. Five: review your domain mappings and manually verify any domain that was attached without a DNS check.
Enterprise SSO requests tend to arrive at a tight moment in a sales cycle and get estimated as two weeks of work. The honest estimate is a few weeks for federation, a comparable stretch for SCIM and the admin surface, then half a day of configuration per new customer and a permanent support load. Put that number on the table early and two things improve at once: the proposal becomes realistic, and you can decide which tier the feature belongs in without a deal pushing the answer.
Need help with this topic?