Getting started with SCIM
Enterprises need to automatically provision and de-provision employee access to applications to ensure security. Scalekit simplifies this process by providing a single interface to your app, abstracting the complexities of various directory providers.
With SCIM Provisioning from Scalekit, you can:
-
Use webhooks to listen for events from your customers’ directory providers (e.g., user updates, group changes)
-
Use REST APIs to list users, groups, and directories on demand
Scalekit enables you to sync user accounts with the latest data in the directory provider. This allows you to:
- Create accounts for new hires during onboarding
- Deactivate accounts when employees depart
- Adjust access levels as employees change roles
-
User provisioning with Scalekit’s directory API
Section titled “User provisioning with Scalekit’s directory API”Scalekit’s directory API allows you to fetch information about users, groups, and directories associated with an organization on-demand. This is useful for scenarios like running cron jobs to sync user and group data. In this guide, we’ll demonstrate how to use the list users in a directory API to retrieve a list of users in a specific directory.
Before you begin, ensure that your organization has a directory set up in Scalekit.
Before diving in, ensure you have:
- A Scalekit account
- An organization with a configured directory
- Access to the Scalekit dashboard
Setting up the SDK
Section titled “Setting up the SDK”Scalekit offers language-specific SDKs for fast SSO integration. Use the installation instructions below for your technology stack:
npm install @scalekit-sdk/nodepip install scalekit-sdk-pythongo get -u github.com/scalekit-inc/scalekit-sdk-go/* Gradle users - add the following to your dependencies in build file */implementation "com.scalekit:scalekit-sdk-java:1.1.3"<!-- Maven users - add the following to your `pom.xml` --><dependency><groupId>com.scalekit</groupId><artifactId>scalekit-sdk-java</artifactId><version>1.1.3</version></dependency>Navigate to the API config tab in the Scalekit dashboard to obtain your credentials. Store your credentials securely in a
.env
file:.env SCALEKIT_ENVIRONMENT_URL='https://b2b-app-dev.scalekit.com'SCALEKIT_CLIENT_ID='<CLIENT_ID_FROM_SCALEKIT_DASHBOARD>'SCALEKIT_CLIENT_SECRET='<SECRET_FROM_SCALEKIT_DASHBOARD>'Initialize the SDK with your API credentials and make your first API call to list organizations.
Terminal window curl -L 'https://$ENV_URL/api/v1/organizations?page_size=5' \-H 'Authorization: Bearer <ACCESS_TOKEN>'import { ScalekitClient } from '@scalekit-sdk/node';const scalekit = new ScalekitClient(process.env.SCALEKIT_ENVIRONMENT_URL,process.env.SCALEKIT_CLIENT_ID,process.env.SCALEKIT_CLIENT_SECRET,);const { organizations } = await scalekit.organization.listOrganization({pageSize: 5,});console.log(`Name of the a organization: ${organizations[0].display_name}`);from scalekit import ScalekitClient# Initialize the SDK clientscalekit_client = ScalekitClient('<SCALEKIT_ENVIRONMENT_URL>','<SCALEKIT_CLIENT_ID>','<SCALEKIT_CLIENT_SECRET>')org_list = scalekit_client.organization.list_organizations(page_size='100')print(f'Organisation details: {org_list[0]}')sc := scalekit.NewScalekitClient(<SCALEKIT_ENVIRONMENT_URL>,<SCALEKIT_CLIENT_ID>,<SCALEKIT_CLIENT_SECRET>)organization, err := sc.Organization.GetOrganization(ctx,organizationId)import com.scalekit.ScalekitClient;ScalekitClient scalekitClient = new ScalekitClient("<SCALEKIT_ENVIRONMENT_URL>","<SCALEKIT_CLIENT_ID>","<SCALEKIT_CLIENT_SECRET>");ListOrganizationsResponse organizations = scalekitClient.organizations().listOrganizations(5, ""); -
Working with directories
Section titled “Working with directories”Retrieving a directory
Section titled “Retrieving a directory”To begin syncing user and group data, first retrieve the directory associated with your organization:
// Get directory using organization ID and directory IDconst { directory } = await scalekit.directory.getDirectory('<organization_id>', '<directory_id>');// Get directory using organization IDconst { directory } =await scalekit.directory.getPrimaryDirectoryByOrganizationId('<organization_id>');# Get directory using organization ID and directory IDdirectory = scalekit_client.directory.get_directory(organization_id='<organization_id>', directory_id='<directory_id>')# Get directory using organization IDprimary_directory = scalekit_client.directory.get_primary_directory_by_organization_id(organization_id='<organization_id>')// Get directory using organization ID and directory IDdirectory, err := sc.Directory().GetDirectory(ctx, organizationId, directoryId)// Get directory using organization IDdirectory, err := sc.Directory().GetPrimaryDirectoryByOrganizationId(ctx, organizationId)// Get directory using organization ID and directory IDDirectory directory = scalekitClient.directories().getDirectory("<directoryId>", "<organizationId>");// Get directory using organization IDDirectory directory = scalekitClient.directories().getPrimaryDirectoryByOrganizationId("<organizationId>");Listing users in a directory
Section titled “Listing users in a directory”Fetch users within a specific directory:
const { users } = await scalekit.directory.listDirectoryUsers('<organization_id>', '<directory_id>');// users[0].email has the email of the first user in the directorydirectory_users = scalekit_client.directory.list_directory_users(organization_id='<organization_id>', directory_id='<directory_id>')options := &ListDirectoryUsersOptions{PageSize: 10,PageToken: "",}directoryUsers,err := sc.Directory().ListDirectoryUsers(ctx, organizationId, directoryId, options)var options = ListDirectoryResourceOptions.builder().pageSize(10).pageToken("").includeDetail(true).build();ListDirectoryUsersResponse usersResponse = scalekitClient.directories().listDirectoryUsers(directory.getId(), organizationId, options);Example Use Case: When setting up a new customer account, you can use this function to automatically connect to their directory and start syncing user data.
Listing groups
Section titled “Listing groups”Retrieve groups within a directory:
const { groups } = await scalekit.directory.listDirectoryGroups('<organization_id>','<directory_id>',);directory_groups = scalekit_client.directory.list_directory_groups(directory_id='<directory_id>', organization_id='<organization_id>')options := &ListDirectoryGroupsOptions{PageSize: 10,PageToken:"",}directoryGroups, err := sc.Directory().ListDirectoryGroups(ctx, organizationId, directoryId, options)var options = ListDirectoryResourceOptions.builder().pageSize(10).pageToken("").includeDetail(true).build();ListDirectoryGroupsResponse groupsResponse = scalekitClient.directories().listDirectoryGroups(directory.getId(), organizationId, options);Example Use Case: You can use this function to implement role-based access control in your application, assigning permissions based on the groups a user belongs to.
Scalekit’s Directory API provides a simple way to fetch user and group information on-demand. Refer to our API reference and examples to explore more capabilities.
-
Realtime user provisioning with webhooks
Section titled “Realtime user provisioning with webhooks”Create a webhook endpoint
Section titled “Create a webhook endpoint”To receive realtime events from directory providers, create a webhook endpoint and register it in the Scalekit dashboard.
app.post('/webhook', async (req, res) => {// Parse the JSON body of the requestconst event = req.body;const { email, name } = event.data;const headers = req.headers;const secret = process.env.SCALEKIT_WEBHOOK_SECRET;try {// Verify the webhook payload using the secret, headers, and event dataawait scalekit.verifyWebhookPayload(secret, headers, event);} catch (error) {// Return a 400 response if the signature is invalidreturn res.status(400).json({ error: 'Invalid signature' });}// Call a function to perform business logicawait createUserAccount(email, name);// Return a JSON response with a status code of 201res.status(201).json({ message: 'User account created' });});from fastapi import FastAPI, Requestapp = FastAPI()@app.post("/webhook")async def api_webhook(request: Request):headers = request.headersbody = await request.json()print(scale.verify_webhook_payload(secret='<secret>', headers=headers, payload=json.dumps(body).encode('utf-8')))# business logic to create user accountawait create_user_account(email, name);response = JSONResponse(status_code=201, content='')return response@PostMapping("/webhook")public String webhook(@RequestBody String body, @RequestHeader Map<String, String> headers) {String secret = "<WEBHOOK SECRET>";boolean valid = scalekit.webhook().verifyWebhookPayload(secret, headers, body.getBytes());if (!valid) {return "error";}ObjectMapper mapper = new ObjectMapper();try {JsonNode node = mapper.readTree(body);String object = node.get("object").asText();JsonNode data = node.get("data");System.out.println("Object: " + object);System.out.println("Data: " + data);//business logic on data goes here} catch (IOException e) {return "error";}return "ok";}webhookSecret := os.Getenv("SCALEKIT_WEBHOOK_SECRET")mux.HandleFunc("POST /webhook", func(w http.ResponseWriter, r *http.Request) {body, err := io.ReadAll(r.Body)if err != nil {http.Error(w, err.Error(), http.StatusBadRequest)return}headers := map[string]string{"webhook-id": r.Header.Get("webhook-id"),"webhook-signature": r.Header.Get("webhook-signature"),"webhook-timestamp": r.Header.Get("webhook-timestamp"),}_, err = sc.VerifyWebhookPayload(webhookSecret, headers, body)if err != nil {http.Error(w, err.Error(), http.StatusUnauthorized)return}w.WriteHeader(http.StatusOK)})In this example, the endpoint URL is
https://www.your-app.app/api/webhook/user-access
When the endpoint receives an HTTP POST request with event data, it extracts the name and email from the payload and calls
createUserAccount()
to perform the necessary business logic — in this case, creating a user account.Register webhook endpoint
Section titled “Register webhook endpoint”First, navigate to the “Webhooks” tab in the Scalekit Dashboard. Click on the “+Add Endpoint” button and enter the endpoint URL along with a meaningful description. Finally, select the desired event types, for example
organization.directory.user_created
, to subscribe to the relevant events.Click “Create” Once registered, the webhook endpoint will start receiving event payloads from the directory providers.
Refer to the API reference for the list of all available event types and setting up webhooks to explore testing webhooks with test endpoints.
Receive event payloads
Section titled “Receive event payloads”Scalekit sends event payloads to your app for consumption and standardizes the payload structure across different directory providers your customers may use.Since we subscribed to user events, let’s log an example of a new hire gaining access to your app when Scalekit sends a user creation event.
See Webhook events for the list of all available event types.
You have now successfully created and registered a webhook endpoint, allowing your app to receive real-time events to automate user provisioning.