SCIM User Provisioning in .NET

What enterprise customers expect and how to build it in ASP.NET Core
Chaïm Zonnenberg | Identity & SSO

Your B2B SaaS supports SSO. Enterprise prospects can log in with Azure Entra ID or Auth0. But their IT admin still has to manually create user accounts in your application. That's where SCIM comes in.


What is SCIM?

SCIM (System for Cross-domain Identity Management) is an open standard for automating user provisioning. It defines a REST API that identity providers like Azure Entra ID and Auth0 call to create, update, and deactivate user accounts in your application.

The current version is SCIM 2.0, defined in RFC 7642, RFC 7643, and RFC 7644. It specifies:

  • User and Group resources with a standard JSON schema
  • CRUD operations via REST endpoints (/Users, /Groups)
  • Filtering and pagination for listing resources
  • Bulk operations for initial provisioning of large user bases

Why enterprise customers require it

Without SCIM, this is what happens when a company with 2,000 employees adopts your SaaS:

Without SCIM
  1. IT admin manually creates 2,000 accounts (or uploads a CSV, if you built that)
  2. Employee joins the company → IT admin remembers to add them to your app
  3. Employee changes department → IT admin remembers to update their role
  4. Employee leaves → IT admin remembers to deactivate their account
  5. Security audit asks "how do you ensure offboarded employees lose access?" → "We hope the IT admin remembers"
With SCIM
  1. IT admin configures SCIM provisioning once in Azure Entra ID or Auth0
  2. Employee joins → automatically provisioned in your app within minutes
  3. Employee changes department → group membership updates automatically
  4. Employee leaves → account deactivated automatically
  5. Security audit: "User lifecycle is managed by our IdP, provisioning is automated via SCIM"

This is why SCIM shows up on enterprise security questionnaires right next to SSO. SSO handles authentication. SCIM handles the user lifecycle. You need both.


How SCIM works technically

Your .NET application exposes a SCIM API. The customer's identity provider (Azure Entra ID, Auth0, etc.) calls this API to manage users. The flow:

SCIM endpoints you implement
Method Endpoint Purpose
POST /scim/Users Create a new user
GET /scim/Users/{id} Get a specific user
GET /scim/Users?filter=... Search users (e.g. by email)
PATCH /scim/Users/{id} Update user attributes
DELETE /scim/Users/{id} Deactivate / remove user
POST /scim/Groups Create a group
PATCH /scim/Groups/{id} Add/remove group members

The identity provider authenticates to your SCIM API using a bearer token (OAuth2) or a long-lived API token. Azure Entra ID and Auth0 both support these methods.


Building SCIM in .NET 10

There's no official Microsoft library for SCIM server-side in .NET. You build it yourself using standard ASP.NET Core controllers and middleware. The key considerations:

1. Schema mapping

SCIM defines a standard user schema (urn:ietf:params:scim:schemas:core:2.0:User) with fields like userName, emails, name.givenName, name.familyName, and active. You map these to your application's user model.

Most SaaS applications don't need the full SCIM schema. Map the fields your application actually uses. Azure Entra ID and Auth0 let administrators configure which attributes to sync.

2. Filtering

Identity providers query your SCIM API to check if a user already exists before creating one. The most common filter: filter=userName eq "john@example.com". You need to implement at least basic SCIM filter parsing. The full filter spec is complex, but in practice Azure Entra ID and Auth0 use a small subset.

3. PATCH operations

SCIM PATCH uses a specific format with Operations containing op, path, and value. This is where most implementation bugs live. Azure Entra ID sends PATCH requests to update individual attributes (e.g. deactivating a user by setting active to false). Get this right.

4. Idempotency

Identity providers may retry requests. Your SCIM endpoints must be idempotent. Creating a user that already exists should return the existing user, not a 409 Conflict. Azure Entra ID specifically relies on this behavior.

5. Testing with real identity providers

Azure Entra ID and Auth0 have SCIM testing tools built into their admin portals. Use them. They send specific request patterns that may differ from what the RFC describes. I always test with the actual IdP my customer uses before going live.


Common pitfalls

  • Ignoring the externalId field. The identity provider uses this to correlate users between systems. Store it. You'll need it for troubleshooting.
  • Hard-deleting users on DELETE. SCIM DELETE should deactivate, not delete. The customer's data and history should remain. Set active = false.
  • Not supporting both PUT and PATCH. Azure Entra ID primarily uses PATCH. Auth0 uses both. Support both operations.
  • Missing error responses. SCIM defines specific error response formats. Identity providers use these to show meaningful errors to IT admins. Return proper SCIM error objects, not generic 500s.
  • No rate limiting. When an enterprise first enables SCIM, the IdP syncs all existing users at once. Without rate limiting, this can overload your application.

SSO + SCIM together

SCIM works best alongside SSO (OpenID Connect). The typical enterprise setup:

  • SCIM provisions user accounts and keeps them in sync
  • SSO (OpenID Connect) handles login, so no passwords live in your application
  • OAuth2 manages API access tokens for machine-to-machine communication

When implemented together, the customer's IT admin configures everything in one place (Azure Entra ID Enterprise Applications, or Auth0 Application Integration). Users are provisioned automatically and log in with their corporate credentials.


My experience with SCIM

I've implemented SCIM provisioning endpoints in multiple .NET applications, tested against Azure Entra ID and Auth0. I know which parts of the SCIM spec matter in practice and which parts you can skip.

I also implement the SSO side (OpenID Connect, OAuth2) so the entire identity integration is consistent. One developer who understands the full picture, not three different teams for SSO, provisioning, and authorization.

Related

Replacing IdentityServer4 in .NET

IdentityServer4 is no longer maintained. Duende IdentityServer, OpenIddict, or Azure Entra ID: which one fits your situation?

Read article

Need SCIM provisioning in your .NET application?

I implement SCIM endpoints that work with Azure Entra ID and Auth0. Tell me about your setup, and I'll give you a concrete plan.