SCIM 2.0 User Provisioning
Overview
The incident management platform includes a full SCIM 2.0 (System for Cross-domain Identity Management) server implementation that enables automated user provisioning and deprovisioning from external identity providers.
Supported Identity Providers:
- Okta
- Azure Active Directory
- Google Workspace
- Any SCIM 2.0 compliant system
Features
✅ SCIM 2.0 Compliant: Full compliance with RFC 7643 and RFC 7644
✅ User Provisioning: Create, read, update, delete, and search users
✅ Group Management: Complete group lifecycle with member synchronization
✅ PATCH Support: Efficient partial updates using SCIM PATCH operations
✅ Advanced Filtering: SCIM filter syntax with complex queries
✅ Pagination: Support for large datasets with startIndex/count
✅ Bearer Token Auth: Secure API access with service account tokens
✅ Rate Limiting: Configurable per-service-account limits
✅ Audit Logging: Complete audit trail of all SCIM operations
✅ Enterprise Extension: Support for enterprise user attributes
Quick Start
Step 1: Create SCIM Service Account
Generate an API token for your identity provider to authenticate SCIM requests:
Using the Web Interface
- Navigate to Settings → SCIM Configuration
- Click “Create Service Account”
- Enter name:
Okta Integration - Enter description:
Okta SCIM provisioning - Copy the generated token (shown only once)
Using the CLI
# Create service account
./im scim create-account --name "Okta Integration" --description "Okta SCIM provisioning"
# Output includes the bearer token
✓ Service account created: scim-okta-integration
🔑 Bearer token: scim-b3f8a9d2c4e6f1a7b9d2c4e6f1a7b9d2c4e6f1a7
⚠️ Save this token securely - it will not be shown againUsing the API
curl -X POST http://localhost:8080/api/v1/scim/service-accounts \
-H "Authorization: Bearer <admin-jwt-token>" \
-H "Content-Type: application/json" \
-d '{
"name": "okta-integration",
"description": "Okta SCIM provisioning"
}'Step 2: Configure Your Identity Provider
Use these settings in your identity provider’s SCIM configuration:
| Setting | Value |
|---|---|
| SCIM Base URL | https://your-domain.com/scim/v2 |
| Authentication | Bearer Token |
| Bearer Token | Token from Step 1 |
| User Schema | SCIM 2.0 Core Schema |
| Supported Operations | Create, Update, Delete, Import |
Step 3: Test the Connection
Most identity providers have a “Test Connection” feature that:
- Fetches
/scim/v2/ServiceProviderConfig - Lists users with
/scim/v2/Users - Validates the authentication token
# Test manually with curl
curl -X GET https://your-domain.com/scim/v2/ServiceProviderConfig \
-H "Authorization: Bearer <scim-token>"
# Should return 200 OK with server capabilitiesIdentity Provider Setup
Okta Configuration
-
Create App Integration:
- In Okta Admin Console: Applications → Create App Integration
- Choose “SWA - Secure Web Authentication”
-
Configure Provisioning:
- Provisioning tab → Configure API Integration
- SCIM connector base URL:
https://your-domain.com/scim/v2 - Unique identifier field:
userName - Supported operations: Create User, Update User Attributes, Deactivate User
- Authentication: Bearer Token
- Bearer Token: Your SCIM service account token
-
Attribute Mappings:
Okta Attribute → SCIM Attribute user.login → userName user.email → emails[type eq "work"].value user.firstName → name.givenName user.lastName → name.familyName user.displayName → displayName user.status → active -
Test and Enable:
- Click “Test API Credentials”
- Enable provisioning: To App and To Okta
- Assign users or groups to the application
Azure AD Configuration
-
Create Enterprise Application:
- Azure Portal → Enterprise Applications → New Application
- Create your own application → Non-gallery application
-
Configure Provisioning:
- Provisioning section → Automatic
- Tenant URL:
https://your-domain.com/scim/v2 - Secret Token: Your SCIM service account token
- Test Connection → Save
-
Attribute Mappings:
{ "userPrincipalName": "userName", "mail": "emails[type eq \"work\"].value", "givenName": "name.givenName", "surname": "name.familyName", "displayName": "displayName", "accountEnabled": "active" } -
Scope and Filters:
- Set provisioning scope (all users or assigned users)
- Configure filters if needed
- Start provisioning cycle
Google Workspace Configuration
-
Create Custom SAML App:
- Google Admin Console → Apps → Web and mobile apps
- Add custom SAML app
-
Configure User Provisioning:
- User provisioning section
- SCIM endpoint:
https://your-domain.com/scim/v2 - Authorization: Bearer token
- Token: Your SCIM service account token
-
Field Mappings:
- Primary email → emails[type eq “work”].value
- First name → name.givenName
- Last name → name.familyName
- Full name → displayName
- Username → userName
- Suspended → active (inverted)
API Reference
Service Provider Configuration
GET /scim/v2/ServiceProviderConfig
Returns server capabilities and supported features.
curl -X GET https://your-domain.com/scim/v2/ServiceProviderConfig \
-H "Authorization: Bearer <scim-token>"Response:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"],
"patch": { "supported": true },
"bulk": { "supported": false },
"filter": {
"supported": true,
"maxResults": 1000
},
"changePassword": { "supported": false },
"sort": { "supported": false },
"etag": { "supported": true },
"authenticationSchemes": [
{
"type": "oauthbearertoken",
"name": "OAuth Bearer Token",
"description": "Authentication using OAuth 2.0 Bearer Token"
}
]
}User Management
Create User
curl -X POST https://your-domain.com/scim/v2/Users \
-H "Authorization: Bearer <scim-token>" \
-H "Content-Type: application/scim+json" \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "john.doe",
"name": {
"givenName": "John",
"familyName": "Doe"
},
"emails": [{
"value": "john.doe@example.com",
"type": "work",
"primary": true
}],
"displayName": "John Doe",
"active": true
}'Get User
curl -X GET https://your-domain.com/scim/v2/Users/{id} \
-H "Authorization: Bearer <scim-token>"Update User (Full Replace)
curl -X PUT https://your-domain.com/scim/v2/Users/{id} \
-H "Authorization: Bearer <scim-token>" \
-H "Content-Type: application/scim+json" \
-H "If-Match: <etag>" \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "{id}",
"userName": "john.doe",
"active": false
}'Patch User (Partial Update)
curl -X PATCH https://your-domain.com/scim/v2/Users/{id} \
-H "Authorization: Bearer <scim-token>" \
-H "Content-Type: application/scim+json" \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "replace",
"path": "active",
"value": false
},
{
"op": "add",
"path": "emails",
"value": [{
"value": "john.doe@newdomain.com",
"type": "work"
}]
}
]
}'Delete User
curl -X DELETE https://your-domain.com/scim/v2/Users/{id} \
-H "Authorization: Bearer <scim-token>"Search Users
# List all users with pagination
curl -X GET "https://your-domain.com/scim/v2/Users?startIndex=1&count=10" \
-H "Authorization: Bearer <scim-token>"
# Filter by username
curl -X GET 'https://your-domain.com/scim/v2/Users?filter=userName eq "john.doe"' \
-H "Authorization: Bearer <scim-token>"
# Complex filter
curl -X GET 'https://your-domain.com/scim/v2/Users?filter=(active eq true) and (emails[type eq "work"].value ew "@example.com")' \
-H "Authorization: Bearer <scim-token>"Group Management
Create Group
curl -X POST https://your-domain.com/scim/v2/Groups \
-H "Authorization: Bearer <scim-token>" \
-H "Content-Type: application/scim+json" \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "Engineering Team",
"members": [{
"value": "{user-id}",
"display": "John Doe"
}]
}'Update Group Members
curl -X PATCH https://your-domain.com/scim/v2/Groups/{id} \
-H "Authorization: Bearer <scim-token>" \
-H "Content-Type: application/scim+json" \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "add",
"path": "members",
"value": [{
"value": "{user-id}",
"display": "Jane Smith"
}]
},
{
"op": "remove",
"path": "members[value eq \"{user-id}\"]"
}
]
}'Filtering and Search
Supported Operators
| Operator | Description | Example |
|---|---|---|
eq |
Equals | userName eq "john.doe" |
ne |
Not equals | active ne false |
co |
Contains | name.givenName co "John" |
sw |
Starts with | emails[type eq "work"].value sw "john" |
ew |
Ends with | emails[type eq "work"].value ew "@example.com" |
gt |
Greater than | meta.created gt "2023-01-01T00:00:00Z" |
lt |
Less than | meta.lastModified lt "2024-01-01T00:00:00Z" |
pr |
Present (not null) | displayName pr |
Logical Operators
and- Logical ANDor- Logical ORnot- Logical NOT
Complex Filter Examples
# Active users with work email at specific domain
filter=(active eq true) and (emails[type eq "work"].value ew "@company.com")
# Users created in last month with display name
filter=(meta.created gt "2025-07-01T00:00:00Z") and (displayName pr)
# Users in specific groups
filter=groups[display eq "Engineering"] or groups[display eq "DevOps"]Enterprise User Extension
Support for additional enterprise attributes:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],
"userName": "john.doe",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
"employeeNumber": "12345",
"costCenter": "CC100",
"organization": "ACME Corp",
"division": "Engineering",
"department": "Platform Team",
"manager": {
"value": "{manager-user-id}",
"displayName": "Jane Manager"
}
}
}Security & Compliance
Authentication
- Bearer Token: All SCIM requests require valid bearer token
- Token Rotation: Service account tokens can be regenerated
- Per-Account Tokens: Each identity provider has separate token
- Token Validation: Tokens validated on every request
Rate Limiting
- Default Limit: 1000 requests per minute per service account
- Configurable: Adjustable per service account
- Headers: Rate limit status in response headers
- Backoff: 429 responses include Retry-After header
Audit Logging
Every SCIM operation is logged with:
- Timestamp: When the operation occurred
- Service Account: Which account performed the operation
- Operation: Type of operation (CREATE, UPDATE, DELETE)
- Resource: Affected user or group
- Status: Success/failure status code
- Source IP: Request origin
- Changes: What was modified (for updates)
Example audit log entry:
{
"timestamp": "2025-08-23T15:30:00Z",
"service_account": "okta-integration",
"operation": "USER_UPDATE",
"resource_id": "user-12345",
"status_code": 200,
"source_ip": "203.0.113.10",
"changes": {
"active": { "from": true, "to": false },
"name.familyName": { "from": "Smith", "to": "Johnson" }
}
}Data Protection
- Field Redaction: Sensitive fields redacted in logs
- Encryption: All data encrypted at rest and in transit
- Retention: Configurable audit log retention periods
- Compliance: GDPR and SOC 2 compliant logging
Troubleshooting
Common Issues
Connection Test Failures
Symptoms: Identity provider can’t connect to SCIM endpoint
Solutions:
# Verify token is correct
curl -I https://your-domain.com/scim/v2/Users \
-H "Authorization: Bearer <token>"
# Should return 200 OK
# Check service account status
./im scim list-accounts
# Regenerate token if needed
./im scim regenerate-token --account okta-integrationUser Creation Failures
Symptoms: 400 Bad Request or 409 Conflict errors
Solutions:
# Check required fields
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "required",
"emails": [{"value": "required", "type": "work"}]
}
# Check for username conflicts
curl -X GET 'https://your-domain.com/scim/v2/Users?filter=userName eq "conflicting-username"' \
-H "Authorization: Bearer <token>"Rate Limit Exceeded
Symptoms: 429 Too Many Requests responses
Solutions:
# Check current rate limits
./im scim account-status --account okta-integration
# Adjust rate limits
./im scim update-limits --account okta-integration --requests-per-minute 2000
# Implement retry logic in IdP with exponential backoffDebug Mode
Enable detailed logging for troubleshooting:
# Set environment variable
export SCIM_DEBUG=true
# Or in configuration file
{
"scim": {
"debug": true,
"log_requests": true,
"log_responses": true
}
}Monitoring
Key Metrics
- Request rate per service account
- Error rate by operation type (CREATE, UPDATE, DELETE)
- Authentication failure rate
- Response time percentiles
Health Checks
# Overall SCIM endpoint health
curl https://your-domain.com/health/scim
# Specific service account health
curl https://your-domain.com/api/v1/scim/service-accounts/{account-id}/health \
-H "Authorization: Bearer <admin-token>"Advanced Configuration
Custom Attributes
Extend user schema with custom attributes:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", "urn:ietf:params:scim:schemas:extension:custom:2.0:User"],
"userName": "john.doe",
"urn:ietf:params:scim:schemas:extension:custom:2.0:User": {
"badgeId": "12345",
"location": "New York",
"timeZone": "America/New_York",
"role": "Senior Engineer"
}
}Webhooks
Receive notifications when users are provisioned/deprovisioned:
# Configure webhook URL
./im scim set-webhook --account okta-integration \
--url https://your-webhook-endpoint.com/scim-events
# Webhook payload example
{
"event_type": "user.created",
"timestamp": "2025-08-23T15:30:00Z",
"service_account": "okta-integration",
"user": {
"id": "user-12345",
"userName": "john.doe",
"active": true
}
}Best Practices
Identity Provider Configuration
- Use dedicated service accounts for each identity provider
- Set appropriate rate limits based on user volume
- Enable audit logging for compliance requirements
- Test thoroughly in staging before production deployment
User Lifecycle Management
- Map all required attributes (userName, emails are required)
- Handle deactivation properly (set active=false, don’t delete)
- Use groups for role-based access control
- Monitor synchronization for failures or delays
Security
- Rotate tokens regularly (quarterly recommended)
- Use HTTPS only for all SCIM communication
- Monitor for unusual patterns in audit logs
- Restrict source IPs if possible (identity provider webhooks)
Performance
- Batch operations when possible via group membership
- Use pagination for large user lists
- Implement retry logic with exponential backoff
- Monitor response times and adjust rate limits accordingly
Integration with Incident Management
Once SCIM provisioning is configured, users are automatically:
- Created in the incident management platform
- Added to groups based on IdP group membership
- Assigned permissions via group-based access control
- Synchronized for profile updates and deactivation
This enables seamless user experience where team members can:
- Log in with corporate credentials
- Access incidents based on team membership
- Have appropriate permissions automatically assigned
- Be automatically deprovisioned when leaving the organization
SCIM 2.0 integration provides the foundation for enterprise-scale user management in your incident response platform.