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

  1. Navigate to SettingsSCIM Configuration
  2. Click “Create Service Account”
  3. Enter name: Okta Integration
  4. Enter description: Okta SCIM provisioning
  5. 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 again

Using 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:

  1. Fetches /scim/v2/ServiceProviderConfig
  2. Lists users with /scim/v2/Users
  3. 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 capabilities

Identity Provider Setup

Okta Configuration

  1. Create App Integration:

    • In Okta Admin Console: ApplicationsCreate App Integration
    • Choose “SWA - Secure Web Authentication”
  2. 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
  3. 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
  4. Test and Enable:

    • Click “Test API Credentials”
    • Enable provisioning: To App and To Okta
    • Assign users or groups to the application

Azure AD Configuration

  1. Create Enterprise Application:

    • Azure PortalEnterprise ApplicationsNew Application
    • Create your own applicationNon-gallery application
  2. Configure Provisioning:

    • Provisioning section → Automatic
    • Tenant URL: https://your-domain.com/scim/v2
    • Secret Token: Your SCIM service account token
    • Test ConnectionSave
  3. Attribute Mappings:

    {
      "userPrincipalName": "userName",
      "mail": "emails[type eq \"work\"].value",
      "givenName": "name.givenName",
      "surname": "name.familyName",
      "displayName": "displayName",
      "accountEnabled": "active"
    }
  4. Scope and Filters:

    • Set provisioning scope (all users or assigned users)
    • Configure filters if needed
    • Start provisioning cycle

Google Workspace Configuration

  1. Create Custom SAML App:

    • Google Admin ConsoleAppsWeb and mobile apps
    • Add custom SAML app
  2. Configure User Provisioning:

    • User provisioning section
    • SCIM endpoint: https://your-domain.com/scim/v2
    • Authorization: Bearer token
    • Token: Your SCIM service account token
  3. 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}\"]"
      }
    ]
  }'

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 AND
  • or - Logical OR
  • not - 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-integration

User 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 backoff

Debug 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.