Skip to Content
ConceptsSCIM 2.0 Protocol

SCIM 2.0 Protocol

The Problem: Manual Provisioning Does Not Scale

When a company hires a new employee, that person needs accounts in dozens of systems: email, chat, project management, CRM, source control, identity providers, and every SaaS product the team uses. When that employee leaves, all those accounts need to be deactivated — immediately, not “when someone remembers.”

Manual provisioning creates three categories of problems:

ProblemImpact
Onboarding delayNew hires wait hours or days for account creation, losing productive time
Offboarding gapsDeparted employees retain access to systems because someone forgot to deprovision them
Orphan accountsAccounts that belong to no one accumulate over time, creating security liability
Attribute driftA user’s department, title, or manager changes in HR but not in downstream systems
Compliance riskAuditors ask “show me that terminated employee X lost access within 24 hours” — and the answer is often “we cannot prove that”
IT burdenProvisioning and deprovisioning is repetitive, error-prone work that scales linearly with headcount

The solution is automated provisioning: the identity provider (Okta, Azure AD, OneLogin, JumpCloud) pushes user lifecycle events to downstream applications in real time. But every SaaS product implementing its own provisioning API would be chaos — different schemas, different protocols, different authentication methods.

What SCIM Solves

SCIM (System for Cross-domain Identity Management) is a standardized REST API for user provisioning, defined in two RFCs:

  • RFC 7643: The SCIM Core Schema — defines the data model (User, Group, EnterpriseUser)
  • RFC 7644: The SCIM Protocol — defines the REST operations, filtering, pagination, and bulk operations

SCIM gives every identity provider and every service provider a common language. When Okta needs to create a user in Auris, it speaks SCIM. When Azure AD needs to disable a user, it speaks SCIM. The integration is the same regardless of which IdP and which service provider are involved.

SCIM is an inbound provisioning protocol in Auris. The IdP pushes changes to Auris — Auris does not poll the IdP. This means provisioning is near-real-time: when an admin assigns a user in Okta, the SCIM POST arrives at Auris within seconds.

SCIM Resource Types

SCIM defines two core resource types:

Users (/Users)

The User resource represents an identity with attributes mapped to the SCIM Core Schema:

{ "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], "id": "usr_abc123", "externalId": "okta-user-id-456", "userName": "[email protected]", "name": { "givenName": "Jane", "familyName": "Doe", "formatted": "Jane Doe" }, "emails": [ { "value": "[email protected]", "type": "work", "primary": true } ], "displayName": "Jane Doe", "active": true, "title": "Senior Engineer", "department": "Engineering", "meta": { "resourceType": "User", "created": "2025-01-15T10:30:00Z", "lastModified": "2025-06-20T14:22:00Z", "location": "https://auth.example.com/scim/v2/Users/usr_abc123" } }
AttributeSCIM TypeDescription
idStringAuris-assigned unique identifier (read-only)
externalIdStringIdP-assigned identifier (used for correlation)
userNameStringUnique login name (typically email)
name.givenNameStringFirst name
name.familyNameStringLast name
emailsMulti-valuedEmail addresses (primary flagged)
displayNameStringHuman-readable full name
activeBooleanAccount enabled/disabled status
titleStringJob title
departmentStringDepartment name

Groups (/Groups)

The Group resource represents a collection of users:

{ "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"], "id": "grp_xyz789", "displayName": "Engineering", "members": [ { "value": "usr_abc123", "display": "Jane Doe" }, { "value": "usr_def456", "display": "John Smith" } ] }

Groups in SCIM map to roles or teams in downstream systems. Auris maps SCIM Groups to Keycloak groups, which can be linked to roles.

SCIM Operations

SCIM uses standard HTTP methods with REST semantics:

Create User

