From 60cfa6cb764b41e8d1a39dc57b9ee891d60d49f2 Mon Sep 17 00:00:00 2001 From: Lars Date: Thu, 30 Jan 2025 09:07:28 +0100 Subject: [PATCH] docs: scim v2 interface (#9246) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Which Problems Are Solved - Lack of documentation for the SCIM v2 interface # How the Problems Are Solved - Introduced a new documentation page detailing the SCIM v2 interface # Additional Context Part of #8140 --------- Co-authored-by: Fabienne Bühler --- docs/docs/apis/scim2.md | 868 ++++++++++++++++++++++++++ docs/docs/guides/manage/user/scim2.md | 127 ++++ docs/sidebars.js | 9 + 3 files changed, 1004 insertions(+) create mode 100644 docs/docs/apis/scim2.md create mode 100644 docs/docs/guides/manage/user/scim2.md diff --git a/docs/docs/apis/scim2.md b/docs/docs/apis/scim2.md new file mode 100644 index 0000000000..10afbb2c5c --- /dev/null +++ b/docs/docs/apis/scim2.md @@ -0,0 +1,868 @@ +--- +title: SCIM v2.0 (Preview) +--- + +:::info +The SCIM v2 interface of Zitadel is currently in a [preview stage](/support/software-release-cycles-support#preview). +It is not yet feature-complete, may contain bugs, and is not generally available. + +Do not use it for production yet. + +As long as the feature is in a preview state, it will be available for free, it will be put behind a commercial license once it is fully available. +::: + +The Zitadel [SCIM v2](https://scim.cloud/) service provider interface enables seamless integration of identity and +access management (IAM) systems with Zitadel, +following the System for Cross-domain Identity Management (SCIM) v2.0 specification. +This interface allows standardized management of IAM resources, making it easier to automate user provisioning and +deprovisioning. + +## Supported endpoints + +The Zitadel SCIM v2.0 service provider implementation supports the following endpoints. +The base URL for the SCIM endpoint in Zitadel is: `https://${ZITADEL_DOMAIN}/scim/v2/{orgId}`. + +| Endpoint | Remarks | +|-------------------------------------------------------------------------|------------------------------------------------------------| +| `GET /scim/v2/{orgId}/ServiceProviderConfig` | Retrieve the configuration of the Zitadel service provider | +| `GET /scim/v2/{orgId}/Schemas` | Retrieve all supported schemas | +| `GET /scim/v2/{orgId}/Schemas/{id}` | Retrieve a known supported schema | +| `GET /scim/v2/{orgId}/ResourceTypes` | Retrieve all supported resource types | +| `GET /scim/v2/{orgId}/ResourceTypes/{name}` | Retrieve a known supported resource type | +| `GET /scim/v2/{orgId}/Users/{id}` | Retrieve a known user | +| `GET /scim/v2/{orgId}/Users`
`POST /scim/v2/{orgId}/Users/.search` | Query users (including filtering, sorting, paging) | +| `POST /scim/v2/{orgId}/Users` | Create a user | +| `PUT /scim/v2/{orgId}/Users/{id}` | Replace a user | +| `PATCH /scim/v2/{orgId}/Users/{id}` | Modify a user | +| `DELETE /scim/v2/{orgId}/Users/{id}` | Delete a user | +| `POST /scim/v2/{orgId}/Bulk` | Apply multiple operations in a single request | + +## Authentication + +The SCIM interface adheres to Zitadel's standard API authentication methods. +For detailed instructions on authenticating with the SCIM interface, refer to the [Authenticate Service Users Guide](/guides/integrate/service-users/authenticate-service-users). + +## Query + +The list users endpoint supports sorting and filtering for both `GET /scim/v2/{orgId}/Users` and `POST /scim/v2/{orgId}/Users/.search` requests. +By default, the response includes up to 100 users, with a maximum allowable value for `count` set to 100. + +### Sort + +The following attributes are supported in the `SortBy` attribute. + +- `meta.created` +- `meta.lastModified` +- `id` +- `username` +- `name.familyName` +- `name.givenName` +- `emails` and `emails.value` + +### Filter + +The following filter attributes and operators are supported: + +| Attribute | Supported operators | +|------------------------------|------------------------------| +| `meta.created` | `EQ`, `GT`, `GE`, `LT`, `LE` | +| `meta.lastModified` | `EQ`, `GT`, `GE`, `LT`, `LE` | +| `id` | `EQ`, `NE`, `CO`, `SW`, `EW` | +| `externalId` | `EQ`, `NE` | +| `username` | `EQ`, `NE`, `CO`, `SW`, `EW` | +| `name.familyName` | `EQ`, `NE`, `CO`, `SW`, `EW` | +| `name.givenName` | `EQ`, `NE`, `CO`, `SW`, `EW` | +| `emails`
`emails.value` | `EQ`, `NE`, `CO`, `SW`, `EW` | +| `active` | `EQ`, `NE` | + +Filters can have a maximum length of 1000 characters. + +## Examples + +Here are practical examples demonstrating how to interact with the SCIM API, +providing clear guidance on common use cases such as creating a user. +Make sure to replace any placeholder values (`${}`) with the actual values from your environment. + +
+`POST /Users`: Create a minimal user + +```bash +curl -X POST "https://${DOMAIN}/scim/v2/${ORG_ID}/Users" \ + -H 'Content-Type: application/scim+json' \ + -H 'Accept: application/scim+json' \ + -H "Authorization: Bearer ${ACCESS_TOKEN}" \ + --data-raw ' + { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], + "userName": "john.doe", + "name": { + "familyName": "Doe", + "givenName": "John" + }, + "password": "Password1!", + "emails": [ + { + "value": "john.doe@example.com", + "primary": true + } + ] + } + ' +``` + +**Response (`201 Created`)** +```json +{ + "schemas": [ + "urn:ietf:params:scim:schemas:core:2.0:User" + ], + "meta": { + "resourceType": "User", + "created": "2025-01-27T15:30:27.651321Z", + "lastModified": "2025-01-27T15:30:27.651321Z", + "version": "2", + "location": "https://${DOMAIN}/scim/v2/${ORG_ID}/Users/304499468865155777" + }, + "id": "304499468865155777", + "userName": "john.doe", + "name": { + "familyName": "Doe", + "givenName": "John" + }, + "preferredLanguage": "en", + "emails": [ + { + "value": "john.doe@example.com", + "primary": true + } + ] +} +``` + +
+
+`POST /Users`: Create a full user + +```bash +curl -X POST "https://${DOMAIN}/scim/v2/${ORG_ID}/Users" \ + -H 'Content-Type: application/scim+json' \ + -H 'Accept: application/scim+json' \ + -H "Authorization: Bearer ${ACCESS_TOKEN}" \ + --data-raw ' + { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], + "externalId": "8d4b51c0-51bd-4386-ae17-79ce5fd36517", + "userName": "john.doe@example.com", + "name": { + "formatted": "Mr. John J Doe, III", + "familyName": "Doe", + "givenName": "John", + "middleName": "Jim", + "honorificPrefix": "Mr.", + "honorificSuffix": "III" + }, + "displayName": "John Doe", + "nickName": "Johnny", + "profileUrl": "https://login.example.com/john.doe", + "emails": [ + { + "value": "john.doe@example.com", + "type": "work", + "primary": true + } + ], + "addresses": [ + { + "type": "work", + "streetAddress": "100 Universal City Plaza", + "locality": "Hollywood", + "region": "CA", + "postalCode": "91608", + "country": "USA", + "formatted": "100 Universal City Plaza\nHollywood, CA 91608 USA", + "primary": true + } + ], + "phoneNumbers": [ + { + "value": "+1 555-555-5555", + "type": "work", + "primary": true + } + ], + "ims": [ + { + "value": "@j.doe", + "type": "X" + } + ], + "photos": [ + { + "value": "https://photos.example.com/profilephoto/john.doe/F", + "type": "photo" + } + ], + "roles": [ + { + "value": "user-admin", + "display": "User administrator" + } + ], + "entitlements": [ + { + "value": "read-passports", + "display": "Read Passports" + } + ], + "userType": "Employee", + "title": "Tour Guide", + "preferredLanguage": "en-US", + "locale": "en-US", + "timezone": "America/Los_Angeles", + "active": true, + "password": "Password1!" + }' +``` + +**Response (`201 Created`)** +```json +{ + "schemas": [ + "urn:ietf:params:scim:schemas:core:2.0:User" + ], + "meta": { + "resourceType": "User", + "created": "2025-01-27T15:31:47.84572Z", + "lastModified": "2025-01-27T15:31:47.84572Z", + "version": "16", + "location": "https://localhost:8080/scim/v2/303879575732073153/Users/304499603368096449" + }, + "id": "304499603368096449", + "externalId": "8d4b51c0-51bd-4386-ae17-79ce5fd36517", + "userName": "john.doe@example.com", + "name": { + "formatted": "John Doe", + "familyName": "Doe", + "givenName": "John", + "middleName": "Jim", + "honorificPrefix": "Mr.", + "honorificSuffix": "III" + }, + "displayName": "John Doe", + "nickName": "Johnny", + "profileUrl": "https://login.example.com/john.doe", + "title": "Tour Guide", + "preferredLanguage": "en-US", + "locale": "en-US", + "timezone": "America/Los_Angeles", + "active": true, + "emails": [ + { + "value": "john.doe@example.com", + "primary": true + } + ], + "phoneNumbers": [ + { + "value": "+15555555555", + "primary": true + } + ], + "ims": [ + { + "value": "@j.doe", + "type": "X" + } + ], + "addresses": [ + { + "type": "work", + "streetAddress": "100 Universal City Plaza", + "locality": "Hollywood", + "region": "CA", + "postalCode": "91608", + "country": "USA", + "formatted": "100 Universal City Plaza\nHollywood, CA 91608 USA", + "primary": true + } + ], + "photos": [ + { + "value": "https://photos.example.com/profilephoto/john.doe/F", + "type": "photo" + } + ], + "entitlements": [ + { + "value": "read-passports", + "display": "Read Passports" + } + ], + "roles": [ + { + "value": "user-admin", + "display": "User administrator" + } + ] +} +``` + +
+
+`GET /Users/{id}`: Retrive a known user + +```bash +curl -G "https://${DOMAIN}/scim/v2/${ORG_ID}/Users/${USER_ID}" \ + -H 'Accept: application/scim+json' \ + -H "Authorization: Bearer ${ACCESS_TOKEN}" +``` + + +**Response (`200 OK`)** +```json +{ + "schemas": [ + "urn:ietf:params:scim:schemas:core:2.0:User" + ], + "meta": { + "resourceType": "User", + "created": "2025-01-27T15:31:47.84572Z", + "lastModified": "2025-01-27T15:31:47.84572Z", + "version": "16", + "location": "https://localhost:8080/scim/v2/303879575732073153/Users/304499603368096449" + }, + "id": "304499603368096449", + "externalId": "8d4b51c0-51bd-4386-ae17-79ce5fd36517", + "userName": "john.doe@example.com", + "name": { + "formatted": "John Doe", + "familyName": "Doe", + "givenName": "John", + "middleName": "Jim", + "honorificPrefix": "Mr.", + "honorificSuffix": "III" + }, + "displayName": "John Doe", + "nickName": "Johnny", + "profileUrl": "https://login.example.com/john.doe", + "title": "Tour Guide", + "preferredLanguage": "en-US", + "locale": "en-US", + "timezone": "America/Los_Angeles", + "active": true, + "emails": [ + { + "value": "john.doe@example.com", + "primary": true + } + ], + "phoneNumbers": [ + { + "value": "+15555555555", + "primary": true + } + ], + "ims": [ + { + "value": "@j.doe", + "type": "X" + } + ], + "addresses": [ + { + "type": "work", + "streetAddress": "100 Universal City Plaza", + "locality": "Hollywood", + "region": "CA", + "postalCode": "91608", + "country": "USA", + "formatted": "100 Universal City Plaza\nHollywood, CA 91608 USA", + "primary": true + } + ], + "photos": [ + { + "value": "https://photos.example.com/profilephoto/john.doe/F", + "type": "photo" + } + ], + "entitlements": [ + { + "value": "read-passports", + "display": "Read Passports" + } + ], + "roles": [ + { + "value": "user-admin", + "display": "User administrator" + } + ] +} +``` + +
+
+`GET /Users`: List users created after a given date sorted by the creation date + +```bash +curl -G "https://${DOMAIN}/scim/v2/${ORG_ID}/Users" \ + -H 'Accept: application/scim+json' \ + -H "Authorization: Bearer ${ACCESS_TOKEN}" \ + --data-urlencode "sortBy=meta.created" \ + --data-urlencode "sortOrder=descending" \ + --data-urlencode "filter=meta.created gt \"2025-01-24T09:22:35.695245Z\"" +``` + +**Response (`200 OK`)** +```json +{ + "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"], + "itemsPerPage": 100, + "totalResults": 1, + "startIndex": 1, + "Resources": [ + { + "schemas": [ + "urn:ietf:params:scim:schemas:core:2.0:User" + ], + "meta": { + "resourceType": "User", + "created": "2025-01-27T15:31:47.84572Z", + "lastModified": "2025-01-27T15:31:47.84572Z", + "version": "3", + "location": "https://localhost:8080/scim/v2/303879575732073153/Users/304499603368096449" + }, + "id": "304499603368096449", + "externalId": "8d4b51c0-51bd-4386-ae17-79ce5fd36517", + "userName": "john.doe@example.com", + "name": { + "formatted": "John Doe", + "familyName": "Doe", + "givenName": "John", + "middleName": "Jim", + "honorificPrefix": "Mr.", + "honorificSuffix": "III" + }, + "displayName": "John Doe", + "nickName": "Johnny", + "profileUrl": "https://login.example.com/john.doe", + "title": "Tour Guide", + "preferredLanguage": "und", + "locale": "en-US", + "timezone": "America/Los_Angeles", + "active": true, + "emails": [ + { + "value": "john.doe@example.com", + "primary": true + } + ], + "phoneNumbers": [ + { + "value": "+15555555555", + "primary": true + } + ], + "ims": [ + { + "value": "@j.doe", + "type": "X" + } + ], + "addresses": [ + { + "type": "work", + "streetAddress": "100 Universal City Plaza", + "locality": "Hollywood", + "region": "CA", + "postalCode": "91608", + "country": "USA", + "formatted": "100 Universal City Plaza\nHollywood, CA 91608 USA", + "primary": true + } + ], + "photos": [ + { + "value": "https://photos.example.com/profilephoto/john.doe/F", + "type": "photo" + } + ], + "entitlements": [ + { + "value": "read-passports", + "display": "Read Passports" + } + ], + "roles": [ + { + "value": "user-admin", + "display": "User administrator" + } + ] + } + ] +} +``` + +
+
+`PATCH /Users/{id}`: Set a user inactive + +```bash +curl -X PATCH "https://${DOMAIN}/scim/v2/${ORG_ID}/Users/${USER_ID}" \ + -H 'Content-Type: application/scim+json' \ + -H 'Accept: application/scim+json' \ + -H "Authorization: Bearer ${ACCESS_TOKEN}" \ + --data-raw ' + { + "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], + "Operations": [ + { + "op": "replace", + "path": "active", + "value": false + } + ] + } + ' +``` + +**Response**: `204 No Content` + +
+
+`PATCH /Users/{id}`: Set the password of a user + +```bash +curl -X PATCH "https://${DOMAIN}/scim/v2/${ORG_ID}/Users/${USER_ID}" \ + -H 'Content-Type: application/scim+json' \ + -H "Authorization: Bearer ${ACCESS_TOKEN}" \ + --data-raw ' + { + "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], + "Operations": [ + { + "op": "replace", + "path": "password", + "value": "Password2!" + } + ] + } + ' +``` + +**Response**: `204 No Content` + +
+
+`PUT /Users/{id}`: Replace a full user + +```bash +curl -X PUT "https://${DOMAIN}/scim/v2/${ORG_ID}/Users/${USER_ID}" \ + -H 'Content-Type: application/scim+json' \ + -H 'Accept: application/scim+json' \ + -H "Authorization: Bearer ${ACCESS_TOKEN}" \ + --data-raw ' + { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], + "externalId": "8d4b51c0-51bd-4386-ae17-79ce5fd36517", + "userName": "john.doe@example.com", + "name": { + "formatted": "Mr. John J Doe, III", + "familyName": "Doe", + "givenName": "John", + "middleName": "Jim", + "honorificPrefix": "Mr.", + "honorificSuffix": "III" + }, + "displayName": "John Doe", + "nickName": "Johnny", + "profileUrl": "https://login.example.com/john.doe", + "emails": [ + { + "value": "john.doe@example.com", + "type": "work", + "primary": true + } + ], + "addresses": [ + { + "type": "work", + "streetAddress": "100 Universal City Plaza", + "locality": "Hollywood", + "region": "CA", + "postalCode": "91608", + "country": "USA", + "formatted": "100 Universal City Plaza\nHollywood, CA 91608 USA", + "primary": true + } + ], + "phoneNumbers": [ + { + "value": "+1 555-555-5555", + "type": "work", + "primary": true + } + ], + "ims": [ + { + "value": "@j.doe", + "type": "X" + } + ], + "photos": [ + { + "value": "https://photos.example.com/profilephoto/john.doe/F", + "type": "photo" + } + ], + "roles": [ + { + "value": "user-admin", + "display": "User administrator" + } + ], + "entitlements": [ + { + "value": "read-passports", + "display": "Read Passports" + } + ], + "userType": "Employee", + "title": "Tour Guide", + "preferredLanguage": "en-US", + "locale": "en-US", + "timezone": "America/Los_Angeles", + "active": true, + "password": "Password1!" + }' +``` + +**Response (`200 OK`)** +```json +{ + "schemas": [ + "urn:ietf:params:scim:schemas:core:2.0:User" + ], + "meta": { + "resourceType": "User", + "created": "2025-01-27T15:31:47.84572Z", + "lastModified": "2025-01-27T15:31:47.84572Z", + "version": "16", + "location": "https://localhost:8080/scim/v2/303879575732073153/Users/304499603368096449" + }, + "id": "304499603368096449", + "externalId": "8d4b51c0-51bd-4386-ae17-79ce5fd36517", + "userName": "john.doe@example.com", + "name": { + "formatted": "John Doe", + "familyName": "Doe", + "givenName": "John", + "middleName": "Jim", + "honorificPrefix": "Mr.", + "honorificSuffix": "III" + }, + "displayName": "John Doe", + "nickName": "Johnny", + "profileUrl": "https://login.example.com/john.doe", + "title": "Tour Guide", + "preferredLanguage": "en-US", + "locale": "en-US", + "timezone": "America/Los_Angeles", + "active": true, + "emails": [ + { + "value": "john.doe@example.com", + "primary": true + } + ], + "phoneNumbers": [ + { + "value": "+15555555555", + "primary": true + } + ], + "ims": [ + { + "value": "@j.doe", + "type": "X" + } + ], + "addresses": [ + { + "type": "work", + "streetAddress": "100 Universal City Plaza", + "locality": "Hollywood", + "region": "CA", + "postalCode": "91608", + "country": "USA", + "formatted": "100 Universal City Plaza\nHollywood, CA 91608 USA", + "primary": true + } + ], + "photos": [ + { + "value": "https://photos.example.com/profilephoto/john.doe/F", + "type": "photo" + } + ], + "entitlements": [ + { + "value": "read-passports", + "display": "Read Passports" + } + ], + "roles": [ + { + "value": "user-admin", + "display": "User administrator" + } + ] +} +``` + +
+
+`DELETE /Users/{id}`: Delete a user + +```bash +curl -X DELETE "https://${DOMAIN}/scim/v2/${ORG_ID}/Users/${USER_ID}" \ + -H "Authorization: Bearer ${ACCESS_TOKEN}" +``` + +**Response**: `204 No Content` + +
+
+`POST /Bulk`: Update the password of one user and delete another one + +```bash +curl -X POST "https://${DOMAIN}/scim/v2/${ORG_ID}/Bulk" \ + -H 'Content-Type: application/scim+json' \ + -H 'Accept: application/scim+json' \ + -H "Authorization: Bearer ${ACCESS_TOKEN}" \ + --data-raw ' + { + "schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkRequest"], + "Operations": [ + { + "method": "PATCH", + "path": "/Users/${USER_ID}", + "data": { + "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], + "Operations": [ + { + "op": "replace", + "path": "password", + "value": "Password2!" + } + ] + } + }, + { + "method": "DELETE", + "path": "/Users/${USER_ID2}" + } + ] + }' +``` + +**Response**: `200 OK` + +```json +{ + "schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkResponse"], + "Operations": [ + { + "method": "PATCH", + "location": "https://${DOMAIN}/scim/v2/${ORG_ID}/Users/${USER_ID}", + "status": "204" + }, + { + "method": "DELETE", + "location": "https://${DOMAIN}/scim/v2/${ORG_ID}/Users/${USER_ID2}", + "status": "204" + } + ] +} +``` + +
+ +
+`GET /ServiceProviderConfig`: Get service provider configuration + +```bash +curl -G "https://${DOMAIN}/scim/v2/${ORG_ID}/ServiceProviderConfig" \ + -H 'Accept: application/scim+json' +``` + +**Response**: `200 OK` + +```json +{ + "schemas": [ + "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig" + ], + "meta": { + "resourceType": "ServiceProviderConfig", + "location": "https://${DOMAIN}/scim/v2/${ORG_ID}/ServiceProviderConfig" + }, + "documentationUri": "https://zitadel.com/docs/guides/manage/user/scim2", + "patch": { + "supported": true + }, + "bulk": { + "supported": true, + "maxOperations": 100, + "maxPayloadSize": 1000000 + }, + "filter": { + "supported": true, + "maxResults": 100 + }, + "changePassword": { + "supported": true + }, + "sort": { + "supported": true + }, + "etag": { + "supported": false + }, + "authenticationSchemes": [ + { + "name": "Zitadel authentication token", + "description": "Authentication scheme using the OAuth Bearer Token Standard", + "specUri": "https://www.rfc-editor.org/info/rfc6750", + "documentationUri": "https://zitadel.com/docs/guides/integrate/service-users/authenticate-service-users", + "type": "oauthbearertoken", + "primary": false + } + ] +} +``` + +
+ +## Error handling + +The SCIM interface uses standard HTTP status codes and error messages to indicate the success or failure of API requests +following the error handling guidelines of [RFC7644](https://datatracker.ietf.org/doc/html/rfc7644#section-3.12). + +In addition to the default SCIM error schema (`urn:ietf:params:scim:api:messages:2.0:Error`), +Zitadel extends the error response with a custom schema, `urn:ietf:params:scim:api:zitadel:messages:2.0:ErrorDetail`. +This schema includes additional attributes, such as the untranslated error message and an error id, +which aids pinpointing the source of the error in the system. + +## Resources + +- **[Zitadel SCIM Documentation](/guides/manage/user/scim2)**: Documentation of Zitadel's SCIM implementation, including configuration details and known limitations. +- **[SCIM](https://scim.cloud/)**: The Webpage of SCIM. +- **[RFC7643](https://tools.ietf.org/html/rfc7643) Core Schema**: + The Core Schema provides a platform-neutral schema and extension model for representing users and groups. +- **[RFC7644](https://tools.ietf.org/html/rfc7644) Protocol**: + The SCIM Protocol is an application-level, REST protocol for provisioning and managing identity data on the web. +- **[RFC7642](https://tools.ietf.org/html/rfc7642) Definitions, Overview, Concepts, and Requirements**: + This document lists the user scenarios and use cases of System for Cross-domain Identity Management (SCIM). diff --git a/docs/docs/guides/manage/user/scim2.md b/docs/docs/guides/manage/user/scim2.md new file mode 100644 index 0000000000..edf5e7bd10 --- /dev/null +++ b/docs/docs/guides/manage/user/scim2.md @@ -0,0 +1,127 @@ +--- +title: SCIM v2.0 (Preview) +--- + +:::info +The SCIM v2 interface of Zitadel is currently in a [preview stage](/support/software-release-cycles-support#preview). +It is not yet feature-complete, may contain bugs, and is not generally available. + +Do not use it for production yet. + +As long as the feature is in a preview state, it will be available for free, it will be put behind a commercial license once it is fully available. +::: + +The Zitadel [SCIM v2](https://scim.cloud/) service provider interface enables seamless integration of identity and +access management (IAM) systems with Zitadel, +following the System for Cross-domain Identity Management (SCIM) v2.0 specification. +This interface allows standardized management of IAM resources, making it easier to automate user provisioning and +deprovisioning. + +## API + +To learn more about Zitadel's SCIM API, see the API documentation [here](/apis/scim2). + +## Provisioning domain + +A provisioning domain refers to an administrative domain that exists outside the domain of a service provider due to +legal or technical reasons. +For more details, refer to the [definitions](https://datatracker.ietf.org/doc/html/rfc7643#section-1.2) +of [RFC7643](https://datatracker.ietf.org/doc/html/rfc7643). + +The `externalId` of a user is scoped to the provisioning domain. +To set a provisioning domain for a machine user, +add a metadata entry with the key `urn:zitadel:scim:provisioningDomain` and assign its value to the corresponding +provisioning domain. + +When a machine user has a `urn:zitadel:scim:provisioningDomain` metadata set, +the `externalId` of all users provisioned or queried by that machine user is stored in the users' metadata. +The key format is `urn:zitadel:scim:{provisioningDomain}:externalId`, +where `{provisioningDomain}` is replaced with the machine user's provisioning domain. +If the machine user does not have a provisioning domain set, +a simplified metadata key `urn:zitadel:scim:externalId` is used to store and retrieve the `externalId` of users. + +## Mapping + +The table below outlines how supported SCIM attributes in the user schema map to corresponding Zitadel user attributes. +Some attributes are directly mapped to Zitadel user attributes, while others are stored in the user's metadata. +For more information about user metadata, see [here](../customize/user-metadata). + +| SCIM | Zitadel | Remarks | +|------------------------|-----------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `id` | `userId` | | +| `username` | `username` | | +| `name.formatted` | `profile.displayName` | The SCIM attribute `displayName` takes precedence over `name.formatted` | +| `name.familyName` | `profile.familyName` | | +| `name.middleName` | `metadata[urn:zitadel:scim:name.middleName]` | | +| `name.honorificPrefix` | `metadata[urn:zitadel:scim:name.honorificPrefix]` | | +| `name.honorificSuffix` | `metadata[urn:zitadel:scim:name.honorificSuffix]` | | +| `displayName` | `profile.displayName` | The SCIM attribute `displayName` takes precedence over `name.formatted` | +| `nickName` | `profile.nickName` | | +| `profileUrl` | `metadata[urn:zitadel:scim:profileUrl]` | | +| `title` | `metadata[urn:zitadel:scim:title]` | | +| `preferredLanguage` | `profile.preferredLanguage` | | +| `locale` | `metadata[urn:zitadel:scim:locale]` | | +| `timezone` | `metadata[urn:zitadel:scim:timezone]` | | +| `active` | `state` | `Initial` and `Active` are mapped to `active = true`, all other states are mapped to `active = false`.
The `active` value can only be updated if the user is in the state `Active` or `Inactive`. | +| `password` | `password` | | +| `emails` | `email` | Only the `primary` email is stored in Zitadel, if there is no `primary` email, the first one is stored. By default emails from SCIM are considered verified, this can be adjusted in the [configuration](#configuration). | +| `phoneNumbers` | `phone` | Only the `primary` phone number is stored in Zitadel, if there is no `primary` phone number, the first one is stored. By default phone numbers from SCIM are considered verified, this can be adjusted in the [configuration](#configuration). | +| `ims` | `metadata[urn:zitadel:scim:ims]` | Serialized as JSON. | +| `photos` | `metadata[urn:zitadel:scim:photos]` | Serialized as JSON. | +| `addresses` | `metadata[urn:zitadel:scim:addresses]` | Serialized as JSON. | +| `entitlements` | `metadata[urn:zitadel:scim:entitlements]` | Serialized as JSON. | +| `roles` | `metadata[urn:zitadel:scim:roles]` | Serialized as JSON. | +| `externalId` | `metadata[urn:zitadel:scim:externalId]`
`metadata[urn:zitadel:scim:{provisioningDomain}:externalId]` | See [provisioning domain](#provisioning-domain). | + +## Configuration + +This section provides details on the runtime configuration of the SCIM interface of Zitadel. + +By default, Zitadel's SCIM interface assumes that email addresses and phone numbers are verified. +The bulk endpoint supports up to 100 operations per request, with a maximum request body size of 1 MB. +This behavior can be adjusted through the Zitadel runtime configuration settings: + +```yaml +SCIM: + EmailVerified: true + PhoneVerified: true + MaxRequestBodySize: 1_000_000 + Bulk: + MaxOperationsCount: 100 + ``` + +## Limitations + +This section outlines the known limitations of the Zitadel SCIM implementation, +including unsupported features, partial compliance with the SCIM specification, +and any potential edge cases to consider during integration. + +### Supported schemas + +Only the users schema `urn:ietf:params:scim:schemas:core:2.0:User` is supported. + +### Required attributes + +The following SCIM user attributes are required, in addition to those required by the SCIM standard: + +* `name.familyName` +* `name.givenName` +* `emails`: at least one email is required + +### Duplicated attribute mapping + +The SCIM user attributes `name.formatted` and `displayName` are both mapped to the `profile.displayName` attribute in +Zitadel. +When a user is provisioned with different values for these attributes, `displayName` takes precedence. +Only the value of `displayName` is stored and returned in subsequent queries. + +## Resources + +- **[Zitadel SCIM API Documentation](/apis/scim2)**: Documentation of Zitadel's SCIM API implementation. +- **[SCIM](https://scim.cloud/)**: The Webpage of SCIM. +- **[RFC7643](https://tools.ietf.org/html/rfc7643) Core Schema**: + The Core Schema provides a platform-neutral schema and extension model for representing users and groups. +- **[RFC7644](https://tools.ietf.org/html/rfc7644) Protocol**: + The SCIM Protocol is an application-level, REST protocol for provisioning and managing identity data on the web. +- **[RFC7642](https://tools.ietf.org/html/rfc7642) Definitions, Overview, Concepts, and Requirements**: + This document lists the user scenarios and use cases of System for Cross-domain Identity Management (SCIM). diff --git a/docs/sidebars.js b/docs/sidebars.js index 5adc09f7a1..a154514d5a 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -159,6 +159,7 @@ module.exports = { "guides/manage/user/reg-create-user", "guides/manage/customize/user-metadata", "guides/manage/customize/user-schema", + "guides/manage/user/scim2", ], }, "guides/manage/terraform-provider", @@ -837,6 +838,14 @@ module.exports = { }, ], }, + { + type: "category", + label: "Provision Users", + collapsed: true, + items: [ + 'apis/scim2' + ], + }, { type: "category", label: "Actions",