SCIM

SCIM Implementation Using Okta

Hrishikesh Premkumar
CONTENTS

Today, companies deal with multiple clients, with hundreds of employees needing platform access. Traditionally, when new employees join, leave, or change roles, IT admins manually create, update, and delete user accounts across different applications. This time-consuming and error-prone process leads to employee access issues and potential security risks.

For instance, new hires may experience delays accessing necessary tools. When employees leave, the IT admin may forget to deactivate their account across integrated applications, which leads to exposing sensitive company data. 

SCIM (System for Cross-domain Identity Management) automates user provisioning and deprovisioning between identity providers, like Okta, and your SaaS applications. This post walks B2B developers through implementing SCIM with Okta to streamline identity management and improve security across your business applications.

SCIM - 101

SCIM is an open standard that simplifies user identity management across different platforms and applications. It allows organizations to automate creating, updating, and deleting user accounts between platforms.

At the core, there’s an identity provider (Okta), a service provider (your SaaS app), and a standard schema for user data. SCIM relies on REST APIs to sync user data, and SCIM connectors and endpoints send and receive this user information. When a change occurs in the directory (adding or deleting a user), SCIM automatically pushes the update to the connected applications and ensures that the data stays up-to-date.

With SCIM Provisioning, IT administrators can avoid manual errors and ensure that user roles, permissions, and access are synchronized across business-critical tools, improving security and operational efficiency.

SCIM connector
SCIM Connector

The above image explains SCIM using Google Workspace as an IdP and Slack as SP and how user attributes are synced across platforms.

To dive deeper, check out our comprehensive SCIM guide and directory sync setup guide for step-by-step instructions.

SCIM implementation with OKTA

In this section, we'll walk through implementing SCIM with Okta, focusing on production-grade implementation for B2B applications. The goal is to automate user provisioning and sync with minimal setup.

We’ll build a Python-based web app that stores users in a local database. To make this accessible over the internet, we’ll use Tailscale to expose the app securely. Next, we’ll configure an Okta SAML app, enabling provisioning for seamless SCIM integration. Finally, we’ll add a new user in Okta and watch as that user is automatically reflected in our local app, demonstrating the power of SCIM.

This example will demonstrate how large teams can be seamlessly onboarded, deprovisioned, and managed within your application, reducing the burden on IT administrators.

You can find the code for this sample application in this repository.

Building The Python App

The first step is to build the Python application. This is a simple Flask application with a front end and SQLite as the data store. The application exposes SCIM-compliant REST endpoints for performing various CRUD operations.

First, we import all the required modules and configure the SCIM_BASE_PATH, which will be appended to the root URL for all the API calls.

SCIM_BASE_PATH = '/scim/v2'

Below is the User schema that we store in our database.

class User(db.Model, Serializer): id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4())) userName = db.Column(db.String, unique=True, nullable=False) firstName = db.Column(db.String, nullable=False) lastName = db.Column(db.String, nullable=False) email = db.Column(db.String, unique=True, nullable=False)

We store the userName, firstName, lastName, email, and an auto-generated ID.

For security (and for configuring Okta), we add functionality to validate tokens to ensure that only authenticated requests can access the endpoints and modify the data. There’s also a token-gen.py file that generates a dummy token you can store as an environment variable and in the token. It’s understood that this shouldn’t be done for a production setup.

SCIM_TOKEN = os.environ.get('SCIM_TOKEN', 'your-secret-token-here') # Use the token-gen.py def requires_token_auth(f): @wraps(f) def decorated(*args, **kwargs): auth_header = request.headers.get('Authorization') if not auth_header or not auth_header.startswith('Bearer '): return jsonify({"error": "Invalid or missing token"}), 401 token = auth_header.split(' ')[1] if token != SCIM_TOKEN: return jsonify({"error": "Invalid token"}), 401 return f(*args, **kwargs) return decorated

We then create various endpoints for performing various operations.SCIM uses the standard REST methods to synchronize users. Here’s a method for creating a user with a POST request.