POST /scim/v2/Users Content-Type: application/scim+json Authorization: Bearer scim_token_here { "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], "externalId": "okta-user-789", "userName": "[email protected]", "name": { "givenName": "Jane", "familyName": "Doe" }, "emails": [ { "value": "[email protected]", "type": "work", "primary": true } ], "active": true }

Response: 201 Created with the full User resource including the Auris-assigned id.

Get User

GET /scim/v2/Users/usr_abc123 Authorization: Bearer scim_token_here

Response: 200 OK with the full User resource.

List Users

GET /scim/v2/Users?filter=userName eq "[email protected]"&startIndex=1&count=10 Authorization: Bearer scim_token_here

Response: 200 OK with a ListResponse:

{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"], "totalResults": 1, "itemsPerPage": 10, "startIndex": 1, "Resources": [ { "id": "usr_abc123", "userName": "[email protected]", ... } ] }

Replace User (Full Update)

PUT /scim/v2/Users/usr_abc123 Content-Type: application/scim+json Authorization: Bearer scim_token_here { "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], "userName": "[email protected]", "name": { "givenName": "Jane", "familyName": "Smith" }, "active": true }

Response: 200 OK with the updated User resource.

Partial Update (PATCH)

SCIM PATCH uses a specific operation format defined in RFC 7644:

PATCH /scim/v2/Users/usr_abc123 Content-Type: application/scim+json Authorization: Bearer scim_token_here { "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], "Operations": [ { "op": "replace", "path": "active", "value": false }, { "op": "replace", "path": "name.familyName", "value": "Smith" } ] }

PATCH is the most common operation for deprovisioning: the IdP sends { "op": "replace", "path": "active", "value": false } to disable the user without deleting the record.

Delete User

DELETE /scim/v2/Users/usr_abc123 Authorization: Bearer scim_token_here

Response: 204 No Content. In Auris, DELETE performs a soft-disable (sets active: false) rather than permanent deletion, preserving audit trail integrity.

Filtering (RFC 7644 Section 3.4.2.2)

SCIM defines a filter expression syntax that allows IdPs to query for specific users. Auris implements a recursive descent parser for SCIM filter expressions.

Filter Operators

OperatorMeaningExample
eqEqualsuserName eq "[email protected]"
neNot equalsactive ne false
coContainsuserName co "jane"
swStarts withuserName sw "jane"
ewEnds withemails.value ew "@company.com"
prPresent (has value)title pr
gtGreater thanmeta.lastModified gt "2025-01-01T00:00:00Z"
ltLess thanmeta.created lt "2025-06-01T00:00:00Z"
geGreater than or equalmeta.lastModified ge "2025-01-01"
leLess than or equalmeta.created le "2025-12-31"

Compound Filters

Filters can be combined with and and or, and grouped with parentheses:

filter=userName eq "[email protected]" and active eq true filter=(department eq "Engineering") or (department eq "Product") filter=userName sw "j" and (active eq true or title pr)

Filter to Prisma Translation

Auris converts SCIM filter expressions to Prisma where clauses via a recursive parser:

SCIM filter: userName eq "[email protected]" and active eq true Parser: tokenize → build AST → convert to Prisma Prisma where: { AND: [ { scimUserName: { equals: "[email protected]" } }, { isEnabled: true } ] }

The parser (lib/scim/filter-parser.ts) handles operator precedence, parenthetical grouping, dot-notation attribute paths (e.g., name.familyName), and value type coercion (strings, booleans, numbers, dates).

SCIM filters operate on SCIM attribute names (e.g., userName, name.familyName), not on database column names. Auris maps SCIM attributes to Prisma fields via the attribute mapping configuration. If a filter references an unmapped attribute, the filter term is ignored (not rejected), following the SCIM specification’s guidance on best-effort filtering.

Pagination

SCIM uses 1-based index pagination (not cursor-based):

ParameterDescriptionDefault
startIndex1-based index of the first result to return1
countMaximum number of results per page100
totalResultsTotal number of matching resources (returned in response)
itemsPerPageActual number of resources in this page (returned in response)
GET /scim/v2/Users?startIndex=1&count=25 { "totalResults": 150, "itemsPerPage": 25, "startIndex": 1, "Resources": [ ... 25 users ... ] } GET /scim/v2/Users?startIndex=26&count=25 { "totalResults": 150, "itemsPerPage": 25, "startIndex": 26, "Resources": [ ... 25 users ... ] }

Bearer Token Authentication

SCIM endpoints in Auris are protected by bearer token authentication. Each SCIM connection has a unique token configured in the Auris Console.

GET /scim/v2/Users Authorization: Bearer scim_aBcDeFgHiJkLmNoPqRsTuVwXyZ123456

The token is validated against the ScimConnection model. Each connection is scoped to a specific tenant, so tokens from one tenant cannot access another tenant’s SCIM endpoints.

Security MeasureDescription
Token hashingTokens are stored as SHA-256 hashes, not plaintext
Tenant isolationEach token is bound to a specific tenant
Audit loggingEvery SCIM operation is logged with the connection ID
IP allowlistingOptional: restrict SCIM access to IdP source IPs via IP Rules

Auris SCIM Implementation

Architecture

Auris implements inbound SCIM provisioning: the IdP pushes user lifecycle changes to Auris. Auris does not pull from the IdP.

Dual Write: Auris + Keycloak

When a SCIM POST creates a user, Auris performs a dual write:

  1. Auris Database: Creates a TenantUser record with scimExternalId (the IdP’s identifier) and scimUserName (the IdP’s username)
  2. Keycloak: Creates a user in the tenant’s Keycloak realm with matching attributes

Both writes must succeed. If Keycloak creation fails, the Auris record is rolled back.

Attribute Mapping

SCIM attributes do not always map 1:1 to Auris fields. The ScimAttributeMapping model allows per-connection customization:

Mappings are configured per SCIM connection in the Auris Console (Integrations > SCIM > connection detail > Mappings tab). Each mapping has a direction: INBOUND (IdP to Auris), OUTBOUND (Auris to IdP, for future use), or BOTH.

Bulk Operations

Auris supports SCIM Bulk operations (RFC 7644 Section 3.7) for batch provisioning:

POST /scim/v2/Bulk Content-Type: application/scim+json Authorization: Bearer scim_token_here { "schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkRequest"], "Operations": [ { "method": "POST", "path": "/Users", "data": { "userName": "[email protected]", "name": { "givenName": "Alice", "familyName": "Johnson" }, "active": true } }, { "method": "POST", "path": "/Users", "data": { "userName": "[email protected]", "name": { "givenName": "Bob", "familyName": "Williams" }, "active": true } }, { "method": "PATCH", "path": "/Users/usr_old_employee", "data": { "Operations": [ { "op": "replace", "path": "active", "value": false } ] } } ] }

Response: Per-operation status codes

{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkResponse"], "Operations": [ { "method": "POST", "location": "/Users/usr_new1", "status": "201" }, { "method": "POST", "location": "/Users/usr_new2", "status": "201" }, { "method": "PATCH", "location": "/Users/usr_old_employee", "status": "200" } ] }

Auris enforces a maximum of 100 operations per bulk request. Each operation is processed independently — a failure in one operation does not prevent others from succeeding.

Bulk operations are especially useful during initial provisioning, when an IdP syncs its entire user directory to Auris for the first time. Without bulk support, this would require one HTTP request per user, which is impractical for directories with thousands of users.

User Lifecycle

The complete SCIM-driven user lifecycle looks like this:

The key benefit over manual provisioning is the deprovisioning speed. When an employee is terminated, the IdP admin removes their access in one place, and all connected applications (including Auris) disable the user within seconds. There is no “forgot to remove access from that one app” risk.

Comparison: Provisioning Approaches

DimensionSCIM 2.0Manual ProvisioningJIT ProvisioningLDAP Sync
Provisioning speedNear-real-time (seconds)Hours to daysOn first login onlyScheduled (minutes to hours)
Deprovisioning speedNear-real-time (seconds)Hours to days (if remembered)Never (no deprovisioning)Next sync cycle
Attribute syncReal-time pushManual updatesLogin-time onlyScheduled batch
Orphan account riskLow (automatic deprovisioning)High (human error)High (no deprovisioning)Medium (depends on sync frequency)
StandardizationRFC 7643/7644 (universal)Proprietary per appProprietary per IdPLDAP protocol (standardized)
IdP supportAll major IdPsN/AMost IdPs via SAML/OIDCRequires LDAP directory
Bulk operationsYes (RFC 7644 Section 3.7)N/AN/AYes (batch sync)
Network directionIdP pushes to SPAdmin manually actsUser initiatesSP pulls from directory
ComplianceExcellent audit trailPoor (manual tracking)Partial (no deprovision proof)Good (sync logs)
Implementation effortModerate (implement SCIM endpoints)None (manual work)Low (read IdP assertions)Moderate (LDAP client)

When to Use SCIM

  • Enterprise customers with centralized identity management (Okta, Azure AD, OneLogin)
  • Compliance requirements that mandate automated deprovisioning (SOC 2, ISO 27001, HIPAA)
  • Large user bases where manual provisioning is impractical
  • Multi-app environments where users need consistent access across many services

When JIT Provisioning Is Sufficient

  • Small teams where manual provisioning is manageable
  • Consumer-facing apps where users self-register
  • Apps where deprovisioning is not critical (read-only dashboards, public tools)

SCIM and JIT provisioning are not mutually exclusive. Many Auris tenants use SCIM for provisioning and deprovisioning (user lifecycle management) and JIT provisioning via SAML/OIDC for the actual login flow. SCIM ensures the user exists and is active; SSO handles the authentication.

Security Considerations

Bearer Token Management

SCIM bearer tokens are long-lived secrets that grant full provisioning access. Treat them with the same care as database credentials.

PracticeDescription
Rotate regularlyGenerate a new token and update the IdP configuration quarterly
Store securelyNever commit SCIM tokens to source control or logs
Monitor usageAuris logs every SCIM operation with the connection ID — review for unexpected patterns
Limit scopeEach SCIM connection is scoped to one tenant — a compromised token cannot affect other tenants

IP Allowlisting

For maximum security, restrict SCIM endpoint access to your IdP’s source IP ranges using Auris IP Rules:

IP Rule: ALLOW CIDR: 100.25.0.0/16 Label: "Okta US East" IP Rule: ALLOW CIDR: 100.26.0.0/16 Label: "Okta US West" IP Rule: BLOCK CIDR: 0.0.0.0/0 Label: "Block all other SCIM access"

This ensures that even if a SCIM token is compromised, it cannot be used from unauthorized networks.

Audit Logging

Every SCIM operation is logged in the Auris audit log with:

  • The SCIM connection ID
  • The HTTP method and path
  • The target user’s externalId and userName
  • The operation result (success/failure)
  • The source IP address
  • A timestamp

These logs are available in the Auris Console under Logs and can be streamed to external SIEM systems via Log Streaming.