SCIM 2.0 API

SCIM 2.0 provisioning API for automated user and group management

Updated Dec 16, 2025
Edit on GitHub

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 member role
  • 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_at timestamp (soft delete)
  • User cannot login
  • Returns active: false in 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 member role

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

  1. Create SCIM token in AuthOS

  2. In Okta Admin Console: Applications → Your App → Provisioning

  3. 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
  4. Enable Provisioning Features:

    • ✅ Create Users
    • ✅ Update User Attributes
    • ✅ Deactivate Users
    • ✅ Sync Password (Not applicable - AuthOS handles auth)

Azure AD Configuration

  1. Create SCIM token in AuthOS
  2. In Azure AD: Enterprise Applications → Your App → Provisioning
  3. Configure:
    • Provisioning Mode: Automatic
    • Tenant URL: https://your-authos.com/scim/v2
    • Secret Token: scim_live_your_token
  4. Test Connection
  5. Configure Attribute Mappings
  6. Start Provisioning

OneLogin Configuration

  1. Create SCIM token in AuthOS
  2. In OneLogin: Applications → Your App → Provisioning
  3. Configure SCIM:
    • SCIM Base URL: https://your-authos.com/scim/v2
    • SCIM Bearer Token: scim_live_your_token
    • API Connection: SCIM 2.0
  4. Enable provisioning operations

Security Considerations

  1. 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
  2. Scope Isolation:

    • Each SCIM token is scoped to a specific organization
    • Users from other organizations are never visible
    • Cross-organization access is strictly prevented
  3. Soft Deletion:

    • active: false performs soft delete (sets deleted_at)
    • Hard DELETE permanently removes user data
    • Recommend using soft deletion for compliance
  4. Audit Logging:

    • All SCIM operations are logged
    • Track token usage via last_used_at timestamp
    • 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}]
  }'