@app.route(f'{SCIM_BASE_PATH}/Users', methods=['POST']) @requires_token_auth def create_user(): data = request.json new_user = User( userName=data['userName'], firstName=data['name']['givenName'], lastName=data['name']['familyName'], email=data['emails'][0]['value'], ) db.session.add(new_user) db.session.commit() return jsonify(new_user.serialize()), 201

REST methods are crucial in this process as they provide a standardized way to perform CRUD (Create, Read, Update, Delete) operations on user data. In this case, Okta will reach the endpoints in our application and perform updates or sync whenever necessary. For instance, it does a GET call to get a list of users to validate the list of users at its end and updates the list accordingly. 

Similarly, we add all the required methods for adding, updating, and deleting users. To keep it simple, we don’t have any methods for dealing with groups. Have a look at the complete app.py file here.

We then create an index.html file under the templates folder, which is just the front end and lists everything in the database. While it’s unnecessary, having a dashboard where you can see the list of users rather than always running a command is easier.

With this, our Python application is ready to integrate with Okta. 

Configuring Tailscale

Since our Python application is running locally, we need to expose the application to the internet so that Okta can access it and send requests. This is possible with many tools, and we’ll be using Tailscale. Tailscale sets up a reverse tunnel that allows us to access the server on our machine via the internet securely.

Set up a Tailscale account and configure your machine. You can follow their installation guide to get started in 4 simple steps.

Once installed, run your Python application using python app.py. In a new terminal window, execute tailscale funnel 5000. This will expose your application to the internet and give you a public URL. Note: don’t close the terminal window.

tailscale funnel 5000 Available on the internet: https://atulpriya-sharma.tailff6d6a.ts.net/ |-- proxy http://127.0.0.1:5000

We’ll use this URL to configure Okta. 

Configuring Okta

To configure Okta, you first need to register for a developer account. The free developer account allows you to create a certain number of applications and users, which is perfect for building POCs and demos.

Create a User

Log in to your Okta account and navigate to “Directory” -> “People” and click on “Add Person”. 

Okta create a user
Add Person in Okta account

Fill in the details like first name, last name, username, and email, and save the user.

find people details in okta
Find details

Once the user is created, we can assign it to the application.

Create an Application

To create an Application, navigate to “Applications” in the same dashboard and click on “Create App Integration.” 

Create App Integration in Okta
Create app integration in Okta

It opens up a dialog box for you to choose the type of application. In this case, we’ll choose SAML.

Select SAML for okta integration
Choose SAML

Provide a name for the application and click “Next.” Provide the Single Sign-On (SSO) URL and the SP Entity ID. We’ll use the application's tail-scale URL here. Please note that we are not going to configure SSO. We’ll just showcase SCIM and directory sync capabilities.

Configure SAML for SCIM
Configure SAML

Update that this is an internal application and Save it. This will create a new application for you.

Help Okta Support understand how you configured this application
Update as an internal app

Configure Directory Sync

After you’ve created the application, navigate to the “General” tab and check the “Provisioning” checkbox to enable SCIM provisioning.

Configure Directory Sync
Enable SCIM provisioning

You’ll now see a “Provision” tab. Navigate to it to configure directory sync. You need to provide the following details: 

  • SCIM Version: v2 
  • SCIM connector base URL: Provide your application's URL. In our case, it’s the Tailscale URL and the SCIM_BASE_URL we configured in our app.py. 
  • Supported Provisioning Actions: This is the list of operations you want to enable as part of SCIM. We’ll check all of them, though we only have user-related endpoints.
  • Authentication mode: It provides you with different authentication options. We’ll choose HTTP Header.
  • Authorization: Since we chose the authentication mechanism as HTTP Header, we have to provide a token. Paste the same token that you configured in your app.py. This is not recommended for production scenarios.
Directory Sync provisioning configuration
Provisioning actions

After entering all the details, click on “Test Connector Configuration”. If everything is configured correctly, the dialog box “Connector configured successfully” will display, with a checkbox for all the provisioning actions we chose during configuration.

Test Directory Sync Connector configuration
Test connector configuration

