Overview

This guide shows how to integrate a SCIM client, built using the open source SCIM-SDK Java Library, with FusionAuth.

Prerequisites

In order to work through this guide, you’ll need a few things already set up.

FusionAuth Configuration

In order for FusionAuth to accept requests from SCIM clients, it must be properly configured as a SCIM server. To do so, follow the steps below.

Entity Types

Review or create the required entity types. These entity types will be present if you installed FusionAuth via the Setup Wizard. However, they will not be present if you have used Kickstart.

If these entity types are present, skip to Entities unless you want to learn more about the entity types and permissions.

Add the Server Entity Type

First, add the SCIM server. Navigate to Entity Management -> Entity Types. Select the Add SCIM Server option.

Add the SCIM server entity type.

This entity will, by default, have the following permissions:

  • scim:enterprise:user:create
  • scim:enterprise:user:delete
  • scim:enterprise:user:read
  • scim:enterprise:user:update
  • scim:group:create
  • scim:group:delete
  • scim:group:read
  • scim:group:update
  • scim:resource-types:read
  • scim:schemas:read
  • scim:service-provider-config:read
  • scim:user:create
  • scim:user:delete
  • scim:user:read
  • scim:user:update

Remove permissions if you never want your SCIM server to support an operation. For example, remove scim:user:delete to disable user deletion by any clients accessing this SCIM server. Set the name of the entity type to an appropriate value, such as SCIM Server.

The details page when adding add the SCIM server entity type.

Add the Client Entity Type

Next, create a SCIM client entity type. Unlike the server, this entity type doesn’t have any permissions. Instead, this is the type representing SCIM client applications. Such applications provide user and group data to the SCIM server to be provisioned.

Adding the SCIM client entity type.

Give this entity type an appropriate name such as SCIM Client.

The details of the SCIM client entity type.

After you have set up or verified the existence of these two types of entities, the next step is to set up the individual entities, representing the actual SCIM server or client applications.

Entities

You need to set up at least two entities: an instance of the SCIM server and the SCIM client. Then, you must grant permissions on the SCIM server to the SCIM client.

You may have as many SCIM clients and servers as you would like, but typically you will have at most one SCIM server per tenant. For each SCIM interaction, only one server can be specified.

To add the entities, navigate to Entity Management -> Entities and create a new entity using the + button.

Adding a SCIM server entity.

Make sure the new SCIM server entity has the Entity type of the SCIM server entity type outlined above. Give it a name as well.

The details of the SCIM server entity.

After you save the entity, you’ll be presented with a list of existing entities. The next step is to add another entity for the SCIM client application.

Adding a SCIM client entity.

Similarly to the SCIM server entity you just created, make sure this entity has the Entity type of the SCIM client entity type outlined above. Since you may have more than one SCIM client, a descriptive name for this entity is especially important.

The details of the SCIM client entity.

Next, manage the client entity to grant the correct permissions to the server entity. Do so by clicking the black button on the entity listing page next to the client entity.

The manage button for the SCIM client.

Click the “Add” button to begin the grant adding process.

The "Add" Button lets you add grants.

Search for the SCIM server by entering the name of the entity you created above in the search box. Select the correct entity.

Searching for the correct SCIM server entity.

Next, add permissions. You may grant one or more SCIM permissions to the client application. These permissions will be included in the authentication process to obtain the appropriate level of access.

The SCIM server entity will be in the Name field. Select permissions you’d like this client to have. Below, the ability to read and create users is granted. This client may neither delete nor update users.

Granting permissions on the server to the client.

Finally, you need to record the client Id of the SCIM server and the client Id and secret of the SCIM client. These will be used by the SCIM client Java application, which uses the SCIM-SDK project and is examined below, to provision users.

You can see the Ids by looking in the list view.

Finding the Ids for the entities.

To find the client secret for the SCIM client entity, view the details screen. You can navigate to the details screen by clicking on the “View” button (the magnifying glass) from the entity list page.

Determining the client secret for the SCIM client.

Request and Response Lambdas

Next, we need to review the lambdas. Navigate to Customizations -> Lambdas. You should see four lambdas prefixed with “SCIM”.

There are two sets of default lambdas, one for users and one for groups. Each set of lambdas has one lambda for incoming requests and one for outgoing responses. You can use the same lambda for both User and EnterpriseUser resources, or you can use different ones.

Lambdas can transform requests and responses, register users for applications, make HTTP requests to external APIs, and contain other business logic. Learn more about the different lambdas, including their arguments.

