SCIM Provisioning
UniAuth supports SCIM 2.0 (System for Cross-domain Identity Management) for automated user provisioning and deprovisioning. Connect your existing identity provider — such as Okta, Azure AD, or OneLogin — to automatically sync users into UniAuth when they join or leave your organization.
Note: SCIM provisioning is an enterprise feature tied to OAuth clients. Each OAuth client can have its own SCIM endpoint with an independent bearer token for authentication.
Setup
To enable SCIM provisioning for an OAuth client:
- Navigate to Admin Panel → OAuth Clients
- Select the client you want to enable SCIM for
- Under the SCIM tab, click Enable SCIM
- A bearer token is generated automatically. Copy and store it securely — it is only shown once.
- Configure your external IdP with the SCIM base URL and bearer token
You can also generate a SCIM token programmatically:
POST /api/admin/webhooks/scim-token
Content-Type: application/json
Authorization: Bearer <admin-session-token>
{
"client_id": "your-oauth-client-id"
}Base URL
All SCIM endpoints are served under:
https://uniauth.id/api/scim/v2When configuring your IdP, use this as the SCIM connector base URL.
Authentication
All SCIM requests must include a bearer token in the Authorization header:
Authorization: Bearer scim_abc123def456...Tokens are scoped to a specific OAuth client and can be revoked or rotated from the admin panel.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /api/scim/v2/Users | List users (with filter and pagination) |
POST | /api/scim/v2/Users | Create a new user |
GET | /api/scim/v2/Users/:id | Get a single user |
PUT | /api/scim/v2/Users/:id | Replace a user (full update) |
PATCH | /api/scim/v2/Users/:id | Update specific user attributes |
DELETE | /api/scim/v2/Users/:id | Deactivate a user |
GET | /api/scim/v2/ServiceProviderConfig | SCIM service provider capabilities |
GET | /api/scim/v2/Schemas | Supported SCIM schema definitions |
GET | /api/scim/v2/ResourceTypes | Available SCIM resource types |
User Schema Mapping
SCIM attributes are mapped to UniAuth user fields as follows:
| SCIM Attribute | UniAuth Field | Notes |
|---|---|---|
userName | email | Must be a valid email address |
name.givenName | first_name | |
name.familyName | last_name | |
displayName | display_name | Falls back to givenName + familyName |
active | email_verified | Deactivated users cannot log in |
title | job_title | |
locale | locale | BCP47 language tag (e.g., en-US) |
timezone | timezone | IANA timezone (e.g., America/New_York) |
addresses[0] | address | OIDC structured address (JSONB) |
Example: Create User
POST /api/scim/v2/Users
Content-Type: application/json
Authorization: Bearer scim_abc123def456...
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "[email protected]",
"name": {
"givenName": "Jane",
"familyName": "Doe"
},
"displayName": "Jane Doe",
"active": true,
"title": "Software Engineer",
"locale": "en-US",
"timezone": "America/New_York"
}Example: Response
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "550e8400-e29b-41d4-a716-446655440000",
"userName": "[email protected]",
"name": {
"givenName": "Jane",
"familyName": "Doe"
},
"displayName": "Jane Doe",
"active": true,
"title": "Software Engineer",
"locale": "en-US",
"timezone": "America/New_York",
"meta": {
"resourceType": "User",
"created": "2026-02-26T14:30:00.000Z",
"lastModified": "2026-02-26T14:30:00.000Z",
"location": "https://uniauth.id/api/scim/v2/Users/550e8400-e29b-41d4-a716-446655440000"
}
}Filtering
The GET /api/scim/v2/Users endpoint supports SCIM filtering via the filter query parameter. Supported operators:
eq— Equalco— Containssw— Starts with
Filter Examples
# Find user by exact email
GET /api/scim/v2/Users?filter=userName eq "[email protected]"
# Search by display name (contains)
GET /api/scim/v2/Users?filter=displayName co "Jane"
# Find users whose name starts with "J"
GET /api/scim/v2/Users?filter=name.givenName sw "J"Pagination
List endpoints support pagination with startIndex and count parameters. The maximum page size is 100.
GET /api/scim/v2/Users?startIndex=1&count=25The response includes pagination metadata:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 142,
"startIndex": 1,
"itemsPerPage": 25,
"Resources": [...]
}Provisioning from Okta
To set up SCIM provisioning from Okta:
- In Okta, go to Applications → Create App Integration
- Select SCIM 2.0 as the provisioning method
- Set the SCIM connector base URL to
https://uniauth.id/api/scim/v2 - Set the authentication mode to HTTP Header
- Paste your UniAuth SCIM bearer token
- Enable the desired provisioning features: Create Users, Update User Attributes, Deactivate Users
- Assign users or groups to the application to begin provisioning
Provisioning from Azure AD
To set up SCIM provisioning from Microsoft Entra ID (Azure AD):
- In the Azure portal, go to Enterprise Applications → New Application
- Create a non-gallery application
- Under Provisioning, set the mode to Automatic
- Set the Tenant URL to
https://uniauth.id/api/scim/v2 - Set the Secret Token to your UniAuth SCIM bearer token
- Click Test Connection to verify connectivity
- Configure attribute mappings (the defaults generally work with UniAuth's schema)
- Assign users or groups and start provisioning
Note: SCIM provisioning creates users without passwords. Users provisioned via SCIM can set a password through the forgot-password flow, or log in via SSO through your IdP.
Error Responses
SCIM error responses follow the standard SCIM error schema. Every error includes a schemas array, a numeric status, an optional scimType, and a human-readable detail message.
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": "400",
"scimType": "invalidValue",
"detail": "Missing required attribute: userName"
}| Status | scimType | Description |
|---|---|---|
400 | invalidValue | Invalid or missing attribute value. Check that all required fields are present and correctly formatted. |
400 | invalidFilter | Malformed filter expression. Check the filter syntax against supported operators (eq, co, sw). |
401 | — | Authentication failed. The bearer token is missing, expired, or invalid. |
404 | — | User not found. The specified user ID does not exist or has been deleted. |
409 | uniqueness | A user with the same userName (email) already exists. Use the existing user or update their attributes instead. |
Groups
Note: Group provisioning is not currently supported. Only User resources are available through the SCIM API. If your IdP pushes group assignments, they will be acknowledged but not processed. Role assignment for users should be managed through the UniAuth admin panel or admin API.
Deactivation vs Deletion
There are two ways to remove a user's access through SCIM, with different outcomes:
| Action | Method | Effect |
|---|---|---|
| Deactivate | PATCH /Users/:id with {"active": false} | Preserves the user account and all associated data. The user cannot log in until reactivated. Existing sessions are terminated. Use this for temporary offboarding or leave of absence. |
| Delete | DELETE /Users/:id | Permanently removes the user and all associated data including sessions, passkeys, OAuth tokens, activity logs, and 2FA configurations. This action cannot be undone. |
# Deactivate a user (soft removal)
PATCH /api/scim/v2/Users/550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json
Authorization: Bearer scim_abc123def456...
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "replace",
"path": "active",
"value": false
}
]
}Pagination Details
The list users endpoint supports pagination to handle large user directories efficiently.
- Default page size: 20 users per page
- Maximum page size: 100 users per page (requests exceeding this are capped)
- startIndex: 1-based (the first user is at index 1, not 0)
- totalResults: Reflects the total number of users matching the current filter, not just the current page
# Page through all users, 50 at a time
GET /api/scim/v2/Users?startIndex=1&count=50 # Page 1 (users 1-50)
GET /api/scim/v2/Users?startIndex=51&count=50 # Page 2 (users 51-100)
GET /api/scim/v2/Users?startIndex=101&count=50 # Page 3 (users 101-150)Continue paginating until startIndex + itemsPerPage exceeds totalResults, or until the Resources array is empty.