After that, click on the “Activate” button to enable the integration. At this point, we have successfully integrated Okta’s SCIM provisioning with your custom Python application.

Testing the integration

To test the integration, navigate to the “Assignments” tab and click on “Assign” -> “Assign to People” option. 

Testing Directory Sync integration for Okta
Testing the integration

It will open the list of users. Choose the user we created earlier, Alan in this case.

Assign SCIM
Choose the user we created

Click on “Assign”, this will open a dialog box for you to provide more details for the user. You can validate if the existing details are correct and click “Done”.

Choosing user for okta directory sync testing
Assign the user

You’ll see that the user “Alan Turing” is successfully assigned to the application.Click on “Assign”, this will open a dialog box for you to provide more details for the user. You can validate if the existing details are correct and click “Done”.

user created for Directory Sync testing
User Created

At the same time, navigate to the Python application's logs, and you’ll see the following request sent by Okta to your application.

2024-09-11 12:59:16,115 - Payload: {"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],"userName":"alan.turing@scalekit.com","name":{"givenName":"Alan","familyName":"Turing"},"emails":[{"primary":true,"value":"alan.turing@scalekit.com"}],"externalId":"00ujeo4y6rv7WBJdG5d7","groups":[],"active":true} 2024-09-11 12:59:16,224 - 127.0.0.1 - - [11/Sep/2024 12:59:16] "[35m[1mPOST /scim/v2/Users HTTP/1.1[0m" 201 -

This is a POST call made to the application with a SCIM object that includes the user details like username, name, and email. The request hits our “Users” endpoint, and the create_user method first authenticates the request and then adds the details to the user database. 

You can also validate it in the UI we created. Locally, navigate to http://127.0.0.1:5000 or use the Tailscale URL to access the dashboard. You’ll see the user Alan Turing being added to the database.

SCIM user management
SCIM user management

Similarly, we can configure Okta so that when we add or delete a user in our application, the user is also added or removed from Okta. 

By configuring Okta and enabling provisioning, our local app seamlessly reflected new users added to Okta in real time. This setup showcases the simplicity and efficiency SCIM brings to identity management, reducing manual tasks and errors and improving security.

Advanced Configurations

For enterprise-level applications, PATCH operations, and filtering can enhance your SCIM implementation by allowing more granular control over user data. 

PATCH 

One of the major reasons SCIM uses REST APIs is for standardization and simplicity. However, the PATCH operation can be tricky to deal with. Since PATCH only updates certain attributes, the exact behaviors vary among IdPs.

To control this, SCIM spec recommends a /ServiceProviderConfig endpoint that allows your application to inform the IdP of operations it supports. For instance, you can declare if PATCH is supported by your SCIM server as follows.

{ "patch": { "supported": false } }

By setting PATCH supported to FALSE, IdPs can tweak their behavior to work with your application. In this case, it could be replacing PATCH with PUT. Implementing this endpoint in your application is good practice. 

Filter

Apart from just the CRUD operations, SCIM also provides the ability to filter the results, which is very handy for large-scale user management. You can create endpoints to enable filtering, as this will significantly enhance the flexibility and power of your SCIM API and make the entire process efficient. 

For instance, A SCIM Client can invoke the following endpoint to find all users with "Turing" in their family name and who also have an employee number. The 'co' operator means "contains", and 'pr' means "present".

GET /Users?filter=name.familyName co "Turing" and employeeNumber pr

These advanced configurations make SCIM an excellent choice for simple to fine-grained use cases.

Summary

In the complex application setup that we work with, manual user management is inefficient and leads to errors and security risks. SCIM offers a solution by automating the user provisioning and deprovisioning process between identity and service providers. 

In this post, we looked at the need for SCIM and how it simplifies directory sync operations. We also looked at a demo of integrating SCIM with a custom Python app, showcasing how user data is seamlessly synced using Okta’s provisioning capabilities.

By adopting SCIM, companies can enhance security, streamline user management, and reduce the overhead on IT teams. For more in depth information on SCIM, do check out our SCIM guide.

Resources

No items found.
Ship Enterprise Auth in days

Ship enterprise auth in hours