SCIM Overview

FusionAuth Reactor logo

This feature is only available in the Enterprise plan. Please visit our pricing page to learn more.

Overview

This functionality has been available since 1.36.0

SCIM (System for Cross-domain Identity Management) is a specification for a client to provision users and groups on a server using a standard protocol. FusionAuth can consume SCIM formatted requests and act as the provisioning server in a SCIM client/server environment.

Common SCIM Use Cases

SCIM lets you provision and deprovision users from external identity stores into FusionAuth. Here are some scenarios where this is useful:

  • When your customers are themselves businesses with a centralized user data store. This is common when you are a business to business SaaS product. Customers want to control access to their instance of your application. They can do so by using SCIM to set up accounts for their users. When an employee leaves the customer’s company, the employee account is automatically disabled in FusionAuth. Since SCIM is configured at the FusionAuth tenant level, this is an enterprise feature that FusionAuth makes it easy to offer.
  • Ensuring your employees have access to your custom applications which use FusionAuth as an identity store. When a new employee is added into your corporate directory (Azure AD/Microsoft Entra ID, Okta, or otherwise), SCIM can provision them into the custom application, accelerating their onboarding experience. Equally important, when the employee departs, their access to the app also departs.

Specifications

The links below include details about the SCIM specification as well as detailed information about the protocols and schemas.

FusionAuth SCIM Support

Any SCIM client can make requests to FusionAuth using the SCIM specification for defining Users and Groups. In this scenario FusionAuth acts as the provisioning server and can respond with SCIM compliant responses.

FusionAuth is not a SCIM compatible client, but if you are interested in similar functionality, review available Webhooks.

The FusionAuth SCIM Workflow

This is an example of a basic interaction between an external SCIM client provisioning request to create a FusionAuth User:

  1. The client would send a SCIM compliant request to the SCIM User endpoint /api/scim/resource/v2/Users. Other SCIM API endpoints are also available.

Example User Create Request JSON

{
  "active": true,
  "emails": [
    {
      "primary": true,
      "type": "work",
      "value": "example@fusionauth.io"
    }
  ],
  "externalId": "cc6714c6-286c-411c-a6bc-ee413cda1dbc",
  "name": {
    "familyName": "Doe",
    "formatted": "John Doe",
    "givenName": "John",
    "honorificPrefix": "Mr.",
    "honorificSuffix": "III",
    "middleName": "William"
  },
  "password": "supersecret",
  "phoneNumbers": [
    {
      "primary": true,
      "type": "mobile",
      "value": "303-555-1234"
    }
  ],
  "schemas": [
    "urn:ietf:params:scim:schemas:core:2.0:Users"
  ],
  "userName": "johnny123"
}
  1. FusionAuth will authenticate the incoming request to ensure the request is from a known SCIM client. Each SCIM client and server instance is represented as an Entity and will authenticate using a Client Credentials Grant. An example client credentials grant using Entities.
  2. FusionAuth will call the assigned incoming request lambda, passing the SCIM request data and a FusionAuth User object. The lambda is responsible for converting the incoming SCIM request data into a FusionAuth User object. For example, the name.givenName property shown above could be mapped to user.firstName.
  1. FusionAuth will attempt to create the FusionAuth User using the mapped object from the incoming request lambda.
  2. Upon successful creation of the User, FusionAuth will call the outgoing response lambda, passing the newly created FusionAuth User and the SCIM response. The outgoing lambda is responsible for mapping the FusionAuth User properties to the appropriate SCIM representation.

The lambdas will need to map the SCIM data to the appropriate FusionAuth object property. Below are some suggested strategies, but the data can be mapped in any way you choose.

Suggested lambda mapping between SCIM Group schema extension and FusionAuth Group

SCIM Group AttributeFusionAuth Group and members property
externalIdThis field is handled automatically so it does not need to be mapped in the lambdas
displayNamegroup.name
members[x].valuemembers[x].userId
members[x].$refmembers[x].data.$ref

