Search
Menu
Search
/
Sign in

Directory Sync

Build frictionless onboarding for entire organizations with real-time provisioning and deprovisioning of users based on changes to your customers’ directories.

IntroductionLink

Organizations use directories from providers like Okta or Workday to easily manage employees and user access to resources. Directories enable IT admins to activate and deactivate employee accounts, create groups that inform access rules, accelerate adoption of new tools, and more. Directory Sync connects your application with their directories, keeping your app informed of any changes in their users, groups, and access rules. Get seamless user lifecycle management for both you and your customers by keeping your app in sync with their employee directory.

The WorkOS Directory Sync API supports read-only operations. We will never mutate end-user directories.
Request a Directory Provider

Don't see a Directory Provider you need? Contact us to request a Directory Provider!

What you’ll buildLink

In this guide, we’ll take you from learning about Directory Sync and POC-ing all the way through to building production-ready features fully integrated with the WorkOS Directory Sync API.

Sign in to your Developer Dashboard account to see code examples pre-filled with your API keys and resource IDs.

This guide will show you how to:

Before getting startedLink

To get the most out of this guide, you’ll need:

API Object DefinitionsLink

ObjectDefinition
DirectoryA Directory stores information about an Enterprise’s employee management system (i.e. Directory Provider).
Directory UserA Directory User represents an Enterprise user that is active in an Enterprise’s Directory Provider.
Directory GroupA Directory Group is an organizational unit of Enterprise users, e.x. IT admins, HR, Database admins, etc.

1
Create a new Directory ConnectionLink

The first step to connecting with an organization’s directory is creating a new Connection to the directory. You can do this in the Directory Sync Dashboard. Let’s start by creating one for development in your Sandbox Project - get Directory Provider specific instructions by selecting which directory provider you want to connect to.

The unique identifier for the Directory is the last part of the URL path and takes the form directory_*
Directory Provider
  • Azure AD SCIM
  • BambooHR
  • G Suite
  • Gusto
  • Hibob
  • Okta SCIM v1.1
  • Okta SCIM v2.0
  • Rippling
  • SCIM v1.1
  • SCIM v2.0
  • Workday
Instructions

You can create a Connection with Azure AD SCIM by reading through our integration guide below. It provides end-to-end instructions for creating your Connection in the WorkOS Developer Dashboard.

Connect to Azure AD SCIM

Our guide to creating a new Connection with to Azure AD SCIM.

2
Add Directory Sync to your appLink

Let’s add Directory Sync to your app to enable programmatic fetching on Directory resources.

1. Install the WorkOS SDK of your choiceLink

WorkOS offers native SDKs in several popular programming languages. Choose a language below to see instructions in your application’s language.

  • Node.jsNode.js
  • RubyRuby
  • GoGo
  • PythonPython
  • PHPPHP
  • LaravelLaravel
  • .NET.NET
Request an SDK

Don't see an SDK you need? Contact us to request an SDK!

Install the SDK using the command below.

Install the WorkOS SDK

Switch
Copy
npm install @workos-inc/node
You can also download the workos-node source code from GitHub.

2. Set environment variablesLink

As a best practice, your WorkOS API key should be kept secret and set as an environment variable on process start. The Project ID should also be set dynamically based on the release environment.

Environment Variables

Copy
WORKOS_API_KEY='{secretKey}'
WORKOS_CLIENT_ID='{clientID}'

3. Fetch Directory resourcesLink

Get Directory UserList Directory UsersGet Directory GroupList Directory Groups

Get the details of an existing Directory User.

Get User

Switch
Copy
1
2
3
4
5
6
const WorkOS = require('@workos-inc/node');

const workos = new WorkOS(process.env.WORKOS_API_KEY);

directoryUserID =  // ... The ID of the Directory User to fetch
const user = await workos.directorySync.getUser(directoryUserID);
Example use case: Pre-populate user attributes for new user accounts.

3
Get real-time updates with incoming webhooksLink

