SCIM 2.0 API
AuthOS implements SCIM 2.0 (System for Cross-domain Identity Management) for automated user and group provisioning from identity providers like Okta, Azure AD, and OneLogin.
Overview
SCIM enables identity providers to automatically:
- Provision new users when added to the directory
- Update user information when changed
- Deprovision users when removed or deactivated
- Manage group memberships and organization structure
Authentication
SCIM endpoints use Bearer token authentication with SCIM-specific tokens.
Creating a SCIM Token
POST /api/organizations/:org_slug/scim-tokens
Authorization: Bearer {org_admin_jwt}
Content-Type: application/json
{
"name": "Okta SCIM Integration",
"expires_at": "2026-12-31T23:59:59Z" // Optional
}
Response:
{
"id": "scim-token-id",
"name": "Okta SCIM Integration",
"token": "scim_live_abc123def456...", // Only shown once
"prefix": "scim_live_abc1",
"created_at": "2025-01-15T10:00:00Z",
"expires_at": "2026-12-31T23:59:59Z"
}
Important: The full token is only returned once during creation. Store it securely.
Using SCIM Tokens
All SCIM API requests must include the token in the Authorization header:
Authorization: Bearer scim_live_abc123def456...
Token Management
List SCIM Tokens:
GET /api/organizations/:org_slug/scim-tokens
Authorization: Bearer {org_admin_jwt}
Revoke SCIM Token:
DELETE /api/organizations/:org_slug/scim-tokens/:token_id
Authorization: Bearer {org_admin_jwt}
Base URL
All SCIM endpoints are prefixed with:
https://your-sso-platform.com/scim/v2
Users Resource
List Users
Endpoint: GET /scim/v2/Users
Retrieves users that are members of the organization associated with the SCIM token.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
startIndex |
integer | No | 1-based index of the first result (default: 1) |
count |
integer | No | Number of results per page (default: 100, max: 1000) |
filter |
string | No | SCIM filter expression |
Supported Filters:
| Filter Expression | Description |
|---|---|
userName eq "user@example.com" |
Exact email match |
userName co "example" |
Email contains substring |
userName sw "user" |
Email starts with substring |
userName ew "example.com" |
Email ends with substring |
Example Request:
curl -X GET "https://sso.example.com/scim/v2/Users?startIndex=1&count=100&filter=userName%20eq%20%22user@example.com%22" \
-H "Authorization: Bearer scim_live_abc123..."
Response:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 150,
"startIndex": 1,
"itemsPerPage": 100,
"Resources": [
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "user-id-123",
"externalId": null,
"meta": {
"resourceType": "User",
"created": "2025-01-10T08:30:00Z",
"lastModified": "2025-01-12T14:20:00Z",
"location": "https://sso.example.com/scim/v2/Users/user-id-123"
},
"userName": "user@example.com",
"name": {
"formatted": "user@example.com"
},
"displayName": "user@example.com",
"emails": [
{
"value": "user@example.com",
"type": "work",
"primary": true
}
],
"active": true
}
]
}
Get User
Endpoint: GET /scim/v2/Users/:id
Retrieves a specific user by ID.
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | User ID |
Example Request:
curl -X GET "https://sso.example.com/scim/v2/Users/user-id-123" \
-H "Authorization: Bearer scim_live_abc123..."
Response (200 OK):
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "user-id-123",
"meta": {
"resourceType": "User",
"created": "2025-01-10T08:30:00Z",
"lastModified": "2025-01-12T14:20:00Z",
"location": "https://sso.example.com/scim/v2/Users/user-id-123"
},
"userName": "user@example.com",
"emails": [
{
"value": "user@example.com",
"type": "work",
"primary": true
}
],
"active": true
}
Error Response (404 Not Found):
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": 404,
"detail": "User not found"
}
Create User
Endpoint: POST /scim/v2/Users
Creates a new user and adds them as a member of the organization.
Request Body:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "newuser@example.com",
"name": {
"givenName": "John",
"familyName": "Doe",
"formatted": "John Doe"
},
"displayName": "John Doe",
"emails": [
{
"value": "newuser@example.com",
"type": "work",
"primary": true
}
],
"active": true
}
Example Request:
curl -X POST "https://sso.example.com/scim/v2/Users" \
-H "Authorization: Bearer scim_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "newuser@example.com",
"emails": [{"value": "newuser@example.com", "type": "work", "primary": true}],
"active": true
}'
Response (201 Created):
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "user-id-456",
"meta": {
"resourceType": "User",
"created": "2025-01-15T10:00:00Z",
"lastModified": "2025-01-15T10:00:00Z",
"location": "https://sso.example.com/scim/v2/Users/user-id-456"
},
"userName": "newuser@example.com",
"emails": [
{
"value": "newuser@example.com",
"type": "work",
"primary": true
}
],
"active": true
}
Features:
- User automatically added to organization with
memberrole - Permissions granted via ReBAC system
- Welcome email job queued (processed asynchronously)
- Email verification not required for SCIM provisioning
Error Response (409 Conflict):
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": 409,
"scimType": "uniqueness",
"detail": "User with email newuser@example.com already exists"
}
Update User (PUT)
Endpoint: PUT /scim/v2/Users/:id
Replaces a user’s attributes.
Request Body:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "updated@example.com",
"emails": [
{
"value": "updated@example.com",
"type": "work",
"primary": true
}
],
"active": true
}
Example Request:
curl -X PUT "https://sso.example.com/scim/v2/Users/user-id-123" \
-H "Authorization: Bearer scim_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "updated@example.com",
"emails": [{"value": "updated@example.com", "type": "work", "primary": true}]
}'
Response (200 OK): Returns the updated user resource (same format as GET User).
Patch User (PATCH)
Endpoint: PATCH /scim/v2/Users/:id
Partially updates a user using SCIM PATCH operations.
Request Body:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "replace",
"path": "emails",
"value": [
{
"value": "newemail@example.com",
"type": "work",
"primary": true
}
]
},
{
"op": "replace",
"path": "active",
"value": false
}
]
}
Supported Operations:
| Operation | Path | Description |
|---|---|---|
replace |
emails |
Update user’s email address |
replace |
userName |
Update user’s username (email) |
replace |
active |
Activate/deactivate user (soft delete) |
Example: Deactivate User
curl -X PATCH "https://sso.example.com/scim/v2/Users/user-id-123" \
-H "Authorization: Bearer scim_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "replace",
"path": "active",
"value": false
}
]
}'
Deactivation Behavior:
- Sets
deleted_attimestamp (soft delete) - User cannot login
- Returns
active: falsein SCIM responses - User data preserved for compliance
Reactivation:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "replace",
"path": "active",
"value": true
}
]
}
Response (200 OK): Returns the updated user resource.
Delete User
Endpoint: DELETE /scim/v2/Users/:id
Permanently deletes a user from the system.
Example Request:
curl -X DELETE "https://sso.example.com/scim/v2/Users/user-id-123" \
-H "Authorization: Bearer scim_live_abc123..."
Response (204 No Content)
Warning: This permanently deletes the user. For deactivation without deletion, use PATCH with active: false.
Groups Resource
Groups in SCIM map to Organizations in AuthOS. Each SCIM token is scoped to a specific organization, so group operations affect that organization’s membership.
List Groups
Endpoint: GET /scim/v2/Groups
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
startIndex |
integer | No | 1-based index of the first result (default: 1) |
count |
integer | No | Number of results per page (default: 100, max: 1000) |
filter |
string | No | SCIM filter expression |
Supported Filters:
| Filter Expression | Description |
|---|---|
displayName eq "Acme Corp" |
Exact organization name match |
Example Request:
curl -X GET "https://sso.example.com/scim/v2/Groups" \
-H "Authorization: Bearer scim_live_abc123..."
Response (200 OK):
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 1,
"startIndex": 1,
"itemsPerPage": 100,
"Resources": [
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"id": "org-id-123",
"meta": {
"resourceType": "Group",
"created": "2025-01-01T00:00:00Z",
"lastModified": "2025-01-15T10:00:00Z",
"location": "https://sso.example.com/scim/v2/Groups/org-id-123"
},
"displayName": "Acme Corporation",
"members": [
{
"value": "user-id-123",
"$ref": "https://sso.example.com/scim/v2/Users/user-id-123",
"type": "User"
},
{
"value": "user-id-456",
"$ref": "https://sso.example.com/scim/v2/Users/user-id-456",
"type": "User"
}
]
}
]
}
Get Group
Endpoint: GET /scim/v2/Groups/:id
Example Request:
curl -X GET "https://sso.example.com/scim/v2/Groups/org-id-123" \
-H "Authorization: Bearer scim_live_abc123..."
Response (200 OK): Returns the group resource with all members.
Create Group
Endpoint: POST /scim/v2/Groups
Status: Not Implemented (501)
Group (Organization) creation via SCIM is not supported. Organizations must be created through the Organizations API.
Response (501 Not Implemented):
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": 501,
"detail": "Group creation via SCIM is not supported. Please use the Organizations API."
}
Update Group (PUT)
Endpoint: PUT /scim/v2/Groups/:id
Updates group membership by replacing the entire members list.
Request Body:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "Acme Corporation",
"members": [
{
"value": "user-id-123",
"type": "User"
},
{
"value": "user-id-789",
"type": "User"
}
]
}
Behavior:
- Adds new members not currently in the group
- Removes members not in the new list
- Grants/revokes permissions via ReBAC system
- All members receive
memberrole
Example Request:
curl -X PUT "https://sso.example.com/scim/v2/Groups/org-id-123" \
-H "Authorization: Bearer scim_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "Acme Corporation",
"members": [
{"value": "user-id-123"},
{"value": "user-id-789"}
]
}'
Response (200 OK): Returns the updated group resource with current members.
Patch Group (PATCH)
Endpoint: PATCH /scim/v2/Groups/:id
Partially updates group membership using SCIM PATCH operations.
Supported Operations:
| Operation | Description | Example Path |
|---|---|---|
add |
Add members to group | N/A (uses value) |
remove |
Remove specific member | members[value eq "user-id"] |
Example: Add Members
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "add",
"value": {
"members": [
{
"value": "user-id-new1"
},
{
"value": "user-id-new2"
}
]
}
}
]
}
Example: Remove Member
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "remove",
"path": "members[value eq \"user-id-123\"]"
}
]
}
Example Request:
curl -X PATCH "https://sso.example.com/scim/v2/Groups/org-id-123" \
-H "Authorization: Bearer scim_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "remove",
"path": "members[value eq \"user-id-456\"]"
}
]
}'
Response (200 OK): Returns the updated group resource.
Delete Group
Endpoint: DELETE /scim/v2/Groups/:id
Status: Forbidden (403)
Group (Organization) deletion via SCIM is not supported for security reasons. Organizations must be deleted through the Organizations API.
Response (403 Forbidden):
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": 403,
"detail": "Group deletion via SCIM is not supported. Please use the Organizations API."
}
Error Responses
The API returns SCIM-compliant error responses following RFC 7644 Section 3.12.
Error Format
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": 400,
"scimType": "invalidValue",
"detail": "Detailed error message"
}
Error Types
| HTTP Status | scimType | Description |
|---|---|---|
| 400 | invalidValue |
Invalid field value provided |
| 401 | N/A | Invalid or missing SCIM token |
| 404 | N/A | Resource not found |
| 409 | uniqueness |
Duplicate resource (e.g., email already exists) |
| 422 | invalidSyntax |
Malformed request body |
| 500 | N/A | Internal server error |
| 501 | N/A | Operation not implemented |
Common Errors
Invalid Authentication:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": 401,
"detail": "Invalid SCIM token"
}
User Already Exists:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": 409,
"scimType": "uniqueness",
"detail": "User with email user@example.com already exists"
}
Invalid Filter Syntax:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": 422,
"scimType": "invalidSyntax",
"detail": "Failed to parse request body: invalid JSON"
}
Compliance & Standards
The implementation follows:
- RFC 7643: SCIM Core Schema
- RFC 7644: SCIM Protocol Specification
- SCIM 2.0: Full compliance with SCIM 2.0 standard
Supported Features
✅ Users Resource: Full CRUD operations ✅ Groups Resource: Read and membership management ✅ Filtering: userName/email filters with operators (eq, co, sw, ew) ✅ Pagination: startIndex and count parameters ✅ PATCH Operations: Partial updates via PATCH ✅ Error Handling: SCIM-compliant error responses ✅ Bearer Token Auth: Secure SCIM token authentication
Limitations
❌ Schema Discovery: /Schemas and /ResourceTypes endpoints not implemented
❌ Bulk Operations: Bulk user/group operations not supported
❌ Search: Advanced filtering beyond basic userName filters
❌ Sorting: sortBy and sortOrder parameters not supported
❌ Attributes Selection: attributes and excludedAttributes not supported
❌ Group Creation/Deletion: Organizations managed via separate API
Integration Examples
Okta Configuration
-
Create SCIM token in AuthOS
-
In Okta Admin Console: Applications → Your App → Provisioning
-
Configure SCIM Connection:
- SCIM Base URL:
https://your-authos.com/scim/v2 - Unique Identifier:
userName - Supported Actions: Import Users, Push New Users, Push Profile Updates, Push Groups
- Authentication Mode: HTTP Header
- Authorization:
Bearer scim_live_your_token
- SCIM Base URL:
-
Enable Provisioning Features:
- ✅ Create Users
- ✅ Update User Attributes
- ✅ Deactivate Users
- ✅ Sync Password (Not applicable - AuthOS handles auth)
Azure AD Configuration
- Create SCIM token in AuthOS
- In Azure AD: Enterprise Applications → Your App → Provisioning
- Configure:
- Provisioning Mode: Automatic
- Tenant URL:
https://your-authos.com/scim/v2 - Secret Token:
scim_live_your_token
- Test Connection
- Configure Attribute Mappings
- Start Provisioning
OneLogin Configuration
- Create SCIM token in AuthOS
- In OneLogin: Applications → Your App → Provisioning
- Configure SCIM:
- SCIM Base URL:
https://your-authos.com/scim/v2 - SCIM Bearer Token:
scim_live_your_token - API Connection: SCIM 2.0
- SCIM Base URL:
- Enable provisioning operations
Security Considerations
-
Token Security:
- SCIM tokens are hashed using SHA256 before storage
- Tokens use constant-time comparison to prevent timing attacks
- Tokens should be rotated regularly
- Use HTTPS for all SCIM requests
-
Scope Isolation:
- Each SCIM token is scoped to a specific organization
- Users from other organizations are never visible
- Cross-organization access is strictly prevented
-
Soft Deletion:
active: falseperforms soft delete (setsdeleted_at)- Hard DELETE permanently removes user data
- Recommend using soft deletion for compliance
-
Audit Logging:
- All SCIM operations are logged
- Track token usage via
last_used_attimestamp - Monitor for suspicious activity
Testing SCIM Integration
Verify Token Authentication
curl -X GET "https://your-sso-platform.com/scim/v2/Users?count=1" \
-H "Authorization: Bearer scim_live_your_token" \
-v
Expected: 200 OK with users list
Test User Provisioning
# Create user
curl -X POST "https://your-sso-platform.com/scim/v2/Users" \
-H "Authorization: Bearer scim_live_your_token" \
-H "Content-Type: application/json" \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "test@example.com",
"emails": [{"value": "test@example.com", "primary": true}],
"active": true
}'
# Deactivate user
curl -X PATCH "https://your-sso-platform.com/scim/v2/Users/{id}" \
-H "Authorization: Bearer scim_live_your_token" \
-H "Content-Type: application/json" \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [{"op": "replace", "path": "active", "value": false}]
}'
Related Documentation
- SCIM Token Management API - Create and manage SCIM tokens
- User Management API - Direct user management endpoints
- Organizations API - Organization management
- Access Control Concepts - ReBAC permission system