Suggested lambda mapping between SCIM User schema and FusionAuth User

SCIM User AttributeFusionAuth User property
activeuser.active
emails[x].valueuser.email
externalIdThis field is handled automatically so it does not need to be mapped in the lambdas
name.familyNameuser.lastName
name.formatteduser.fullName
name.givenNameuser.firstName
name.honorifixPrefixuser.data.honorificPrefix
name.honorifixSuffixuser.data.honorificSuffix
name.middleNameuser.middleName
passworduser.password
name.givenNameuser.firstName
phoneNumbers[x].valueuser.mobilePhone
userNameuser.userName

The SCIM EnterpriseUser schema is an extension of the SCIM User schema so the suggested mappings would include the ones from Table 1 above and the additional mappings in Table 2 below. This is the suggested mapping strategy for all SCIM schema extensions.

Suggested lambda mapping between SCIM EnterpriseUser schema extension and FusionAuth User where schema is urn:ietf:params:scim:schemas:extension:enterprise:2.0:User

SCIM EnterpriseUser AttributeFusionAuth User property
costCenteruser.data.extensions[schema].costCenter
departmentuser.data.extensions[schema].department
divisionuser.data.extensions[schema].division
employeeNumberuser.data.extensions[schema].employeeNumber
manager.displayNameuser.data.extensions[schema].managerDisplayName
manager.$refuser.data.extensions[schema].managerURI

Configuration

In order for FusionAuth to accept requests from SCIM clients, you need to perform a few one time configuration steps.

  • You need to enable SCIM support for your tenant.
  • You need to define your incoming request and outgoing response lambdas for each the supported SCIM resource types (User, Enterprise User, Group)
  • You will need to verify that the default SCIM schemas provided match your desired SCIM schema for each of the SCIM resource types or provide your own.
  • You will need an Entity defined for each SCIM client and SCIM Server. Default entity types are provided for you. You can create the entities from those default types or create your own types.

Permissions

Below is a list of available permissions that can be included in your SCIM server entity type. Each controls access to a single API endpoint. You can choose to create as few or as many of these as you require. The names must match exactly.

NameAccess to API
scim:enterprise:user:createCreate an Enterprise User
scim:enterprise:user:readRetrieve an Enterprise User
scim:enterprise:user:updateUpdate an Enterprise User
scim:enterprise:user:deleteDelete an Enterprise User
scim:group:createCreate a Group
scim:group:readRetrieve a Group
scim:group:updateUpdate a Group
scim:group:deleteDelete a Group
scim:resource-types:readRetrieve Resource Types
scim:schemas:readRetrieve Schemas
scim:service-provider-config:readRetrieve Service Provider Configuration
scim:user:createCreate a User
scim:user:readRetrieve a User
scim:user:updateUpdate a User
scim:user:deleteDelete a User

FusionAuth SCIM API Endpoints

In order to use FusionAuth as your SCIM provisioning server for SCIM clients, you will need to call the correct FusionAuth SCIM API endpoint. FusionAuth provides endpoints for retrieving, creating, replacing, and deleting SCIM Users, EnterpriseUsers, and Groups.

See the SCIM API Overview for details about the supported endpoints.

Adding Registrations

With SCIM, users are provisioned. They are not registered for applications within FusionAuth.

Options to automatically add a registration to a new user include:

  • Listen for the user.create.complete webhook and add the registration using an API call on the receiver.
  • Make an API call registering the user to an application from the SCIM User Response Converter lambda which is called after the user is created. Ensure this idempotent as the lambda will be called any time the user is updated as well.
  • If you enable self service registration for your application, and the user logs in to the application, they will be automatically registered for the application. Learn more.

SCIM Client Authentication

FusionAuth requires the token from a completed Client Credentials grant for SCIM server authentication, as mentioned above. The token generated from the grant is used in the Authorization header as a Bearer token.