Subscribe your app to changes in Directories by registering incoming webhooks to receive Directory Sync events.

There is currently no rate limiting on event deliveries.

Event TypesLink

1. Build a webhook URLLink

Webhooks should use HTTPS and expect to receive POST requests with the following headers:

KEYVALUE
Content-Typeapplication/json
WorkOS-Signaturet=${issued_timestamp}, v1=${signature_hash}

Below, we’ve provided example approaches for implementing a webhook endpoint.

Webhook endpoint

Switch
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const express = require('express')

const app = express();

app.use(express.json());

app.post('/webhook', (req, res) => {
  const sig = req.headers['workos-signature'];
  const { data, event } = req.body;

  // Verify the signature and process the event

  res.json(req.body);
});

2. Register the webhookLink

Set and save the webhook URL in the Developer Dashboard so WorkOS knows where to deliver events.

The Webhook Secret is used to verify webhook requests from WorkOS. Be sure to keep the value secure.

3. Receive eventsLink

We suggest handling events using two concurrent processes to avoid the possibility of unnecessary retry requests hitting your webhook handler.

Process A: Respond with HTTP 200 OKLink

On receiving an event, you should respond with an HTTP 200 OK. Otherwise, WorkOS will consider the event delivery a failure and retry up to 12 times, with exponential backoff over 3 days.

Process B: Process the requestLink

Before processing the request payload, verify the request was sent by WorkOS and not an unknown party.

First, extract the timestamp and signature from the header. There are two values to parse from the WorkOS-Signature, delimited by a , character.

  1. issued_timestamp: The epoch time at which the event was issued, prefixed by t=.
  2. signature_hash: The HMAC SHA256 hashed signature for the request, prefixed by v1=.

Extract timestamp and signature

Switch
Copy
1
2
3
4
const signature = req.headers['workos-signature'];
const [t, v1]= signature.split(',');
const { 1: issuedTimestamp } = t.split('=');
const { 1: signatureHash } = v1.split('=');

To avoid replay attacks, we suggest validating that the issued_timestamp does not differ too much from the current time.

Validate timestamp

Switch
Copy
1
2
3
4
5
6
const MAX_SECONDS_SINCE_ISSUED = 3 * 60; // Replace this value with your own limit
const currentTime = Date.now();
const secondsSinceIssued = (currentTime - issuedTimestamp) / 1000;
if (secondsSinceIssued > MAX_SECONDS_SINCE_ISSUED) {
  // Reject event
}

Construct the expected signature. The expected signature is computed from the concatenation of:

  1. issued_timestamp
  2. The . character
  3. The request’s body as a utf-8 decoded string

Hash the string using HMAC SHA256, using the Webhook Secret as the key. The expected signature will be the hex digest of the hash.

Construct expected signature

Switch
Copy
1
2
3
4
5
6
7
8
9
import crypto from 'crypto';

const signedPayload = `${timestamp}.${JSON.stringify(req.body)}`;

const expectedSignature = crypto
  .createHmac('sha256', process.env.WEBHOOK_SECRET)
  .update(signedPayload)
  .digest()
  .toString('hex');

Compare signatures to make sure the webhook request is valid.

Compare signatures

Switch
Copy
1
2
3
if (signatureHash !== expectedSignature) {
  // Reject event
}

Once you’ve determined the event request is validly signed, it’s safe to use the event, i.e. the request body, in your application’s business logic.

Go live checklistLink

Make sure you're ready to go live to production by going through this checklist.

You may occasionally receive duplicate webhook events. To prevent duplicate processing of events, we suggest caching received events and implementing logic to skip processing seen events.

Since webhook events may be delivered out of order, i.e. not in the order in which they were generated, be sure to handle accordingly. The issued_timestamp extracted from the WorkOS-Signature header can be used to determine order.

Depending on your network architecture, you may need to allowlist incoming traffic from api.workos.com.

WorkOS currently cannot promise that webhook traffic will originate from a static set of IP addresses.