SAML, SCIM and the security questionnaire: what FDEs run into on their first enterprise contract
The demo can work perfectly, but the customer's security team will not let you into production until you can say how long a departing employee keeps access.
In brief
- SAML gets users into the application; SCIM manages their accounts. Security teams care about both, and about revocation most of all.
- JIT provisioning is enough when a customer is starting out, but it cannot revoke access because it only runs when someone signs in.
- Each IdP supports only part of the SCIM standard and syncs with different delays, so test separately against Okta, Entra ID and every other IdP you support.
SAML gets users into the application; only SCIM can revoke access without waiting for anyone to sign in again.
Graphic: FDE Times
It is your third day on the customer’s site. The demo works and the business users want to start using it for real. Then an email arrives from the customer’s security team with a questionnaire several dozen lines long attached. The first line asks whether the application supports SAML SSO.
According to a playbook on enterprise SSO onboarding published by CIAM Compass, the first enterprise B2B SaaS contract usually comes with a security questionnaire that requires SAML SSO.
A 2026 FDE career guide from Georgia Southern goes further, placing enterprise SSO and compliance constraints such as SOC 2, HIPAA, FedRAMP and data residency at the centre of the role’s day-to-day work.
Most developers think of login as a form with a username and password. An FDE has to treat identity as a system with a lifecycle: how users get in, what they are allowed to do, and when they lose access. Answer those three questions clearly and you earn the security team’s trust.
Signing in and managing accounts are different problems
SAML is an XML-based protocol for exchanging authentication data with an identity provider. When a customer’s employee clicks “Sign in with company account”, an IdP such as Okta or Entra ID authenticates them and sends your application a signed assertion stating who the person is and which groups they belong to.
SCIM solves a different problem. It is a REST + JSON protocol for synchronising identity data: the IdP calls your API to create, modify or deactivate accounts. Authgear sums up the difference neatly: SAML lets users sign in, while SCIM creates and manages their accounts.
Between the two sits JIT (just-in-time) provisioning. The first time someone signs in via SAML, the application creates their account from the information in the assertion. It is fast and cheap, but it has a weakness every security team will ask about.
Clerk’s write-up on SCIM 2.0 states plainly that JIT cannot deprovision. An employee locked out in the IdP will never sign in again, so the application never receives a signal. If they still have an open session or an old API token, their account in your system remains valid.
SCIM fixes this because the deactivate operation runs independently, without waiting for anyone to sign in.
An example: a hospital on Entra ID
Imagine you are deploying a data-analysis tool for a hospital subject to HIPAA, and the hospital uses Microsoft Entra ID. Before writing a single line of configuration, the first thing to settle is whether the customer mandates SAML or will accept OIDC.
The CIAM Compass playbook advises asking directly whether the customer’s procurement team specifically requires SAML.
A discovery conversation might go like this.
FDE: Do you strictly require SAML, or is SSO through Entra ID enough? IAM lead: Our policy says SAML. For OIDC we’d have to check with procurement. FDE: Do your assertions include group claims? Which groups do you currently have that relate to this tool? IAM lead: Yes. One group for clinical analysts, one for the administrators. FDE: When an employee leaves, how quickly does internal policy require them to lose access?
The last question matters most. It decides whether you can stop at JIT or must build SCIM from the start.
Once you have group claims, the next step is to map them to the application’s role model, as the playbook recommends. The principle is default deny: anyone not in a declared group does not get in.
GROUP_TO_ROLE = {
"hosp-tool-admins": "admin",
"hosp-clinical-analysts": "analyst",
}
ROLE_PRIORITY = ("admin", "analyst")
def resolve_role(group_claims: list[str]) -> str | None:
roles = {GROUP_TO_ROLE[g] for g in group_claims if g in GROUP_TO_ROLE}
for role in ROLE_PRIORITY:
if role in roles:
return role
return None # no matching group: deny, do not assign a default "viewer"
def on_saml_login(assertion):
role = resolve_role(assertion.groups)
if role is None:
raise PermissionError("User is not in an authorised group")
user = upsert_user(email=assertion.email, role=role) # JIT
return start_session(user)
The on_saml_login function refreshes the role on every sign-in, so if someone is moved out of the admin group they lose admin rights the next time they sign in. But if they never sign in again, nothing changes.
That is where SCIM has to come in, with an endpoint that receives the deactivate command, marks the account inactive, kills every session and revokes tokens immediately.
The standard on paper versus IdPs in the wild
At this point many people assume that reading the RFC and implementing it faithfully is enough. Clerk warns that RFC 7644 defines a very broad protocol, but enterprise IdPs implement only a pragmatic subset of it. Code that works with one IdP can break with another, so you have to test separately against every IdP the customer actually uses.
Latency differs too. Provisioning from Okta is close to real-time, while Microsoft Entra ID syncs incrementally, sending only changes, on fixed scheduled cycles. For the hospital in the example, that means there will be a gap between IT locking an account in Entra ID and your application receiving the deactivate command.
State that gap clearly to the security team. Do not promise “instant revocation”.
Steps to take in the first week
Start by reading the security questionnaire carefully and pinning down the real requirements: SAML or OIDC, which IdP, whether group claims are sent, and the deadline for revoking access. Then design the group-to-role mapping table and send it to the customer for approval before writing code, because the group names are their data, not yours.
Next, build JIT first so users can get in, and document clearly that JIT does not yet handle revocation. If the customer has many users or a strict revocation policy, put SCIM in the plan straight away.
The CIAM Compass playbook also holds that JIT is only enough for the early stage, and that B2B SaaS at scale needs SCIM as well.
The final step is usually the hardest and has nothing to do with code: getting production credentials. The Georgia Southern guide calls this outright a matter of internal politics when working with the customer’s security team. The better prepared your answers on deprovisioning, permissions and audit logs, the shorter that negotiation will be.
Common mistakes
The most common mistake is assigning a default role to anyone who matches no group. It is convenient in development, but in a HIPAA environment it is an authorisation hole. The second is assuming that locking an account in the IdP means the application automatically knows, when with JIT the application never receives that signal.
The third is testing against a single IdP and then claiming support for “standard SCIM”. The fourth is promising a revocation time without knowing the sync cycle of the customer’s IdP. The last is waiting until the security team asks before thinking about any of this.
This week’s exercise
Take an application you are working on and draw the timeline from the moment an employee is locked out in the IdP to the moment they actually lose all access: sessions, API tokens, running jobs. Mark which steps depend on them signing in again, then redo the calculation for both Okta and Entra ID.
If you can answer that question with a number and a diagram, you are speaking the security team’s language. For an FDE, that is often the fastest route to production access.
Was this article useful?
Thanks for the feedback!