However, some SCIM clients can’t dynamically complete a client credentials grant. Instead, they need a static authorization header value.

To correctly integrate with such clients, do the following:

  • Optionally change the JWT duration of the SCIM Client Entity Type to a larger value, such as a year, which is 31536000. The generated JWT will not be able to be revoked, so pick a duration that balances the security risk with the effort of updating the JWT in the SCIM client configuration (Azure AD/Microsoft Entra ID, Okta, etc).
  • Gather the Client Id of the SCIM Client, the Client Secret of the SCIM Client, and the SCIM Server Client Id. These values are available from the respective Entity details screen.
  • Determine the SCIM permissions you want to grant the SCIM Client.
  • Perform the Client Credentials grant manually using a tool like curl (see below for an example).

Performing the Client Credentials grant for a SCIM Client.

# This curl script grants all SCIM permissions to the client via the JWT.
# Edit the scope below if you need restricted permissions for this token.
SCIM_CLIENT_CLIENT_ID=...
SCIM_CLIENT_CLIENT_SECRET=...
SCIM_SERVER_CLIENT_ID=...
FUSIONAUTH_HOSTNAME=https://local.fusionauth.io # update this

SCIM_ENTITY_PERMISSIONS='scim:enterprise:user:create,scim:enterprise:user:update,scim:user:update,scim:group:read,scim:group:create,scim:enterprise:user:delete,scim:group:delete,scim:group:update,scim:user:delete,scim:enterprise:user:read,scim:user:create,scim:user:read'

curl -u $SCIM_CLIENT_CLIENT_ID:$SCIM_CLIENT_CLIENT_SECRET $FUSIONAUTH_HOSTNAME/oauth2/token \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "scope=target-entity:$SCIM_SERVER_CLIENT_ID:$SCIM_ENTITY_PERMISSIONS"

This script will return JSON, including an access_token value.

Sample JSON returned from the Client Credentials grant.

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImd0eSI6WyJjbGllbnRfY3JlZGVudGlhbHMiXSwia2lkIjoiZWQzNzU4NThkIiwidXNlIjoic2NpbV9zZXJ2ZXIifQ.eyJhdWQiOiI3MGYxOTViYS0wNzI5LTRiMjAtYjA3YS1kYjhiNjkxNGFjYzQiLCJleHAiOjE2NjM4MDY1NDYsImlhdCI6MTY2MzgwMjk0NiwiaXNzIjoiYWNtZS5jb20iLCJzdWIiOiIzY2ZiYTdjNi1jMTc4LTQxZTMtOWQ0Yi1hYzU1MjY2NmM2MzkiLCJqdGkiOiI0NWFkYzZhNC0wZDQzLTQ4Y2UtOGI4Ni01OGU2MTJkYmU3MzgiLCJzY29wZSI6InRhcmdldC1lbnRpdHk6NzBmMTk1YmEtMDcyOS00YjIwLWIwN2EtZGI4YjY5MTRhY2M0OnNjaW06ZW50ZXJwcmlzZTp1c2VyOmNyZWF0ZSxzY2ltOmVudGVycHJpc2U6dXNlcjp1cGRhdGUsc2NpbTp1c2VyOnVwZGF0ZSxzY2ltOmdyb3VwOnJlYWQsc2NpbTpncm91cDpjcmVhdGUsc2NpbTplbnRlcnByaXNlOnVzZXI6ZGVsZXRlLHNjaW06Z3JvdXA6ZGVsZXRlLHNjaW06Z3JvdXA6dXBkYXRlLHNjaW06dXNlcjpkZWxldGUsc2NpbTplbnRlcnByaXNlOnVzZXI6cmVhZCxzY2ltOnVzZXI6Y3JlYXRlLHNjaW06dXNlcjpyZWFkIiwidGlkIjoiMzA2NjMxMzItNjQ2NC02NjY1LTMwMzItMzI2NDY2NjEzOTM0IiwicGVybWlzc2lvbnMiOnsiNzBmMTk1YmEtMDcyOS00YjIwLWIwN2EtZGI4YjY5MTRhY2M0IjpbInNjaW06ZW50ZXJwcmlzZTp1c2VyOmNyZWF0ZSIsInNjaW06ZW50ZXJwcmlzZTp1c2VyOmRlbGV0ZSIsInNjaW06ZW50ZXJwcmlzZTp1c2VyOnJlYWQiLCJzY2ltOmVudGVycHJpc2U6dXNlcjp1cGRhdGUiLCJzY2ltOmdyb3VwOmNyZWF0ZSIsInNjaW06Z3JvdXA6ZGVsZXRlIiwic2NpbTpncm91cDpyZWFkIiwic2NpbTpncm91cDp1cGRhdGUiLCJzY2ltOnVzZXI6Y3JlYXRlIiwic2NpbTp1c2VyOmRlbGV0ZSIsInNjaW06dXNlcjpyZWFkIiwic2NpbTp1c2VyOnVwZGF0ZSJdfX0.ZHqaZAn9SFJ10HGfvQ1ACLS3ys8JjzH1W_Cmgq_hOOU",
  "expires_in": 3599,
  "scope": "target-entity:70f195ba-0729-4b20-b07a-db8b6914acc4:scim:enterprise:user:create,scim:enterprise:user:update,scim:user:update,scim:group:read,scim:group:create,scim:enterprise:user:delete,scim:group:delete,scim:group:update,scim:user:delete,scim:enterprise:user:read,scim:user:create,scim:user:read",
  "token_type": "Bearer"
}