A list including the default SCIM lambdas.

You may edit and modify lambdas as needed, but for the purposes of this document, the default lambdas work fine.

The default SCIM user request lambda.

After you have verified the lambdas will work for your needs, enable and configure SCIM in the tenant settings.

Tenant Configuration

Prior to this, you have configured everything required to enable SCIM for a FusionAuth tenant.

To do so, navigate to Tenants -> Default Tenant. Edit the tenant and then navigate to the SCIM tab. Once you’ve checked the Enabled field, you’ll see all the SCIM settings.

Configure the following details:

  • The Client entity type should be the client entity type you previously created: SCIM Client.
  • The Server entity type should be the client entity type you previously created: SCIM Server.
  • The User request lambda should be the default lambda of the correct type.
  • The User response lambda should be the default lambda of the correct type.
  • The Enterprise User request lambda should be the default lambda of the correct type.
  • The Enterprise User response lambda should be the default lambda of the correct type.
  • The Group request lambda should be the default lambda of the correct type.
  • The Group response lambda should be the default lambda of the correct type.

You can leave the Schemas field blank; a default schema will be provided.

A configured tenant's SCIM settings.

Each of these settings is documented in detail elsewhere. Review detailed documentation about the Tenant SCIM settings.

The SCIM Client Application

Next, create a command line SCIM client Java application. This application will use the open source SCIM-SDK Java library to interact with the FusionAuth SCIM server.

Clients are the source of user information, so this client will be able to create, list and retrieve a user in FusionAuth.

The entire source code is available. Below you’ll download, configure and run it.

Before you configure the application, clone the repository and compile it:

Compiling the example SCIM client application

git clone https://github.com/FusionAuth/fusionauth-example-scim-integration && \
cd fusionauth-example-scim-integration && \
mvn compile

Configure the Application

You’ll need to modify the application by editing the src/main/java/io/fusionauth/example/scim/ScimExample.java file using the text editor or IDE of your choice.

Search for the text: change these. You’ll see something similar to the below code.

Configuration to change for the example

	// change these
	private static final String FUSIONAUTH_HOST = "https://local.fusionauth.io";
	private static final String SCIM_SERVER_ENTITY_ID = "70f195ba-0729-4b20-b07a-db8b6914acc4";
	private static final String CLIENT_ID = "3cfba7c6-c178-41e3-9d4b-ac552666c639";
	private static final String EXISTING_USER_ID = "d4a3ba16-fc77-4a5c-8216-5f629a4afb62";
	private static final String CREATED_USER_LOGIN_ID = "test@example.com";

	// probably won't need to change these
	private static final String SCIM_PERMISSIONS = "scim:user:read,scim:user:create";
	private static final String SCIM_APPLICATION_BASE_URL = FUSIONAUTH_HOST+"/api/scim/resource/v2/";
	private static final String DEFAULT_USER_PASSWORD = "password";

You need to update the various constants:

  • Update FUSIONAUTH_HOST with the URL pointing to your FusionAuth installation, such as http://localhost:9011.
  • Update SCIM_SERVER_ENTITY_ID with the Id of the entity with the type SCIM Server created above. This represents the FusionAuth server. If you didn’t record this, navigate to Entity Management -> Entities and copy the Id from the list of entities.
  • Update CLIENT_ID with the Id of the entity with the type SCIM Client created above. This represents this Java program. If you didn’t record this, navigate to Entity Management -> Entities and copy the Id from the list of entities.
Finding the Ids for the entities.

You may also optionally update EXISTING_USER_ID with the Id of any user in your FusionAuth system. Find one by navigating to Users and viewing the details of a user. If you don’t update this constant, you won’t be able to retrieve a user.

Optionally update CREATED_USER_LOGIN_ID with a unique username. This will be the username of the created user. If you don’t modify this value, the default username will be used.

The other constants may be left unchanged, unless you want to experiment with changing permissions or setting a different password for created users.

Run the Application

The application can be run in three modes:

  • get which retrieves a single user
  • list which lists up to five users
  • create, which adds a new user

Let’s create a new user and then check to see that the user was added.

To run the program, to recompile it to ensure the changes above are picked up.

Recompiling the sample application

mvn compile

Then, run it. You need to provide two arguments to the application. The first is the client secret for the SCIM client entity. This value, along with the client Id, will be used to authenticate the SCIM client before the SCIM APIs are called. If you didn’t record this, navigate to Entity Management -> Entities, view the details of the SCIM Client entity, and copy the secret.

