Search
Menu
Search
/
Sign in

Admin Portal

A first-class, out-of-the-box Single Sign-On and Directory Sync onboarding and management experience for enterprise IT admins.

IntroductionLink

The Admin Portal provides an out-of-the-box UI for IT admins to configure SSO and Directory Sync Connections. Designed to remove friction, custom walk-through documentation for each Identity Provider means that enterprise admins can onboard their orgs without high-touch support from your team. Easy to integrate and fully maintained and hosted by WorkOS, the Admin Portal makes the SSO and Directory Sync setup process simple, fast, and secure.

What you’ll buildLink

In this guide, we'll walk you through the full end-to-end integration of the Admin Portal into your application.

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
ConnectionA Connection represents the method by which an Enterprise’s users sign in to your application.
OrganizationAn Organization describes an Enterprise whose users sign in with a SSO Connection, or whose users are synced with a Directory Sync Connection.
Portal LinkA Portal Link is an ephemeral link to initiate an Admin Portal session.

1
Configure an Admin Portal redirect linkLink

Before integrating, you must first configure your app’s default redirect link in your Production Project. The default redirect link is where your Admin Portal users will be redirected once their session is complete, unless otherwise specified when generating an Admin Portal link. You can configure your redirect link in the Admin Portal Dashboard.

The redirect link must use HTTPS.

2
Add Admin Portal to your appLink

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!

1. Install the WorkOS SDK of your choiceLink

Command Line

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 Client ID should also be set dynamically based on the release environment.

Environment Variables

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

3. Create a new OrganizationLink

Each Admin Portal session is scoped to a specific Organization resource, meaning a session is only capable of managing a Connection that belongs to its associated Organization. Organizations may only have one Connection.

For every Enterprise in your application that would like access to the Admin Portal, you must create an Organization and maintain a reference to its ID.

Create an Organization when onboarding a new Enterprise.

Create an Organization

Switch
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const express = require('express');
const WorkOS = require('@workos-inc/node');

const app = express();

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

app.post('/provision-enterprise', (_req, res) => {
  const organizationName =  // ... The name of the Enterprise to provision
  const organizationDomains =  // ... The list of domains the Enterprise uses

  const organization = await workos.organizations.createOrganization({
    name: organizationName,
    domains: organizationDomains,
  });

  // You should persist `organization.id` since it will be needed
  // to generate a Portal Link.

  // Provision additional Enterprise-tier resources.
});

4. Redirect an IT admin to the Admin PortalLink

A Portal Link is your enterprise user’s gateway to accessing their Admin Portal. Each Portal Link is generated using an Organization resource ID. Only resources belonging to the specified Organization can be managed during a Portal Session.

In the API call to generate an Admin Portal Link, you will pass an intent with possible values of sso for an Admin Portal session to create an SSO connection, and dsync for an Admin Portal session to create a Directory Sync connection.

For security reasons, Portal Links expire 5 minutes after they’re created, so we recommend redirecting users immediately (i.e. don’t email the user Portal Links.)

The endpoint that redirects a user to the Admin Portal should be guarded by auth in your application and only available to IT admins.
If you’re interested in custom-labeling the Admin Portal, please reach out to WorkOS support.

Redirect to Admin Portal

Switch
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const express = require('express');
const WorkOS = require('@workos-inc/node');

const app = express();

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

app.get('/admin-portal', (_req, res) => {
  const organizationID =  // ... The ID of the organization to start an Admin Portal session for

  const { link } = await workos.portal.generateLink({
    organization: organizationID,
    intent: "sso",
    returnUrl: "https://www.example.com" //optional
  });

  res.redirect(link);
});

An optional return_url parameter can be used to describe exactly where a user should be sent when they are finished in the Admin Portal. If one is not provided, the default redirect link configured in the Admin Portal Dashboard is used.

3
Get real-time updates with incoming webhooksLink

Subscribe your app to changes in Connections by registering incoming webhooks to receive Connection 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 = `${issuedTimestamp}.${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 redirect and webhook traffic will originate from a static set of IP addresses.