Place the access_token in the authorization header configuration field of your SCIM client.

When the token expires, the SCIM integration will fail. Document how to regenerate the token and update the client configuration.

Learn more about the Client Credentials grant.

Limits

The current SCIM implementation does not support bulk operations using SCIM. Bulk operations on users, such as addition and deletion, are available via FusionAuth APIs, but are not currently supported via SCIM compatible endpoints. If this functionality is required, please file a GitHub issue explaining your use case.

The list operation is limited to 10,000 users if you are using the Elasticsearch search engine. See Limitations for more information.

You cannot create a FusionAuth Registration for a user provisioned with SCIM directly during the provisioning process. See Adding Registrations for workarounds.

While it is not enforced, or a hard limitation, it is recommended to configure at most one SCIM client per tenant. While you can have multiple SCIM clients configured to provision users in one FusionAuth tenant, at the end of the day you only have one user data store in each tenant. Conflicts with creation, updates and deletion could happen; they won’t be automatically resolved by FusionAuth. If you need multiple SCIM clients provisioning users into a single tenant, ensure you handle conflicts.

Okay, okay, you want multiple SCIM clients to provision users into a single FusionAuth tenant. Let’s talk about the complexities. Imagine you have an Okta SCIM client provisioning users into a FusionAuth tenant and an Azure AD/Microsoft Entra ID SCIM client provisioning users into the same tenant.

Issues with this approach include:

  • The user and group lambdas would have to include logic to differentiate between a user from Okta and a user from Azure AD/Microsoft Entra ID and handle the fields differently. The incoming SCIM request does not include information about the source, but you might be able to examine an email domain or a marker attribute to determine where the user was coming from.
  • User collisions are not handled by FusionAuth. If the Okta SCIM client created an account for a user with the email address richard@example.com in the tenant, then later the Azure AD SCIM client tried to create an account for a user with the email address richard@example.com, the second account creation would fail. One workaround would be for the lambda to resolve the collision, for example by adding a suffix or prefix to make the email address unique.
  • Update or deletion requests from the Okta SCIM client could modify users created by the Azure AD SCIM client and vice versa.
  • The bearer access token used to authenticate each SCIM client can be different, but they must have the same lifetime, since that is configured at the Entity Type level. You couldn’t have Okta’s credentials be valid for a year but Azure AD’s credentials be valid for six months.