Then, run the command below, with the value of YOUR_CLIENT_SECRET updated to the real value, such as i2kN2KFBPKKj3FsxfilPXDDreBUskn2Sl-27QbQRYQM.

Running the sample application

mvn exec:java -Dexec.mainClass="io.fusionauth.example.scim.ScimExample" \
-Dexec.args="YOUR_CLIENT_SECRET create"

You’ll see the output of the sample application, which should look something like this.

Output of sample application

[INFO] Scanning for projects...
[INFO] 
[INFO] ---------------< io.fusionauth.example:scim-integration >---------------
[INFO] Building scim-integration 0.0.1
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- exec-maven-plugin:3.0.0:java (default-cli) @ scim-integration ---
{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],"active":true,"id":"fccf49ab-f34e-4736-9dfc-50a68b4a86f3","meta":{"created":"2022-07-05T13:42:02.963Z","lastModified":"2022-07-05T13:42:02.963Z","location":"https://local.fusionauth.io/api/scim/resource/v2/Users/fccf49ab-f34e-4736-9dfc-50a68b4a86f3","resourceType":"User"},"userName":"test@example.com"}
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.259 s
[INFO] Finished at: 2022-07-05T09:42:03-04:00
[INFO] ------------------------------------------------------------------------

If you navigate to Users in the administrative user interface, you will see the new user has been added.

New user added via SCIM.

Examine the Application

Let’s look at two parts of the example application: the SCIM client authentication and the method that creates the user.

To authenticate a SCIM client in FusionAuth, the client credentials grant is performed, including requesting any needed SCIM permissions. The resulting access token is then used as a bearer token in the SCIM API request, by including it in the Authorization header. The token generation happens in the getCredentials method.

The getCredentials method

	private static String getCredentials(String secret) throws AuthenticationException, IOException {
		CloseableHttpClient client = HttpClients.createDefault();
		HttpPost httpPost = new HttpPost(FUSIONAUTH_HOST+"/oauth2/token");

		List<NameValuePair> params = new ArrayList<NameValuePair>();
		params.add(new BasicNameValuePair("grant_type", "client_credentials"));
		params.add(new BasicNameValuePair("scope", "target-entity:"+SCIM_SERVER_ENTITY_ID +":"+SCIM_PERMISSIONS));
		httpPost.setEntity(new UrlEncodedFormEntity(params));

		// auth using our client id and secret
		UsernamePasswordCredentials creds = new UsernamePasswordCredentials(CLIENT_ID,secret);
		httpPost.addHeader(new BasicScheme().authenticate(creds, httpPost, null));	    

		CloseableHttpResponse response = client.execute(httpPost);

		// pull the access_token out of the response
		String out = new String(response.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8);

		ObjectMapper mapper = new ObjectMapper();
		TypeReference<HashMap<String, String>> typeRef = new TypeReference<HashMap<String, String>>() {};
		Map<String, String> map = mapper.readValue(out, typeRef);

		String token = map.get("access_token");

		client.close();

		return token;
	}

The create operation first builds a user object and then calls the SCIM-SDK provided scimRequestBuilder.create method, which posts to a SCIM server; in this case, the FusionAuth server receives the request.

The createUser method

	private static void createUser(ScimRequestBuilder scimRequestBuilder, String username, String password) {

		User user = User.builder().password(password).userName(username).active(true).build();

		String endpointPath = EndpointPaths.USERS; 
		ServerResponse<User> response = scimRequestBuilder.create(User.class, endpointPath).setResource(user)
				.sendRequest();
		if (response.isSuccess()) {
			User createdUser = response.getResource();
			System.out.println(createdUser);
		} else if (response.getErrorResponse() == null) {
			// the response was not an error response as described in RFC7644
			String errorMessage = response.getResponseBody();
			System.out.println("error message status: " + response.getHttpStatus());
			System.out.println("error message: " + errorMessage);
		} else {
			ErrorResponse errorResponse = response.getErrorResponse();
			// do something with it
			System.out.println("error message status: " + response.getHttpStatus());
			System.out.println("error response: "+errorResponse);
		}
	}

The list and get operations of this client application similarly build the request and use the SCIM-SDK library to make a SCIM compliant request. As noted above, you can view, download and run the client application by cloning the GitHub repository.

Congrats! You’ve configured FusionAuth as a SCIM server and created a SCIM client that can provision users with SCIM.

More Information