SCIM provisioning basics: flows, fields, and safe testing
SCIM provisioning basics for keeping users in sync with your identity provider: create, update, deactivate flows, required fields, and safe testing steps.

What SCIM provisioning is and why teams use it
SCIM provisioning solves a simple, painful problem: the list of people who can access an app slowly stops matching the list in your identity provider (IdP). Someone gets hired, changes their name, switches teams, or leaves, and the app doesnât always reflect that change right away.
Provisioning means the IdP pushes user changes to the app automatically. Instead of an admin manually inviting users, updating profiles, and removing access, changes start in the IdP and the app follows.
When invites and offboarding are manual, the same failures show up again and again. New hires wait for access because someone forgot an invite. Former employees keep access because offboarding was missed. Names, emails, and departments drift across tools. Audits get harder because you canât trust the appâs user list. Support tickets pile up (canât log in, wrong access, still seeing old data).
SCIM is a good fit when you need reliable user lifecycle control at scale, especially for internal tools, admin panels, and customer portals where access should mirror HR and IT decisions.
SSO alone usually isnât enough. SSO answers âHow does a user sign in?â SCIM answers âShould this user exist in the app, and what should their account look like right now?â
The core idea: one source of truth for users
Start with one rule: pick a single system thatâs ârightâ about who a user is and what they can access. In most companies, that system is the IdP (Okta, Azure AD, Google Workspace).
The IdP is where people are created, disabled, and assigned to groups. The service provider (SP) is the app receiving those decisions and applying them in its own user database. That could be a SaaS product, or a custom internal app you built.
Once the IdP is the source of truth, the app shouldnât argue with it. If an admin disables a user in the IdP, the app should treat that user as disabled even if someone tries to re-enable them locally. The same applies to group membership when groups drive access.
Provisioning is usually push-based: the IdP sends changes to the app when something happens. Thatâs different from pull-based directory sync, where the app periodically asks what changed. Push is faster and clearer, but mistakes can take effect immediately, so defaults and matching rules matter.
Most activity is driven by normal HR and IT events: new hires, role changes, leave of absence, and terminations. If you keep status and group assignments controlled in the IdP, you reduce duplicates, âghostâ accounts, and last-minute access gaps when someone moves teams.
User lifecycle flows: create, update, deactivate
Most provisioning setups boil down to one promise: the IdP tells your app who exists and whether they should be able to sign in. Your app needs to handle a few lifecycle states consistently.
The three states that matter
Most teams think in three states:
- Active: the user can authenticate and use the product.
- Inactive (deactivated): the account remains, but access is blocked.
- Deleted: the record is removed (many apps avoid hard deletes and treat this like inactive).
Create usually happens when an admin assigns the app to a person in the IdP, or when they join a synced group. Your SCIM endpoint should store what you need to match that person later: a stable unique ID from the IdP (often the SCIM id), plus a login value (commonly userName). If your app requires email, make that explicit in mapping so the create doesnât fail halfway through.
Update happens when the IdP changes a profile field or assignment. Apply changes to identity and communication fields (name, email, department) without unexpectedly changing access. The most sensitive field is the login identifier. If userName can change, you still need to match the same person using an immutable identifier. Otherwise youâll create duplicates.
Deactivate should block access quickly without losing business data. The IdP typically sets active=false. Your app should treat that as âcannot sign in, cannot use API,â while preserving owned records, audit history, and references.
Reactivate is the reverse. active=true should restore access for the same account, not create a new one. If the IdP considers it the same person, your app should too, even if email or display name changed while they were away.
Required fields and attribute mapping that avoids surprises
Provisioning works when the app and the IdP agree on two things: how to identify a user, and which attributes the IdP is allowed to overwrite.
The minimum you usually need
SCIM is flexible, but most apps end up relying on the same core attributes:
- A stable unique identifier (the SCIM resource
id, often paired withexternalIdfrom the IdP) - Email or username (commonly
userName, often used for login) - Name (either
name.givenNameandname.familyName, ordisplayName) - Active status (
active: true/false) - Timestamps or metadata (optional, but helpful for audits and debugging)
The identifier is the key detail. Email feels unique, but it changes. If you match users only by email and someone gets renamed (marriage, rebrand, domain migration), the IdP may look like itâs creating a new person instead of updating the old one. Thatâs a common path to duplicates.
Decide what the IdP can overwrite
Pick a clear rule: which fields are IdP-owned (the IdP always wins) and which are app-owned (the app can change them without being reverted).
A common, safe split:
- IdP-owned:
active, email/username, given and family name, display name - App-owned: app-specific profile fields (preferences, internal notes)
If your app lets people edit their name, decide whether those edits should stick or get replaced by the next SCIM update. Either choice can work. The problem is when itâs unpredictable.
Handle missing and messy data
Expect blanks and inconsistent formats. Some directories send only displayName. Others send given and family name but no display name. A practical fallback is to build displayName from given and family name when needed, and handle missing family names gracefully.
Validate critical fields. If userName is empty, or not an email when your login requires an email, reject the request with a clear error and log it. Quietly creating a user who canât sign in turns into a slow outage.
How accounts get matched and why duplicates happen
A âmatchâ is when the IdP and your app agree that two records represent the same person. Most provisioning issues come down to which fields your app uses to find an existing user when the IdP sends an update.
What should be used for matching
Match on a stable, non-human identifier first. Treat email and username as profile data that can change.
Common matching keys (most reliable to least reliable):
- Immutable external ID from the IdP
- SCIM
id(stable per user in that app) - Email (useful, but changeable)
- Username (often renamed, reused, or formatted differently)
If your app matches by email only, an email change can look like a brand-new person and create a duplicate. Instead, keep the external ID as the primary key and allow email to update without changing identity.
Why duplicates happen
Duplicates tend to appear in three situations:
- The IdP sends a âcreateâ because the app didnât return a clear match, often due to missing required attributes or a mapping mistake.
- The app treats email as the unique identifier, so an email change creates a second user.
- The same person is provisioned from two places (two IdPs, or manual invites plus SCIM).
To reduce conflicting updates, choose one owner for core profile fields. If the IdP owns names, email, and active status, donât rely on manual edits inside the app for those fields (or label them clearly as âmanaged by IdPâ).
If two IdP users end up pointing to one app user, donât auto-merge. Pause SCIM for those accounts, decide which IdP identity is correct, re-link using the external ID, and deactivate the wrong one. That keeps audit history consistent.
Groups, roles, and access: keep the rules predictable
When SCIM starts sending users and groups, the biggest risk is surprise access. Keep the model simple: grant access based on IdP groups, or grant access based on roles managed inside the app. Mixing both without a clear rule leads to âwhy did they get access?â incidents.
Group-driven access works well when your IdP is already where admins manage team membership. Role-driven access works better when app owners need to fine-tune permissions without touching the IdP. If you must combine them, define which one wins when they conflict.
Be conservative with defaults. If group data is delayed or missing (common during first sync), create the account but give it no sensitive access until the expected group arrives. Treat âno groupsâ as âno accessâ rather than guessing.
A predictable rule set:
- Create user: assign a baseline role with minimal access, or no role.
- Add to group: grant the access tied to that group.
- Remove from group: remove that access immediately.
- Deactivate user: block sign-in and revoke access regardless of groups.
- Reactivate user: restore only what current group membership allows.
Group removal and deactivation are different. Group removal should reduce access while keeping the account usable if the user still belongs to other groups. Deactivation is the hard stop for offboarding.
Keep the documentation short, but specific: which groups map to which permissions, what happens if groups are missing, who owns group changes (IT vs app owner), and roughly how long changes take to show up.
Step-by-step: test SCIM without locking people out
Start in a non-production environment (separate tenant, workspace, or staging instance) with a clean directory and a few test accounts. Turn on provisioning there first.
Before connecting anything, create a break-glass admin account that is not managed by SCIM. Give it a strong password and keep it out of your IdP SCIM assignments. This is your way back in if provisioning disables your normal admins.
Use a small pilot group (2-5 people). Include one admin and one regular user. Donât enable provisioning for the whole company until the pilot behaves exactly as expected.
A simple test plan that covers the risky parts:
- Create: Assign a new test user in your IdP and confirm the account appears in the app with the right name, email, and status.
- Update: Change one field (often email) and confirm the app updates the same user rather than creating a duplicate.
- Deactivate: Remove the assignment (or disable the user) and confirm the app blocks access without deleting business data.
- Reactivate: Re-assign the user and confirm the same account becomes active again.
- Repeat: Run the same steps again to catch âfirst run onlyâ behavior.
Donât trust the UI alone. Check SCIM logs on both sides and confirm timestamps: when the IdP sent the change, when the app processed it, and which fields changed.
If any step creates a second account, deactivates the wrong user, or drops admin access, stop the rollout and fix matching and attribute mapping before expanding beyond the pilot.
Common mistakes that cause lockouts or messy directories
Most problems arenât âSCIM bugs.â They come from small assumptions that seem harmless during setup, then break at scale. Matching rules and defaults matter more than the connector.
Mistakes that usually cause lockouts
Common patterns that lead to disabled accounts, duplicates, and access sprawl:
- Loose matching (for example, matching on email only, or allowing multiple users with the same identifier).
- Treating email as a permanent ID even though emails get renamed, migrated, and sometimes reused.
- Letting SCIM overwrite manual fixes without anyone noticing (the IdP will reapply its view of truth).
- Giving broad access on user creation by default and forgetting to tighten it later.
- Turning provisioning on for everyone before a pilot, so one mapping mistake hits the whole company.
A real-world failure mode: during a domain change, IT renames emails. If the app matches on email, SCIM canât find the existing account, creates a new one, and then deactivates the old one. The user ends up with two profiles, broken history, and no access at the worst time.
How to avoid the mess
Match on a stable unique identifier (often the IdPâs immutable user ID) and treat email as changeable.
Decide who can edit user fields in the app. If SCIM is the source of truth, either block manual edits for IdP-owned fields or make it obvious theyâll be reverted.
Start with a small pilot and least-privilege defaults. Itâs easier to add access once you trust the flow than to clean up after over-provisioning or a bad deactivate run.
Quick checklist before you enable SCIM for more users
Before expanding beyond a pilot, verify the full lifecycle: create the right account, update the same account later, and remove access when needed.
Use one fresh test identity in your IdP (not a real employee). Provision it and confirm the account shows up with the expected username, email, display name, and status in your app.
Then run a change test. Update the personâs name and email in the IdP and watch what happens in the app. You want one user record updated, not a second user created.
Finally, test removal and recovery. Deactivate the user in the IdP and confirm they canât sign in and no longer have access. Then reactivate them and confirm access returns predictably (correct roles, correct groups, no accidental admin rights).
A short go-live checklist:
- New user provisions correctly with the right key fields and starts in the right access state.
- Profile changes update the same person (no duplicates).
- Deactivation blocks sign-in and removes access quickly.
- Reactivation restores access safely.
- Admin recovery exists (break-glass admin, ability to pause SCIM, audit trail of recent changes).
A realistic example: onboarding and offboarding a team member
Imagine a 200-person company using an IdP and SCIM to manage access to an internal tool.
On Monday, Maya joins Sales Ops. When IT assigns the app to Maya in the IdP, SCIM sends a Create. A new user appears in the app with the right unique identifier, email, and a âSales Opsâ department value. If groups drive access, the app also receives the group membership that grants the correct role.
On Thursday, Maya moves to RevOps. That triggers an Update. Maya stays the same person (same external ID), but attributes change. If permissions depend on department or groups, this is where mistakes show up, so verify it right away.
At the end of the month, Maya leaves. The IdP disables the account or removes the app assignment, and SCIM sends a Deactivate (often an update like active=false). Maya canât sign in, but her historical data remains owned by the business.
An admin can verify quickly:
- Create: user exists once, can sign in, gets the expected default role.
- Update: the same user record is updated (no duplicate), and access changes correctly.
- Deactivate: login blocked, sessions ended, no new API access, audit history intact.
- Audit: SCIM events are logged with timestamps and outcomes.
If a contractor needs temporary access, donât reuse Mayaâs account. Create a separate contractor identity in the IdP, put it in a time-boxed group, and let provisioning manage the removal.
Next steps: roll out safely and keep it maintainable
Provisioning can be easy to get working and still hard to run well later. Treat it like a small system with rules, owners, and a change log.
Write down your attribute mapping and access rules in one place: which IdP fields populate username, email, name, department, manager, and which groups grant access. When someone asks why a person was disabled, you want one answer, not five guesses.
Choose a pilot thatâs big enough to be real, but small enough to undo. Define checkpoints (day 1, week 1, week 2), make rollback steps explicit (pause assignments, stop SCIM, restore access), and keep the break-glass admin account outside SCIM.
Monitoring keeps you from learning about problems from angry users. Agree on what youâll watch and who gets notified: spikes in deactivations or reactivations, sudden duplicate growth, unusually high update volume (often a mapping loop), and users created without required attributes.
If youâre building the app yourself, plan user management early: create users, update profiles, deactivate accounts, and assign roles. Itâs much easier when these are first-class features.
If youâre prototyping internal tools, AppMaster (appmaster.io) can be a practical way to build the backend, web app, and mobile app in one place, then connect SCIM through your APIs once your user model and access rules are stable.
FAQ
SCIM provisioning keeps your appâs user list automatically aligned with your identity provider (IdP). When someone is hired, renamed, moved to a new team, or offboarded, the IdP pushes those changes to the app so admins donât have to manually invite, edit, or remove users.
SSO only controls how a user authenticates. SCIM controls whether the user should exist in the app at all, whether theyâre active or inactive, and what their profile fields look like right now. Using both together prevents âthey can sign in but shouldnât have an accountâ and âthey have an account but canât get accessâ problems.
Treat the IdP as the source of truth for identity fields and lifecycle status, then make the app follow it consistently. If your app allows local edits, decide which fields the IdP is allowed to overwrite so you donât get confusing back-and-forth changes.
Most teams rely on three states: active, inactive (deactivated), and deleted. In practice, many apps avoid hard deletes and use deactivation instead, because it blocks access while keeping business data and audit history intact.
Store a stable unique identifier from the IdP (often the SCIM user id, sometimes paired with an IdP immutable ID), plus a login value like userName and any required communication fields such as email. The stable ID is what prevents duplicates when emails or usernames change later.
Match users by an immutable identifier first, not by email. Email and usernames change during renames, domain migrations, and rebranding, and using them as the primary key is one of the fastest ways to create duplicate accounts.
Define which attributes the IdP owns (commonly active status, email/username, and name fields) and apply those updates automatically. Keep app-specific fields (like preferences or internal notes) owned by the app so SCIM updates donât unexpectedly wipe local data.
Start with a small pilot in a non-production environment and keep a break-glass admin account outside SCIM so you can recover if something goes wrong. Test create, update (especially email changes), deactivate, and reactivate, and confirm you always update the same user record rather than creating a second one.
The most common causes are matching on email only, missing required attributes during create, or provisioning the same person from two places (manual invites plus SCIM, or multiple IdPs). Fixing it usually means choosing one authoritative ID, pausing provisioning for affected accounts, and re-linking identities rather than auto-merging records.
Default to least privilege: create the account with minimal or no access, then grant permissions only when the expected group or role arrives. If group data is missing or delayed, treat that as âno accessâ instead of guessing, and make deactivation always override group membership so offboarding is reliable.


