SSO / SCIM
SAML-based single sign-on and SCIM 2.0 user/group provisioning.
Base paths: /api/sso (SSO), /api/scim (SCIM)
Plan requirement: Enterprise plan required for all configuration and management endpoints.
SSO Endpoints
Initiate SAML Login
GET /api/sso/saml/login
Authentication: None
Redirects the user to the organization's configured SAML Identity Provider for authentication.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
orgId | string | Yes | Organization ID to look up SSO configuration |
Errors
| Status | Error | Description |
|---|---|---|
| 400 | orgId is required | Missing query parameter |
| 404 | SSO not configured for this organization | No enabled SSO config found |
Example
curl "https://api.controlinfra.com/api/sso/saml/login?orgId=ORG_ID"SAML Assertion Callback
POST /api/sso/saml/callback
Authentication: None (SAML assertion verification)
Handles the SAML assertion from the Identity Provider. Creates or finds the user, adds them to the organization if not already a member, and redirects to the frontend with an exchange code.
On success, redirects to: {FRONTEND_URL}/auth/callback?code={code}
On failure, redirects to: {FRONTEND_URL}/auth/error?reason={reason}
Get SSO Configuration
GET /api/sso/config
Authentication: Bearer token | Role: Admin | Permission: integrations:write | Plan: Enterprise
Returns the current SSO configuration for the organization. The SAML certificate is masked in the response.
Response
{
"configured": true,
"config": {
"provider": "okta",
"saml": {
"entryPoint": "https://idp.example.com/sso/saml",
"issuer": "https://api.controlinfra.com",
"cert": "****"
},
"enforcedDomains": ["example.com"],
"defaultRole": "member",
"enabled": true
}
}If not configured: { "configured": false }
Example
curl -H "Authorization: Bearer TOKEN" \
-H "x-org-id: ORG_ID" \
https://api.controlinfra.com/api/sso/configUpdate SSO Configuration
PUT /api/sso/config
Authentication: Bearer token | Role: Admin | Permission: integrations:write | Plan: Enterprise
Create or update the SSO configuration. Performs an upsert.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
provider | string | No | IdP name (e.g. okta, azure_ad, custom). Default: custom |
saml.entryPoint | string | Yes | IdP SSO URL |
saml.issuer | string | Yes | SP entity ID / issuer |
saml.cert | string | Yes | IdP signing certificate (PEM, without headers) |
saml.signatureAlgorithm | string | No | Signature algorithm. Default: sha256 |
saml.wantAuthnResponseSigned | boolean | No | Require signed responses. Default: true |
enforcedDomains | string[] | No | Email domains that must use SSO |
defaultRole | string | No | Role assigned to new SSO users. Default: member |
enabled | boolean | No | Enable/disable SSO. Default: false |
Example
curl -X PUT https://api.controlinfra.com/api/sso/config \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-H "x-org-id: ORG_ID" \
-d '{
"provider": "okta",
"saml": {
"entryPoint": "https://idp.example.com/sso/saml",
"issuer": "https://api.controlinfra.com",
"cert": "MIIC..."
},
"enforcedDomains": ["example.com"],
"enabled": true
}'Delete SSO Configuration
DELETE /api/sso/config
Authentication: Bearer token | Role: Admin | Permission: integrations:write | Plan: Enterprise
Remove the SSO configuration entirely. Users who were provisioned via SSO retain their accounts but must use another login method.
Response
{ "success": true }SCIM 2.0 Protocol Endpoints
All SCIM protocol endpoints use bearer token authentication with a SCIM token (generated via the token management endpoints below). Responses use Content-Type: application/scim+json.
Base path: /api/scim/v2
Discovery
| Method | Endpoint | Description |
|---|---|---|
| GET | /v2/ServiceProviderConfig | SCIM service provider capabilities |
| GET | /v2/ResourceTypes | Supported resource types (User, Group) |
| GET | /v2/Schemas | SCIM schema definitions |
Users
| Method | Endpoint | Description |
|---|---|---|
| GET | /v2/Users | List users (supports filter, pagination) |
| POST | /v2/Users | Provision a new user |
| GET | /v2/Users/:id | Get a single user |
| PUT | /v2/Users/:id | Full user replacement |
| PATCH | /v2/Users/:id | Partial update (activate/deactivate) |
| DELETE | /v2/Users/:id | Remove user from organization |
List Users Query Parameters
| Parameter | Type | Description |
|---|---|---|
startIndex | integer | 1-based start index (default: 1) |
count | integer | Page size, max 200 (default: 100) |
filter | string | SCIM filter (e.g. userName eq "user@example.com") |
Create User — Key Fields
| Field | Type | Required | Description |
|---|---|---|---|
userName | string | Yes | User email address |
displayName | string | No | Display name |
name.givenName | string | No | First name |
name.familyName | string | No | Last name |
externalId | string | No | External identifier from IdP |
Supports the urn:ietf:params:scim:schemas:extension:enterprise:2.0:User extension (employeeNumber, department, manager).
Groups
| Method | Endpoint | Description |
|---|---|---|
| GET | /v2/Groups | List groups (supports filter, pagination) |
| POST | /v2/Groups | Create a group |
| GET | /v2/Groups/:id | Get a single group |
| PUT | /v2/Groups/:id | Full group replacement |
| PATCH | /v2/Groups/:id | Partial update (add/remove members) |
| DELETE | /v2/Groups/:id | Delete a group |
Bulk Operations
POST /api/scim/v2/Bulk
Authentication: SCIM bearer token
Process up to 100 User and Group CRUD operations in a single request. Each operation specifies method, path (e.g. /Users, /Groups/:id), optional bulkId, and data.
SCIM Token Management
These endpoints are called from the frontend Settings UI (not by IdPs).
Authentication: Bearer JWT | Role: Admin | Permission: integrations:write | Plan: Enterprise
List Tokens
GET /api/scim/tokens
Response
{
"tokens": [
{ "id": "...", "label": "Okta SCIM", "prefix": "a1b2c3d4", "createdAt": "...", "lastUsedAt": "..." }
]
}Generate Token
POST /api/scim/tokens
| Field | Type | Required | Description |
|---|---|---|---|
label | string | No | Token label. Default: SCIM Token |
Response (token shown only once)
{
"id": "...",
"label": "Okta SCIM",
"token": "a1b2c3d4e5f6...",
"createdAt": "2026-01-15T00:00:00.000Z"
}Revoke Token
DELETE /api/scim/tokens/:id
Response
{ "message": "Token revoked" }SCIM Group Mapping
Map SCIM groups to organization roles. When group membership changes, member roles are automatically synced (highest-privilege group wins).
Authentication: Bearer JWT | Role: Admin | Permission: integrations:write | Plan: Enterprise
List Group Mappings
GET /api/scim/groups
Response
{
"groups": [
{ "id": "...", "displayName": "Engineers", "memberCount": 5, "mappedRole": "member", "mappedCustomRoleId": null }
]
}Update Group Mapping
PATCH /api/scim/groups/:id/mapping
| Field | Type | Required | Description |
|---|---|---|---|
mappedRole | string | No | Role to assign: admin, member, or viewer |
mappedCustomRoleId | string | No | Custom RBAC role ID (or null to clear) |
Response
{
"id": "...",
"displayName": "Engineers",
"mappedRole": "admin",
"mappedCustomRoleId": null
}