# WorkOS Documentation > WorkOS is the enterprise authentication and identity platform for SaaS companies. AuthKit ships email/password, social login, passkeys, MFA, magic auth, and enterprise SSO from one integration, and is free up to 1M monthly active users. Enterprise APIs include Single Sign-On, SCIM Directory Sync, RBAC, Audit Logs, Radar (bot and fraud protection), Vault, and a no-code Admin Portal — priced per connection with volume discounts. SDKs for Node, Python, Go, Ruby, PHP, Java, and .NET. This documentation site provides guides, references, and examples for implementing WorkOS features in your applications. - [Postman](#postman) - [On prem deployment](#on-prem-deployment) - [Migrate standalone sso](#migrate-standalone-sso) - [Mcp](#mcp) - [Glossary](#glossary) - [Email](#email) - [Widgets](#widgets) - [Vault](#vault) - [Single Sign-On](#sso) - [Sdks](#sdks) - [API Reference](#reference) - [RBAC](#rbac) - [Pipes](#pipes) - [Migrations](#migrate) - [Multi-Factor Auth](#mfa) - [Magic Link](#magic-link) - [Integrations](#integrations) - [FGA](#fga) - [Feature Flags](#feature-flags) - [Events](#events) - [Domain Verification](#domain-verification) - [Directory Sync](#directory-sync) - [Deprecations](#deprecations) - [Custom Domains](#custom-domains) - [AuthKit](#authkit) - [Audit Logs](#audit-logs) - [Admin Portal](#admin-portal) ## Getting started - [Auth](https://workos.com/auth.md): Instructions for how agents can set up a new WorkOS account and start developing with the SDKs. ## Pricing - [Pricing](https://workos.com/pricing.md): WorkOS pricing details for AuthKit, SSO, Directory Sync, Audit Logs, Radar, and more. ## Postman {#postman} ### WorkOS Postman collection Test the WorkOS API with Postman. ## Introduction Postman is a popular API development tool that allows users to easily test API endpoints. The [WorkOS API collection](https://www.postman.com/workos/workspace/workos-public/collection/25188762-79ce1172-4741-4f1d-a486-64380f9a599f?ctx=documentation) is a set of pre-configured requests specific to the WorkOS API, meant to help developers to quickly get started testing the WorkOS API endpoints. The [environment template](https://www.postman.com/workos/workspace/workos-public/environment/25188762-b99e7518-d907-4aa0-82d2-a199157a53c7) supports this collection, and allows variables to be abstracted away from the individual requests. The environment template makes it easier to manage and re-use common variables across the collection's requests. ## Configuring Postman There are several ways to use this collection. You can create a fork, or you can export/import the collection and environment. ### Creating a fork The preferred and simplest way to get started using the WorkOS API collection is to create a fork of the collection and environment. To create a fork of the collection, first sign in to your Postman account. Then navigate to the WorkOS API collection. Hover over the name of the collection and click the three dots, then click "Create a fork". ![A screenshot showing how to fork a collection in Postman](https://images.workoscdn.com/images/a3d67b02-a824-4f27-b055-c06eaf5a7e94.png?auto=format&fit=clip&q=50) Select your fork label and workspace, then click the "Fork collection" button. ![A screenshot showing the fork collection details page in Postman.](https://images.workoscdn.com/images/c9074bd3-8ab8-4864-9b68-56c6a858a17e.png?auto=format&fit=clip&q=50) You will now see the WorkOS API collection appear in your workspace's collection tab. To fork the WorkOS environment template, the same process is used. Navigate to the environments tab of the WorkOS Public workspace. Hover over the WorkOS environment template, click the three dots, and then click "Create a fork". Select your fork label and workspace, then click the "Fork environment" button. ### Exporting the collection and environment Another way to use the WorkOS API collection is to import the collection and environment into your workspace. Using this approach allows you to share the collection as a JSON file to easily share it with others. To export the collection, navigate to the collection tab in the WorkOS workspace, then hover over the WorkOS API collection name and click on the three dots. Click export to download the collection as a JSON file. ![A screenshot showing the export option in Postman.](https://images.workoscdn.com/images/54aed639-6c8f-467e-baa6-53099c36fe35.png?auto=format&fit=clip&q=50) Navigate to your workspace's collections tab and click on the import button. ![A screenshot showing where to find the import button in Postman.](https://images.workoscdn.com/images/802d9d45-c258-4548-9f88-7d04f2d260c2.png?auto=format&fit=clip&q=50) Select the JSON file that was downloaded in the previous step and then click import. You will now see the collection available to use and edit in the collection tab. The environment can be exported from the WorkOS workspace and imported to your personal workspace using these same steps. Navigate to the collection tab in your workspace and select the environment. This allows the collection to reference the environment variables. ## Environment variables The WorkOS API collection makes use of environment variables. All environment variables that are used in the WorkOS API collection are defined in the environment tab in Postman. ![A screenshot showing the environments tab in Postman.](https://images.workoscdn.com/images/bd26c85b-8d66-478c-909b-f5ee01ffaffd.png?auto=format&fit=clip&q=50) To get started, you will need to obtain the `api_key` and `client_id` values from your WorkOS dashboard and enter them in the environment template. You can find your API key and the client ID on the [API Keys](https://dashboard.workos.com/api-keys) page in the WorkOS dashboard. There are also several other environment variables in the template which will need to be replaced with various IDs and values in the course of making API calls. These values are defined in the variable descriptions. ## Sending requests to the WorkOS API The WorkOS collection sends data in several ways. Some requests use values directly in the URL, some requests use query parameters, and some requests send data in the body of the request. Each call will indicate where there are values present with a green dot. The "Get A Directory User" request for instance uses the `api_key` environment variable in the authorization tab of the request, and the `base_url` and `directory_user_id` values in the URL of the request. ![A screenshot showing the Get a Directory User request in Postman.](https://images.workoscdn.com/images/76d3df52-cf4e-467a-a898-df62a920a800.png?auto=format&fit=clip&q=50) The "Generate a Portal Link" request uses the `base_url` and `api_key` variables in the same way that the Get A Directory User call does, but also sends the name of the Organization and intent in the body of the request as x-www-form-urlencoded data. ![A screenshot showing the Generate a Portal Link request in Postman.](https://images.workoscdn.com/images/c2ae7131-dc79-49ee-aac1-724d3de42c48.png?auto=format&fit=clip&q=50) To send a request, first select the WorkOS environment template so the collection has access to its variables. ![A screenshot showing where to select the Environment in Postman.](https://images.workoscdn.com/images/fea5d174-0fea-400b-b498-3753c85c5eeb.png?auto=format&fit=clip&q=50) Finally, ensure all the values are defined where they are needed for the particular request and then click send. ## Debugging requests Postman provides a developer console if you need to debug any requests. Navigate to a request and click on the console button to view the details of the requests you send. ![A screenshot showing the developer console in Postman.](https://images.workoscdn.com/images/9dafe4a0-5a9a-46d3-bee9-ba01d5b25724.png?auto=format&fit=clip&q=50) If you have any questions while using the WorkOS API collection, please reach out to our team at [support@workos.com](mailto:support@workos.com). ## On prem deployment {#on-prem-deployment} ### Using WorkOS with On-prem Customers Best practices for using WorkOS with on-prem customers. ## Introduction WorkOS can be used with both cloud and on-prem deployments. This guide explains the considerations needed to use WorkOS features with on-prem deployment strategies. For example, many SaaS companies offer enterprise solutions where their infrastructure can be deployed to a customer's cloud or data center. When using an on-prem deployment strategy, two key considerations are: - Deploying a static API key to each customer's installation to isolate access to their team only - Ensuring your customer's network can send and receive requests from the WorkOS API Outside of these considerations, WorkOS integration for on-prem customers functions in the same way as in cloud deployments. ![diagram showing on-prem configuration using WorkOS](https://images.workoscdn.com/images/17460e43-790f-4791-93ee-f0b001ef5eae.png?auto=format&fit=clip&q=50) ## Using a static API key for each customer's deployment Since a full deployment of your software is being deployed to your customer's environment, each deployment requires its own unique WorkOS API key. This can be accomplished by creating a separate environment in your WorkOS dashboard for each on-prem customer. Each WorkOS workspace comes with Staging and Production environments by default. To create a new environment for an on-prem customer: - Reach out to the WorkOS support team at [support@workos.com](mailto:support@workos.com) - Provide the name you'd like to use for the new environment and specify that it should be a production environment ![diagram showing different environments in the WorkOS dashboard](https://images.workoscdn.com/images/2e280efe-011f-4583-9c67-1fedd60f0071.png?auto=format&fit=clip&q=50) The support team will create the environment, which will then be available in the environments dropdown menu in your WorkOS workspace. To retrieve the client ID and API key for this environment, navigate to the [API Keys section](https://dashboard.workos.com/api-keys) of the WorkOS dashboard where the values are available to download. ## Allowing WorkOS Traffic Through Firewalls A common challenge with on-premise deployments is coordinating which traffic will be allowed by the firewall. Several strategies exist for allowing traffic to and from WorkOS to communicate with an on-prem deployment. ### Strategy 1: Configure Firewall Rules or ACLs The most common approach is to deploy your application with the WorkOS integration to your customer's on-prem environment configured the same as you would for cloud application users, then have the firewall rules or access control lists (ACLs) set to allow WorkOS API traffic. WorkOS uses Cloudflare to ensure security and reliability. If you need to allowlist IP addresses for redirect requests, you can use the IP ranges listed in the [Cloudflare documentation](https://www.cloudflare.com/ips/). ![diagram showing different environments in the WorkOS dashboard](https://images.workoscdn.com/images/23e605b6-2b82-41be-a93b-664d07b07d0a.png?auto=format&fit=clip&q=50) #### Firewall Ingress Rules (Incoming Traffic) Ingress rules control external traffic entering your network. Some features of WorkOS require requests originating from our APIs directly to the on-prem installation, such as authentication callbacks, action callbacks, and webhooks. Events can also be ingested with the Events API, which is the preferred method for event delivery in an on-prem deployment scenario since those requests will originate from your on-prem application infrastructure. - All requests use HTTPS on port 443 - All authentication requests originate from [Cloudflare's published IP ranges](https://www.cloudflare.com/ips/) - All outbound requests for [Actions Webhooks](/authkit/actions) and [event and log streaming](/events/observability/datadog) will originate from the following IP ranges: - 3.217.146.166 - 23.21.184.92 - 34.204.154.149 - 44.213.245.178 - 44.215.236.82 - 50.16.203.9 - 52.1.251.34 - 52.21.49.187 - 174.129.36.47 - Requests will require an external domain name that resolves to the installation's host #### Firewall Egress Rules (Outgoing Traffic) Egress rules manage traffic leaving your network to external services. Key aspects include: - All requests leave the on-prem network over HTTPS on port 443 - All traffic is handled on Cloudflare's published IP ranges ##### Best Practices - Apply the principle of least privilege - Log and monitor cross-boundary traffic - Regularly audit firewall rules Implement a workflow of starting with restrictive default deny rules, then carefully opening only necessary ports and protocols to ensure that your integration with WorkOS is secure. ### Strategy 2: Use ngrok for Network Traffic Management Another approach is to use a service like [ngrok](https://ngrok.com/) to manage traffic to and from the WorkOS API instead of modifying firewall rules. This approach allows you to implement WorkOS authentication without adjusting firewall configurations. With ngrok, you can: - Create secure tunnels from the public internet to your on-premise deployment - Receive webhook events from WorkOS directly to your local development environment - Implement WorkOS AuthKit, SSO and Directory Sync features in environments with restrictive network policies Implementation involves installing the ngrok client on your application server, establishing a tunnel to your application's local port, and configuring your WorkOS integration to use the ngrok-provided public URL. ![diagram showing a WorkOS on-prem configuration using ngrok ](https://images.workoscdn.com/images/42766c0c-741c-460f-818f-6bb4875634ca.png?auto=format&fit=clip&q=50) This approach requires configuration of third-party software and additional cost. ngrok offers different pricing tiers based on your needs, with paid plans providing features like persistent URLs, IP restrictions, and additional security controls essential for production environments. ## Air-Gapped Environments For customers operating in air-gapped environments with no external network connectivity, cloud-based authentication services like WorkOS cannot be utilized as they require API connectivity. However, many organizations with air-gapped environments have established security protocols that permit the deployment of approved third-party software within their isolated networks, as their security architecture already provides robust authentication mechanisms internally. In these scenarios, we recommend a dual-implementation approach: - Continue leveraging WorkOS for authentication in cloud-based and network-connected on-premises deployments - Develop a specialized deployment package for air-gapped environments that: - Integrates with the customer's existing internal authentication infrastructure - Maintains feature parity while operating independently of external services - Adheres to the security policies specific to air-gapped environments This approach allows you to maintain a consistent product experience across different deployment scenarios while accommodating the strict security requirements of air-gapped customers. ## Migrate standalone sso {#migrate-standalone-sso} ### Migrate from the standalone SSO API Learn how to migrate your code from an existing WorkOS SSO integration. ## Introduction The WorkOS AuthKit API supports all of the same social and enterprise identity providers, while providing higher level authentication features that most applications need. In this guide, we'll outline the steps to migrate an existing WorkOS SSO integration to the AuthKit API. > The existing standalone [WorkOS SSO API](/reference/sso) will continue to be supported. This is a viable option for you if you prefer to handle more of the authentication flow yourself. ## The new User resource The primary difference between existing integrations with [SSO](/sso) or [Directory Sync](/directory-sync) is the addition of a new resource: [Users](/reference/authkit/user). The WorkOS [User object](/reference/authkit/user) represents a single user in your application, and binds together information from all of the Directory and Identity providers that WorkOS supports into a single resource. As you migrate your existing integration, you can expect to replace references to WorkOS Profiles and Directory Users with instead references to Users. ## Switch to AuthKit API calls If you have built an integration with our standalone SSO API using [Get Authorization URL](/reference/sso/get-authorization-url), you will need to switch these calls with analogous calls to the AuthKit API. ### (1) Switch SSO initiation call When initiating SSO for one of your users, instead of calling the SSO [Get Authorization URL](/reference/sso/get-authorization-url) API, call the AuthKit [Get Authorization URL](/reference/authkit/authentication/get-authorization-url) API instead: The AuthKit Get Authorization API supports all of the same initiation parameters as the SSO API. In addition, it also supports an additional provider type, `authkit`, which will be covered later in this guide. ### (2) Switch API in Application Callback Similar to an SSO integration, your application will still have a callback identified by the Redirect URI passed during the previous initiation call. The contract with your callback is the same, where you should expect to be given a `code`, along with any `state` that was originally provided. However, instead of calling the SSO [Get a Profile and Token](/reference/sso/profile/get-profile-and-token) API, call the AuthKit [Authenticate](/reference/authkit/authentication) API instead, with the `grant_type` set to `authorization_code`: > **Important:** Instead of receiving a [Profile](/reference/sso/profile), your application now receives a full [User object](/reference/authkit/user). While many of the fields are similar, such as the user's email or name, the **User ID's will be different** than the Profile ID's you may have previously persisted in your application. If email is a unique identifier in your application, you can use the WorkOS User's email to identify the application-local user. WorkOS ensures that user email is verified before successfully completing an authentication request. When the API issues an email verification challenge, an [email verification response](/reference/authkit/authentication-errors/email-verification-required-error) is returned. ### Handling new authentication flows The AuthKit API offers a higher-level abstraction than the SSO API, offering more advanced [security features](/authkit/overview/security) like email verification and account Linking. This means that when your application attempts to exchange a code for a user object, it may return one of several new expected errors. These map to cases that were previously mentioned, like requiring that the user first verify their email, or enroll in MFA. If your application doesn't require these extra settings, they can be disabled in the _Authentication_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). > If you are using AuthKit, you won't need to handle error cases like required email verification, as AuthKit will automatically request this before a user is directed to their callback endpoint. ## AuthKit If you prefer to have full control over the authentication UI, you can choose to integrate with the AuthKit API directly. However, the easiest way to get started is to use AuthKit Hosted UI, a pre-built hosted authentication UI that guides users through all of the advanced flows, like email verification and MFA enrollment. You can enable AuthKit from the WorkOS dashboard, where you can also configure AuthKit branding and custom domains. Getting started with AuthKit is as simple as passing `authkit` as the `provider`: AuthKit can handle many of the concerns your application likely needed to previously, such as identifying which users sign in using enterprise SSO, and correctly routing them to their organization's identity provider. ## Directory Sync Directory provisioning is also supported in AuthKit. See the [Directory Provisioning documentation](/authkit/directory-provisioning) to learn more. ## Next Steps Check out the [full guide](/authkit), along with the [API reference](/reference/authkit) to get an idea of all the ways your application's user management needs can be solved by WorkOS. If you need help migrating your existing WorkOS integration, or have any other questions, please reach out to [WorkOS support](mailto:support@workos.com?subject=WorkOS%20Support). ## Mcp {#mcp} ### WorkOS MCP Give AI agents access to your WorkOS workspace. ## Overview The WorkOS MCP server lets MCP-compatible AI agents act on your WorkOS workspace using the [Model Context Protocol](https://modelcontextprotocol.io/). Once connected, your agent can read and change the same dashboard data you can (managing organizations, connections, users, branding, and more) by calling the WorkOS API on your behalf. The MCP server acts as **you**: it inherits your dashboard role and can only do what your account is allowed to do. See [Permissions](#permissions) for details. ## Connect a client Every client connects over streamable HTTP and authenticates with OAuth using [WorkOS Connect](/authkit/connect). The first time you connect, your client opens a WorkOS consent screen where you sign in and approve access. After you approve, the agent is connected as your account. ![WorkOS MCP OAuth consent screen](https://images.workoscdn.com/images/856aa389-6e6d-4262-a16a-008369ed3bc3.png?auto=format&fit=clip&q=80) Pick your client below for setup steps. ## Permissions The MCP server never grants more access than you already have. ### Role inheritance When you connect, the agent authenticates as your dashboard account and assumes your exact role and permissions. Every operation runs through the same access controls that govern the dashboard, so the agent can only read and change what you can. A member without admin rights can't use the agent to perform admin-only actions, and a read-only role can't make any changes at all. ### Environment scope The agent works against one environment at a time, so it can't accidentally change the wrong one. It defaults to a sandbox environment and only operates on production when you direct it to. Switching to production never escalates your access. The agent can only reach environments you already have access to in the dashboard, and your team's admins can block production entirely. ### Destructive confirmation Irreversible operations, like deleting an organization, connection, or directory, aren't executed on the first attempt. Instead, the agent receives a description of exactly what the operation will destroy and must explicitly confirm before it runs. This gives you a chance to review the consequences, so a single ambiguous prompt can't wipe out data. ### Secrets Values like API keys and client secrets are stripped from responses before they ever reach the agent, so they can't leak into its context or be echoed back in a chat transcript. Stripping only applies to returned values, so the agent can still set a secret value you provide without being able to read existing ones back. ### Admin controls Team admins can restrict or completely disable MCP access for the whole team from the team authentication settings page. Three settings can be toggled independently, and all are enabled by default: - **Enable**: Allow this team to access the WorkOS dashboard over MCP. Turning this off disables MCP for the team entirely, which also disables the two settings below. - **Allow production access**: Allow agents to access production environments. When off, MCP can only reach sandbox environments. This never escalates anyone's permissions: agents can still only reach production for members who already have production access in the dashboard. - **Allow write access**: Allow agents to perform write operations. When off, MCP is restricted to read-only operations. ![WorkOS MCP admin controls](https://images.workoscdn.com/images/88c0d427-131b-4cbc-935f-7f0ea68b1f90.png?auto=format&fit=clip&q=80) ## Example prompts Connect an agent and describe what you want in plain language. The agent discovers the right operations and runs them for you. Here are a few examples. **Brand your sign-in page from a screenshot** **Debug a sign-in problem** **Onboard a new customer** **Understand your users** **Manage a user** **Audit your configuration** **Stream audit logs** These are just starting points. Try to give agents tasks that you typically do in the dashboard. ## Limitations Some dashboard capabilities are intentionally unavailable over MCP. - **No impersonation.** The dashboard's user impersonation isn't exposed to agents, and mutations are blocked on impersonated sessions. An agent always acts as you. It can't act as one of your users. - **Not every dashboard action.** The agent works with the operations WorkOS has enabled for MCP (managing organizations, connections, users, branding, and more), but the most sensitive actions are intentionally left out. It can't change the MCP access settings that govern its own access, mint or rotate credentials such as API keys, OAuth client secrets, and signing certificates, or delete your WorkOS team. - **One team at a time.** The agent is scoped to the team you authenticate with. It can't read or change resources belonging to another team. ## Glossary {#glossary} ### Glossary Terminology and concepts used in the WorkOS documentation. ## Access Token An access token represents the successful authorization of your application to access a user's profile. During the Single Sign-On authorization flow, you'll receive an access token and profile in exchange for your authorization code. ## ACS URL An Assertion Consumer Service URL (ACS URL) is an endpoint where an identity provider posts SAML responses. ## API Key A unique identifier used to authenticate your API requests. ## Attribute Mapping Attribute mapping allows IT contacts to customize the user claims that are sent to your application. WorkOS normalizes these claims, so you can depend on a reliable, expected set of user profile information. ## Authorization Code An authorization code is a temporary code that you will exchange for an access token. During the Single Sign-On authorization flow, you'll exchange your authorization Code for an access token and profile. ## Authentication Challenge An authentication challenge, also known as challenge-response authentication, is a set of protocols that helps validate actions and protect resources from unauthorized access. ## Authentication Factor An authentication factor is a category of credential that is intended to verify, sometimes in combination with other factors, that an entity requesting access to some system is who, or what, they are declared to be. ## Authorization URL An authorization URL is the location your user will be directed to for authentication. ## Bearer Token A Bearer Token is an HTTP authentication scheme that uses a single security token to act as the authentication of an API request. The client must send this token in the Authorization header when making requests to protected resources. In the context of a Directory Sync integration, a Bearer Token is generated by WorkOS for SCIM providers such as Okta to authenticate endpoint requests. ## CIMD Client ID Metadata Document (CIMD) is the mechanism through which an MCP client identifies itself to an authorization server. You can use WorkOS and AuthKit to implement authentication for an MCP server you develop. As part of that, you'll enable CIMD in the WorkOS Dashboard under _Connect_ → _Configuration_. ## Client ID The client ID is a public identifier for your application that maps to a specific WorkOS environment. ## Client Secret The client secret is a value only known to your application and an OAuth identity provider. Currently, client secrets are used in OpenID Connect and Google/Microsoft/GitHub OAuth connections. ## Connection A connection is a way for a group of users (typically in a single organization) to sign in to your application. A directory connection is a way to retrieve a complete list of users and groups from an organization. ## Discovery Endpoint An OIDC discovery endpoint is a URL that provides metadata about an OIDC provider, including the issuer URL, supported authentication and token endpoints, supported scopes, public keys for signature verification, and other configuration information. The discovery endpoint path is `/.well-known/openid-configuration` on a URL. Clients can use this endpoint to dynamically discover and interact with an OIDC provider without requiring manual configuration. ## Directory Group A directory group is a collection of users within an organization who have been provisioned with access to your application. ## Directory Provider A directory provider is the source of truth for your enterprise client's user and group lists. ## Directory User A directory user is a person or entity within an organization who has been provisioned access to your application. ## Endpoint An endpoint is a location where an API receives requests about a specific resource. In the context of a Directory Sync integration, an endpoint is the standardized SCIM definition of two things: a `/Users` endpoint and a `/Groups` endpoint. ## HRIS A Human Resources Information System (HRIS) is software designed to maintain, manage, and process detailed employee information and human resources-related policies. ## IdP An Identity Provider (IdP) is the source of truth for your enterprise client's user database and authentication. Sometimes referred when describing the IdP-initiated flow, which is an authentication flow that starts from an identity provider like Okta instead of your application. ## IdP URI (Entity ID) An Identity Provider URI (Entity ID) is a globally unique name for an identity provider that performs SAML authentication assertions. Sometimes referred to as Identity Provider Issuer (Okta, Entra ID). ## IdP SSO URL An Identity Provider SSO URL (IdP SSO) is the URL your application's users will be redirected to for authentication with an identity provider. Sometimes referred to as Identity Provider SAML 2.0 Endpoint (OneLogin). ## IdP Metadata An Identity Provider Metadata (IdP Metadata) is the URL or XML file containing all of the metadata relevant to a specific identity provider. It includes attributes used by a service provider to route SAML messages, which minimizes the possibility of a rogue identity provider orchestrating a man-in-the-middle attack. ## JIT User Provisioning Just-in-time (JIT) user provisioning creates a user in an app when the user attempts to sign in for the first time. The account and respective role doesn't exist until the user creates it – just-in-time. ## JWT JSON Web Tokens are an open, industry standard method for representing claims securely between two parties. ## Sign-out redirect An allowlisted location a user is redirected to after they sign out via the Logout API. ## OAuth 2.0 OAuth 2.0 is an open standard for authorization. WorkOS supports OAuth 2.0, and our Single Sign-On API is modeled after concepts found in OAuth. ## OIDC OpenID Connect (OIDC) is an open standard and identity layer built on top of the OAuth 2.0 framework. ## Redirect URI A redirect URI is a required, allowlisted callback URL. The redirect URI indicates the location to return an authorized user to after an authorization code is granted, and the authentication process is complete. ## SAML Security Assertion Markup Language (SAML) is an open standard for authentication. Most of your enterprise clients will require SAML 2.0 authentication for their Single Sign-On. ## SCIM System for Cross-domain Identity Management (SCIM) is an open standard for managing automated user and group provisioning. It's a standard that many directory providers interface with. ## SP Service Provider (SP) is SAML parlance for "your application". Sometimes referred when describing the SP-initiated flow, which is an authentication flow that starts from your application instead of an identity provider like Okta. ## SP Entity ID A Service Provider (SP) Entity ID is a globally unique name for a service provider that performs SAML authentication requests, and is the intended audience for SAML responses. It is sometimes referred to as the Audience value. ## SP Metadata Service Provider Metadata (SP Metadata) is an XML file containing all of the metadata relevant to a specific service provider. Identity providers will use SP metadata files to make onboarding your application easier. ## TOTP Time-based One-time Password (TOTP) is a temporary code, generated by an algorithm that uses the current time as a source of uniqueness. ## X.509 Certificate An X.509 Certificate is a public key certificate used to authenticate SAML assertions. Sometimes referred to as Token Signature (AD FS). ## Email {#email} ### Email delivery Best practices for sending email with WorkOS. ## Introduction Many WorkOS features rely on your users receiving and acting upon email. For example, this includes invitations to join your app, password reset links, or Magic Auth sign-in. Prompt delivery of these emails is crucial. WorkOS offers three options for sending email: - **WorkOS email domain:** WorkOS sends email from the `workos-mail.com` domain. - **Your email domain:** WorkOS sends email from your own email domain. - **Send your own email:** WorkOS emits events, allowing your app to listen to these events and send email using your own email provider. These options provide different trade-offs between convenience, customization, and control over email deliverability. WorkOS follows industry best practices when sending email. SPF and DKIM email authentication records are configured automatically, the email content is continually refined to ensure it passes spam filters, and delivery of every email is actively monitored. However, regardless of the option you chose for sending email to your users, there are additional steps you can take to ensure that it reaches user inboxes. --- ## (A) WorkOS email domain By default WorkOS will send the following emails from the `workos-mail.com` domain in production environments. | Email | Sent From | Purpose | | ------------------ | :---------------------- | :------------------------------------- | | Invitation | welcome@workos-mail.com | Invite a user to create an account | | Magic Auth | access@workos-mail.com | Allow sign in with a one-time-use code | | Email verification | welcome@workos-mail.com | Verify ownership of a given email | | Password reset | access@workos-mail.com | Support the password reset flow | WorkOS has configured SPF, DKIM and DMARC email authentication records for the `workos-mail.com` domain. These records prove to the receiving mail server that a given email comes from WorkOS. We actively monitor the delivery of email sent from the `workos-mail.com` domain to protect the domain's reputation. If we detect unusually high rates of undelivered mail or mail marked as spam from a WorkOS team account, we may suspend that team's ability to send email. ### Do not send unsolicited email To ensure email is delivered when using the WorkOS email domain, be sure not to allow unsolicited email to be sent on your behalf. For example, an invitation email should be sent only if a user explicitly requests access to your application for themselves or another user. Do not attempt to bulk invite users from an email marketing list. ### Use appropriate team and organization names It is also important to ensure that your WorkOS team account and all organizations under your team have appropriate names that avoid [common spam words](https://mailtrap.io/blog/email-spam-words/) that may trigger spam filters. While our static email content is thoroughly tested, WorkOS emails can include your environment's [display name](/authkit/branding) (which defaults to your team name) as well as the names of organizations under your team. There may be an impact to email deliverability if these names use terms often flagged by spam filters. --- ## (B) Your email domain While using the WorkOS email domain option is convenient, you can provide your users a better experience. Using your own email domain means that your users will receive emails from a domain they recognize, one associated with your app. In addition, because you control the email domain, you have more control over the domain reputation and therefore more control over email deliverability. You can configure your own email domain in the [WorkOS dashboard](https://dashboard.workos.com). You will need to verify ownership of the domain by setting up a CNAME record with your domain provider. Two additional CNAME records are required to automatically configure SPF and DKIM email authentication using [SendGrid's automated security feature](https://support.sendgrid.com/hc/en-us/articles/21415314709147-Email-Authentication-SendGrid-s-Automated-Security-Explained). ![Configuring your email domain](https://images.workoscdn.com/images/84e47c58-e5e5-47c3-8245-f414a203f284.png?auto=format&fit=clip&q=50) In addition to not sending unsolicited emails and using appropriate team and organization names, when using your own email domain there are a few additional steps you can take to ensure email is delivered promptly. ### Set up inboxes When using your own domain, email will be sent from `welcome@` and `access@`. Email providers check if there are inboxes associated with sender addresses, so setting up inboxes for both the `welcome` and `access` email addresses on your domain can help ensure your emails reach users. ### Set up DMARC WorkOS recommends that you set up DMARC (Domain-based Message Authentication, Reporting & Conformance) with your domain provider. Google has released [guidelines](https://support.google.com/a/answer/81126?visit_id=638529785140327067-2643207201&rd=1#zippy=%2Crequirements-for-all-senders%2Crequirements-for-sending-or-more-messages-per-day) for email senders and the guidelines include DMARC requirements. Apple and Yahoo have released similar best practice guides. A DMARC policy tells a receiving mail server what to do when a message from your domain doesn't pass DMARC authentication. Configuring DMARC requires setting up a DNS TXT record with your domain provider. Here is an example DMARC record that will reject all emails not legitimately sent by an email provider on your behalf: ```plaintext TXT Record name: _dmarc<.example.com> content: v=DMARC1; p=reject; rua=mailto:postmaster@example.com, mailto:dmarc@example.com; pct=100; adkim=s; aspf=s ``` More details about DMARC can be found at [dmarc.org](https://dmarc.org/overview/). --- ## (C) Connect your own email provider to WorkOS By connecting your own email provider to WorkOS, you get control over deliverability, reputation, and compliance, while still offloading the heavy lifting of email handling. This option also allows you to easily utilize an existing email service provider configuration. For complete instructions on configuring a custom email provider, see the [custom email providers section](/authkit/custom-email-providers). --- ## (D) Send your own email There are a number of reasons why you may want to send email using your own email provider. Perhaps you already send a welcome email to new users and want to include an invitation link instead of sending a second email. Perhaps you already track sent email status with your own email provider and want a unified view into the status of all emails associated with your app. Regardless, when you send your own email, you have complete control over email deliverability. For complete instructions on sending your own email, see the section on [custom emails](/authkit/custom-emails) in the AuthKit documentation. When sending your own email, you will want to follow the all of the recommendations in Google's [email sender guidelines](https://support.google.com/a/answer/81126?hl=en). This includes setting up SPF, DKIM and DMARC email authentication. You will also need to be conscious of your sender reputation. It's based on the quality of emails, their frequency, and user interaction. A good sender reputation can increase the chances of your emails reaching inboxes. SendGrid provides some [useful tips for improving sender reputation](https://sendgrid.com/en-us/blog/email-reputation-101-ip-reputation-vs-domain-reputation). If you author your own email content, you may want to test your emails against various email providers' spam filters. There are a number of spam testing services available such as [Litmus](https://www.litmus.com/email-testing) and [Warmly](https://www.warmy.io/free-tools/email-deliverability-test/). --- ## (E) Check suppression status Email providers maintain suppression lists: addresses that previously bounced, were marked as spam, or were flagged as invalid. Once suppressed, WorkOS will not attempt to deliver emails to that address. ### Suppression types - **Bounce**: The email hard-bounced because the address doesn't exist. - **Spam complaint**: The recipient marked the email as spam. - **Block**: The email provider blocked delivery. - **Invalid**: The email address is malformed. ### Checking and removing suppressions In the [WorkOS Dashboard](https://dashboard.workos.com/), navigate to the **Users → \[User] → Emails** tab. The suppression status is shown for the user's email address. If suppressed, you can click "Re-enable email" to remove the suppression. Before removing a suppression, confirm: - The recipient wants to receive emails. - The mailbox is not full and can receive mail. - The email address is valid and not malformed. Suppression management is available when using the default WorkOS email provider or a [custom email provider](/authkit/custom-email-providers). --- ## Troubleshooting Even when following industry best practices, an email may get filtered as spam and not reach a user's inbox. Other times an email might be delayed, for example, when [Enhanced Pre-delivery Message Scanning](https://apps.google.com/supportwidget/articlehome?hl=en&article_url=https%3A%2F%2Fsupport.google.com%2Fa%2Fanswer%2F7380368%3Fhl%3Den&product_context=7380368&product_name=UnuFlow&trigger_context=a) is enabled on a Google workspace or when a similar feature is enabled with other email providers. Email providers do not explain the heuristics used by their spam filters and security mechanisms, and they are often changing, making it especially frustrating to troubleshoot problems. The first step in troubleshooting is to determine if the problem exists for all users or only a subset of users. Generally, this will provide insight into the nature of the issue and how best to resolve it. If the issue exists for all users, it is most likely a matter of poor domain reputation. If the issue only exists for a subset of users, it may be because of specific settings used by an email provider or the IT department at a given organization. Both Google and Microsoft have been noted as being especially aggressive when identifying spam. However, both companies provide some tooling to help you debug email deliverability problems. Google offers [Postmaster Tools](https://www.gmail.com/postmaster/) to help with email deliverability related to Gmail and Google Workspaces. Microsoft offers similar tools with [Sender Support](https://sendersupport.olc.protection.outlook.com/pm/). Lastly, more general spam testing services such as [Litmus](https://www.litmus.com/email-testing) and [Warmly](https://www.warmy.io/free-tools/email-deliverability-test/) are available. If you continue to have issues regarding email deliverability despite following all of the above suggestions, please [contact support](mailto:support@workos.com). ## Widgets {#widgets} ### WorkOS Widgets Learn how to integrate WorkOS Widgets in your app. ## Introduction WorkOS Widgets are React components that provide complete functionality for common enterprise app workflows, for example a Users Management Widget that provides a UI for inviting, removing and editing users. This guide will cover how to add a widget to your app, configure CORS, and supply an authorization token for the widget. ### User Sessions Widget A widget for displaying and managing user sessions in your application. ![User Sessions Widget screenshot](https://images.workoscdn.com/images/c4ff10a8-e0a3-4c9d-b0a7-56bbf93f6862.png?auto=format&fit=clip&q=50) The `` widget provides users with visibility into their active sessions across different devices and browsers. Users can view session details and sign out of individual sessions as needed. In order to use the User Sessions widget, a user must have a role that has the `widgets:users-table:manage` permission. ## API Reference ### User Security Widget A widget for controlling user security settings in your application. ![User Security Widget screenshot](https://images.workoscdn.com/images/91c883ca-c3e5-474f-b93f-c2e1d0517380.png?auto=format&fit=clip&q=50) The `` widget enables users to control their security settings. With this widget, users can: - Set or change their password - Configure and reset Multi-Factor Authentication No special permissions are required to use this widget. ## API Reference ### User Profile Widget A widget for displaying and managing a user's profile in your application. ![User Profile Widget screenshot](https://images.workoscdn.com/images/790e97bb-0875-4ca7-8ff4-c01dafce77f4.png?auto=format&fit=clip&q=50) The `` widget allows users to view and manage their personal information. With this widget, users can: - View their profile picture and connected OAuth accounts - Edit their display name - Change their email address, with a verification code sent to the new address No special permissions are required to use this widget. ## API Reference ### User Management Widget A widget for displaying and managing users in your application. ![Users Management screenshot](https://images.workoscdn.com/images/20f235c5-c888-48f5-90aa-87ec9189483a.png?auto=format&fit=clip&q=50) The `` widget allows IT contacts to manage the members in an organization. IT contacts can invite new users, remove users, and change roles all within the widget. In order to use the User Management widget, a user must have a role that has the `widgets:users-table:manage` permission. ## API Reference ### Authorization Tokens Ensure Widgets have the appropriate permissions in your application. Widgets must be supplied with an authorization token. The token can be acquired in one of two ways: - If you are using the `authkit-js` or `authkit-react` libraries, you can use the provided access token. - If you use one of our backend SDKs, use the "get token" method in the SDK to request a token with the appropriate scope for the widget you want to use. Widget tokens expire after one hour. > New WorkOS accounts are created with an "Admin" role that has all Widget permissions assigned. Existing accounts will need to assign the proper permissions to a role. This can be done on the "Roles" page of the WorkOS Dashboard. See the [Roles and Permissions guide](/authkit/roles-and-permissions) for more information. To successfully generate a token, the user must be assigned a role with the correct permissions for the widget. ### Quick Start A step-by-step guide for setting up WorkOS Widgets in your application. ## Installation First, install the `@workos-inc/widgets` package from the npm registry, along with its peer dependencies: ```bash title="Install packages" npm install @workos-inc/widgets @radix-ui/themes @tanstack/react-query ``` WorkOS Widgets uses [Radix Themes](https://www.radix-ui.com/themes) for its UI components and style customization APIs, while [TanStack Query](https://tanstack.com/query/latest) is used for data fetching and caching. Since both libraries are often used in applications, we require them as peer dependencies to avoid duplication, version conflicts, and bloated bundles. > Widgets can be used in any client- or server-rendered React application. See our [Widgets examples on GitHub](https://github.com/workos/widgets-examples) to see how they can be integrated in various frameworks. ## Styles WorkOS Widgets are powered by Radix Themes, which provides beautiful default styles with zero configuration. Start by importing styles exported from both Radix Themes and WorkOS Widgets. > Widgets can be customized using the `theme` prop or with plain CSS. See the [styling guide](/widgets/styling) for more details. ## Root component The `WorkOsWidgets` component should be rendered at the top of your application. This component is responsible for managing context for data fetching and providing theme styles to all Widgets. ## CORS configuration Because WorkOS widgets issue client-side requests to WorkOS, it is necessary to configure your site as an allowed web origin. In the Applications page of the [WorkOS Dashboard](https://dashboard.workos.com/environment/applications), open your application. CORS can be configured within the Sessions tab. This will prevent CORS issues when using the widget. ![CORS configuration](https://images.workoscdn.com/images/586fb07f-6839-4c5c-95c1-e1055a5b3ace.png?auto=format&fit=clip&q=80) ### Pipes Widget A widget for displaying and managing connected accounts with Pipes. ![Pipes widget screenshot](https://images.workoscdn.com/images/e84a33bb-0510-4d85-9041-33b1a0ce938c.png?auto=format&fit=clip&q=50) The `` widget allows users to manage their connections to third-party providers. Users can view the available providers, connect their accounts, reauthorize when needed, and disconnect their accounts. Read more in the [Pipes guide](/pipes). ## API Reference ### Pipes Admin Widget A widget for organization admins to manage their organization's Pipes connections — enabling providers, supplying OAuth credentials, and configuring scopes. ![Pipes Admin screenshot](https://images.workoscdn.com/images/42e15dab-db7f-4d8d-8a40-6ab469cd7470.png?auto=format&fit=clip&q=50) The `` widget lets organization administrators manage their organization's [Pipes](/pipes) connections. From a single list, an admin can enable or disable providers for their organization's members, supply their organization's own OAuth credentials (client ID and secret) for providers configured to use customer credentials, and adjust the scopes requested when members connect. This widget is gated by the `widgets:pipes:manage` permission. End users who only need to connect and manage their own accounts should use the [Pipes widget](/widgets/pipes) instead. Read more in the [organization-scoped providers guide](/pipes/organization-scoped-providers). ## API Reference ### Organization Switcher Widget A widget for switching between organizations in your application. The `` widget allows users to switch between organizations. There are no special permissions required to use this widget as users can switch between organizations they have access to. If an organization requires SSO or MFA, the user will be redirected to reauthorize with the new organization. ![Organization Switcher screenshot](https://images.workoscdn.com/images/e22cad7a-f11a-4f47-8cc7-fb015a22114f.png?auto=format&fit=clip&q=80) ### Switching Organizations There are multiple ways to integrate with the Organization Switcher widget depending on your library choice. If you are using either the `authkit-js` or `authkit-react` libraries, you can use the `useAuth` hook to get the current organization and pass it to the widget. If you are using one of the backend SDKs, you can build the organization switcher action in the backend and pass it in as a prop to the widget to be called when the user attempts to switch organizations. See the [Switching Organizations](/authkit/sessions/integrating-sessions/switching-organizations) guide for more information to set up the backend actions. This can then be passed in as a prop to the widget. ### Creating Organizations The widget accepts children components that can be used to either redirect the user to create an organization or to show a modal with a form to create an organization. You can use this to integrate with your existing organization creation flow that uses the WorkOS APIs to create organizations. ## API Reference ### Localization Learn how to display Widgets in multiple languages. Widgets can automatically translate text in your users' preferred language, with support for 90 languages out of the box. If your website is already localized in multiple languages, then Widgets can match the page's language, giving your users a consistent experience. ![API keys widget translated into Japanese](https://images.workoscdn.com/images/8f52fe99-99b3-4bf3-acd4-ead279b594ff.png?auto=format&fit=clip&q=80) Dates are also formatted with respect to the user's locale. ## Installation Localization support is provided through a separate `@workos-inc/widgets-i18n` package. This opt-in approach keeps the core Widgets package lightweight for applications that don't require multilingual behavior. Translation dictionaries are loaded lazily, meaning only the language bundle matching the end user's locale is downloaded at runtime. Install the package: ```bash title="Install package" npm install @workos-inc/widgets-i18n ``` ## Setup Wrap your application with the `WorkOsLocaleProvider`: ```tsx title="app/layout.tsx" import { WorkOsLocaleProvider } from '@workos-inc/widgets-i18n'; export default async function RootLayout({ children, }: { children: React.ReactNode; }) { const locale = await getLocale(); // read from request headers const direction = getLocaleDir(locale); return ( {children} ); } ``` The `WorkOsLocaleProvider` should wrap your entire application, similar to other context providers. Pass the user's locale as the `locale` prop. ## Detecting user locale Use the utilities exported from `@workos-inc/widgets-i18n` to detect and validate locales: - `getLocaleCodes()` – Set of all supported locale codes - `isValidLocale()` – Validates whether a string is a supported locale code - `getDir()` – Returns the text direction (`'ltr'` or `'rtl'`) for a locale Here's an example on how to detect the user's locale from the `accept-language` header in Next.js: ```tsx title="utils/locale.ts" import { getLocaleCodes, getDir, isValidLocale, } from '@workos-inc/widgets-i18n'; import Negotiator from 'negotiator'; import { headers } from 'next/headers'; const DEFAULT_LOCALE = 'en-US'; export async function getLocale(): Promise { const headersList = await headers(); const acceptLanguage = headersList.get('accept-language') ?? ''; const negotiator = new Negotiator({ headers: { 'accept-language': acceptLanguage }, }); const locale = negotiator.language(Array.from(getLocaleCodes())); return isValidLocale(locale) ? locale : DEFAULT_LOCALE; } export function getLocaleDir(locale: string): 'ltr' | 'rtl' { return getDir(locale); } ``` ## RTL language support For right-to-left languages like Arabic and Hebrew, set the `dir` attribute on your HTML element. Use the `getDir()` function to determine the appropriate text direction: ```tsx title="app/layout.tsx" import { getDir } from '@workos-inc/widgets-i18n'; const direction = getDir(locale); // Returns 'ltr' or 'rtl' return ( {/* ... */} ); ``` Widgets will automatically inherit their text direction based on the nearest ancestor's `dir` attribute. ## Supported locales Widgets support the same locales as the AuthKit hosted UI. See the [AuthKit localization documentation](/authkit/hosted-ui/localization) for the full list of supported locale codes. ### Directory Sync Widget A widget for managing Directory Sync connections in the Admin Portal. ![Directory Sync Widget screenshot](https://images.workoscdn.com/images/ad6ecb52-d450-4778-b9b8-239f74b58cbc.png) The `` widget enables users to manage Directory Sync connections in the Admin Portal. It displays the directory status, metadata, and callout messages. In order to use the Directory Sync widget, a user must have a role that has the `widgets:dsync:manage` permission. ## API Reference ### Audit Log Streaming Widget A widget for configuring and monitoring audit log streaming in the Admin Portal. ![Audit Log Streaming Widget screenshot](https://images.workoscdn.com/images/408ea781-5544-4340-a566-a9d2e16f903d.png?auto=format&fit=clip&q=50) The `` widget enables users to configure and monitor audit log streaming to external destinations in the Admin Portal. It displays the streaming status, destination configuration, and connection health. In order to use the Audit Log Streaming widget, a user must have a role that has the `widgets:audit-log-streaming:manage` permission. ## API Reference ### API Keys Widget A widget for displaying and managing API keys. ![API Keys widget screenshot](https://images.workoscdn.com/images/13e0893f-eb84-43f1-9467-2598567538f3.png?auto=format&fit=clip&q=50) The `` widget allows users to create, view, and revoke API keys, all within the widget. It supports two scopes via the `scope` prop: - `"organization"` (the default): manage API keys owned by the organization. - `"user"`: manage API keys owned by individual users. ## Organization API keys The default `scope="organization"` mode allows admins to manage API keys in an organization. Admins can create API keys with specific permissions, view details of existing API keys, and revoke API keys. In order to use the widget with `scope="organization"`, a user must have a role that has the `widgets:api-keys:manage` permission. ## User API keys Setting `scope="user"` puts the widget into user API key management. In order to use the widget with `scope="user"`, a user must have a role that has at least one of the following permissions: - `widgets:user-api-keys:manage-self`: the user can create, view, and revoke their own API keys. - `widgets:user-api-keys:manage-all`: includes everything `manage-self` grants, plus the ability to view and revoke API keys owned by any other user in the organization. ## API Reference ### SSO Connection Widget A widget for setting up SSO connections in the Admin Portal. ![SSO Connection Widget screenshot](https://images.workoscdn.com/images/1c8bb97f-b321-4fab-8a1b-b46d3dd92f1f.png?auto=format&fit=clip&q=50) The `` widget enables users to set up SSO connections in the Admin Portal. In order to use the SSO Connection widget, a user must have a role that has the `widgets:sso:manage` permission. ## API Reference ### Domain Verification Widget A widget for verifying domains in the Admin Portal. ![Domain Verification Widget screenshot](https://images.workoscdn.com/images/6a98da6f-7178-4bb1-a276-ff024461cc16.png?auto=format&fit=clip&q=50) The `` widget enables users to verify domains in the Admin Portal. In order to use the Domain Verification widget, a user must have a role that has the `widgets:domain-verification:manage` permission. ## API Reference ### Styling Customize the look and feel of WorkOS Widgets. WorkOS Widgets are powered by Radix Themes, which provides beautiful default styles with zero configuration. The fastest way to style your Widgets is with the [`theme` prop](/widgets/styling/theme-customization). This prop is provided to the `WorkOsWidgets` component rendered at the top of your application. All Widgets will inherit styles configured in the `theme` prop. See the [theme customization guide](/widgets/styling/theme-customization) for more details on `theme` prop. ## Using CSS If you choose not to use the theming capabilities in Radix Themes, you can style Widgets using CSS. Individual elements in Widgets are accessible via CSS class selectors prefixed with `woswidgets-`. For example, you can add your own button styles by selecting the `woswidgets-button` class. See the [CSS customization guide](/widgets/styling/css-customization) for more details on styling Widgets with CSS. ### Theme Customization Customize the look and feel of WorkOS Widgets using Radix Themes. ## Using the `theme` prop The `theme` prop can be used to customize the overall appearance of WorkOS Widgets. `theme` support relies on external stylesheets from Radix Themes and WorkOS Widgets. Start by importing both stylesheets into your application. ### `theme` properties See the [Radix Themes API reference](https://www.radix-ui.com/themes/docs/components/theme#api-reference) for more information on theming options. ## Using the `elements` prop Underlying components can be styled using the `elements` prop. This object is a mapping of component names to their respective Radix Theme component props. ### `elements` properties Each element is mapped to a Radix Theme component and accepts the same props as its respective component. See the Radix Themes documentation for each component for all available props. | Component | Radix component | | :-------------------- | :-------------------------------------------------------------------------- | | `avatar` | [`Avatar`](https://www.radix-ui.com/themes/docs/components/avatar) | | `badge` | [`Badge`](https://www.radix-ui.com/themes/docs/components/badge) | | `primaryButton` | [`Button`](https://www.radix-ui.com/themes/docs/components/button) | | `secondaryButton` | [`Button`](https://www.radix-ui.com/themes/docs/components/button) | | `destructiveButton` | [`Button`](https://www.radix-ui.com/themes/docs/components/button) | | `dialog` | [`Dialog`](https://www.radix-ui.com/themes/docs/components/dialog) | | `dropdown` | [`Dropdown`](https://www.radix-ui.com/themes/docs/components/dropdown) | | `iconButton` | [`IconButton`](https://www.radix-ui.com/themes/docs/components/icon-button) | | `label` | [`Label`](https://www.radix-ui.com/themes/docs/components/label) | | `primaryMenuItem` | [`MenuItem`](https://www.radix-ui.com/themes/docs/components/menu-item) | | `destructiveMenuItem` | [`MenuItem`](https://www.radix-ui.com/themes/docs/components/menu-item) | | `select` | [`Select`](https://www.radix-ui.com/themes/docs/components/select) | | `skeleton` | [`Skeleton`](https://www.radix-ui.com/themes/docs/components/skeleton) | | `textfield` | [`TextField`](https://www.radix-ui.com/themes/docs/components/text-field) | ### CSS Customization Customize the look and feel of WorkOS Widgets using CSS. Widgets can be styled using plain CSS using namespaced class and data-attribute selectors. While optional, we recommend starting with the `layout.css` stylesheet from Radix Themes, as well as the `base.css` stylesheet from WorkOS Widgets. These styles provide a base level of functional styling without opinionated design choices. ## Universal selectors Elements in Widgets are accessible via CSS class selectors prefixed with `woswidgets-`. | Selector | Description | | :------------------- | :-------------------------------------------------- | | `.woswidgets-root` | The root element for the Widgets provider | | `.woswidgets-widget` | A selector used on the root element for all Widgets | ## Element selectors ### Avatar | Selector | Description | | :------------------- | :-------------------------- | | `.woswidgets-avatar` | Targets all avatar elements | ### Badge | Selector | Description | | :------------------ | :------------------------- | | `.woswidgets-badge` | Targets all badge elements | ### Button | Selector | Description | | :-------------------------------- | :-------------------------- | | `.woswidgets-button` | Targets all button elements | | `.woswidgets-button--primary` | Targets primary buttons | | `.woswidgets-button--secondary` | Targets secondary buttons | | `.woswidgets-button--destructive` | Targets destructive buttons | ### Dialog | Selector | Description | | :--------------------------- | :--------------------------------------- | | `.woswidgets-dialog` | Targets all dialog elements | | `.woswidgets-dialog-overlay` | Targets the overlay for a dialog element | ### Dropdown | Selector | Description | | :--------------------- | :---------------------------- | | `.woswidgets-dropdown` | Targets all dropdown elements | ### Icon Button | Selector | Description | | :------------------------ | :------------------------------- | | `.woswidgets-button` | Targets all button elements | | `.woswidgets-icon-button` | Targets all icon button elements | ### Label | Selector | Description | | :------------------ | :------------------------- | | `.woswidgets-label` | Targets all label elements | ### Menu Item | Selector | Description | | :----------------------------------- | :----------------------------- | | `.woswidgets-menu-item` | Targets all menu item elements | | `.woswidgets-menu-item--destructive` | Targets destructive menu items | ### Select | Selector | Description | | :---------------------------- | :----------------------------------------------- | | `.woswidgets-select` | Targets all select elements | | `.woswidgets-select-dropdown` | Targets dropdown elements belonging to a select | | `.woswidgets-select-item` | Targets menu item elements belonging to a select | ### Skeleton | Selector | Description | | :--------------------- | :---------------------------- | | `.woswidgets-skeleton` | Targets all skeleton elements | ### Text Field | Selector | Description | | :----------------------- | :------------------------------ | | `.woswidgets-text-field` | Targets all text field elements | ## Vault {#vault} ### Vault Encrypt, store, and control access to sensitive data. # Introduction WorkOS Vault is a developer-friendly EKM to encrypt and optionally store data including tokens, passwords, certificates, files, and any other customer content. Ideal for scaling encryption in cloud applications, it minimizes key exposure and simplifies compliance. ## Key features ### Encrypted Key-Value Storage Each secret stored with Vault uses a unique encryption key and is cryptographically isolated based on user-provided context. Envelope encryption enhances security by encrypting data with a data encryption key (DEK), which is then encrypted with a key encryption key (KEK). This approach ensures sensitive data remains protected while allowing secure key management and access control. ### Enterprise Key Management (EKM) The Enterprise Key Management features of Vault centralize control over encryption keys used for customer data in multi-tenant architectures. It streamlines key lifecycle management, access policies, and auditability while integrating seamlessly with your existing applications. Key segmentation by organization, user, or any provided context ensures cryptographic keys are isolated, reducing risk and enforcing access control at boundaries that make sense for your business. ### Bring-Your-Own-Key (BYOK) With Vault you can provide keys either from your own environment or directly linked to your customers' cloud environments. BYOK gives you full control over encryption keys while integrating seamlessly with your own security tooling such as cloud SIEMs. It ensures your keys stay protected in your custody while enabling secure access for encryption operations, perfect for compliance-driven workloads. BYOK integration is available for many popular key management services, including Amazon Web Service KMS, Google Cloud Compute KMS, Azure Key Vault, and HashiCorp Vault. ## Common Use Cases ### Organizational secrets Sensitive data in a B2B application is often linked to specific organization. This can be shared secrets, API keys, OAuth credentials, or even data generated by your application. Vault protects this information and easily links each secret with the organization it belongs to in order to provide full cryptographic separation from other organizations within your application. ### User secrets User data such as Personally Identifiable Information (PII) or Protected Health Information (PHI) is highly sensitive and can have strict regulatory requirements including strong encryption, access controls, and data minimization. The risk for mishandling this data is very high - both financially and reputationally. Vault lets you store this data using unique encryption keys without needing to manage the complex lifecycle of key hierarchies. ### Application secrets With short-lived dynamic workloads in the cloud, static credentials represent a huge security risk. Secrets can get spread out across many services, making rotation difficult and increasing the risk of a leak. Vault can encrypt and store application data such as API keys, database credentials, and PKI certificates in a centralized service and provide them to your application at runtime. ### Quick Start A step-by-step guide on how to start using Vault to manage encrypted objects. ## Before getting started To get the most out of these guides, you'll need: - A [WorkOS account](https://dashboard.workos.com/) Sign in to your WorkOS Dashboard account and create a new Organization. ![WorkOS Dashboard UI showing organization creation](https://images.workoscdn.com/images/1c69fd98-01be-491d-9255-58363bc6a983.png?auto=format&fit=clip&q=50) ## What you'll build In this guide, we will walk you through what you will need to set up Vault for securing and isolating organization-specific data: - Encrypt and store data linked to an organization - Retrieve the encrypted data - Delete an object that's no longer in use ## API object definitions [Object](/reference/vault/object) : Represents an encrypted key-value item stored by Vault. [Organization](/reference/organization) : Describes an organization whose users sign in with a SSO Connection, or whose users are synced with a Directory Sync Connection. ## Add Vault to your app ### Install the WorkOS SDK WorkOS offers native SDKs in several popular programming languages. Choose a language below to see instructions in your application's language. ### Set objects To make calls to WorkOS, provide the API key and, in some cases, the client ID. Store these values as managed secrets, such as `WORKOS_API_KEY` and `WORKOS_CLIENT_ID`, and pass them to the SDKs either as environment variables or directly in your app's configuration based on your preferences. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' ``` > The code examples use your staging API keys when [signed in](https://dashboard.workos.com) ### Create an object The Vault API and SDKs provide a method to encrypt and store a blob of data linked to a WorkOS organization. The encryption key used will be both unique to the KV item and cryptographically isolated from all other organizations. ### Update the value of the object Once created, the key context for an object cannot be changed. Only the value can be updated. The expected version of the object can be provided as a consistency lock when writing to the object. ### Retrieve the object value Objects can be listed, returning just the names of the objects. The metadata for each object can be queried - this provides more information about it without needing to decrypt the actual value. Fetching the object value will return the same metadata in addition to the unencrypted value. ### Delete the object When an object is no longer needed it can be marked for deletion. This will make the object unavailable to API operations, but the data will not be immediately deleted. ### Key Context User-managed cardinality for keys within Vault. When encrypting data with Vault, a set of key-value metadata pairs called the key context is required. This determines which key or keys will be used to encrypt the data without needing to explicitly list IDs for the keys. The key context is used both when [creating an encrypted object](/reference/vault/object/create) and when [encrypting locally](/reference/vault/key/encrypt-data) with Vault-managed keys. ## Key matching Each item in the context is used to identify a long-lived key within the WorkOS environment called a key-encrypting key (KEK). The key material lives in a Hardware Security Module (HSM) and cannot be exported to plaintext - it can only be used to generate or decrypt data keys. KEKs are created just-in-time and don't require any configuration in advance. ### Bring Your Own Key (BYOK) When Vault is used with a BYOK setup, the customer-managed key (CMK) is used in place of the WorkOS managed KEK. Matching the encryption operation to the CMK is still done based on the key context. For example, if Vault is configured to use a CMK called `key_abc` for all data of `organization_abc123`, then that key would automatically be used when the key context is set to `{"organization_id": "organization_abc123"}`. The same operation with a context of `{"organization_id": "organization_xzy987"}` would instead use a WorkOS managed KEK. ## Data keys Although the KEKs identified by key context are long-lived, they aren't directly used for encrypting data. A random data-encrypting key (DEK) is generated for an encryption operation. The DEK is then encrypted using each KEK from the key context, resulting in a single plaintext key and one or more encrypted keys. The encrypted keys are then stored with the encrypted data for future decryption. This ensures that the data and keys have the same durability while keeping the keys safe. It also means that even if one key is exposed, not all of the data will be at risk since many different data keys are used for the same key context. ## Limitations The following limitations are enforced by the Vault API for the key context object: - All values in the context must be strings. - A maximum of 10 items can be present in a single context. - Each context name has a maximum length of 120 characters. - Each context value has a maximum length of 500 characters. ### Bring Your Own Key (BYOK) Allow your customers to use their own encryption keys with WorkOS Vault for enhanced security and compliance. Bring Your Own Key (BYOK) allows your customers to use their own customer-managed keys (CMKs) with WorkOS Vault instead of relying solely on WorkOS-managed keys. This feature enables you to offer your customers additional control over their encryption keys and help them meet specific compliance requirements. ## Overview With BYOK, your customers maintain control over their key material while still leveraging Vault's encryption and data management capabilities. Customer-managed keys are used as key-encrypting keys (KEKs) in place of WorkOS-managed KEKs, providing an additional layer of security and compliance for your application's users. ## How BYOK works When Vault is configured with BYOK: 1. **Key Matching**: Encryption operations are matched to customer CMKs based on the [key context](/vault/key-context) provided 2. **Envelope Encryption**: Customer CMKs encrypt data-encrypting keys (DEKs), not the data directly 3. **Automatic Fallback**: Operations that don't match a customer's CMK configuration will use WorkOS-managed KEKs ### Key Context Matching BYOK uses the same key context mechanism as standard Vault operations. When a customer's CMK is configured for specific context values, Vault automatically uses that key for matching operations. **Example Configuration:** - Customer CMK `key_abc` configured for `organization_id: "org_123"` - Key context `{"organization_id": "org_123"}` → Uses customer CMK `key_abc` - Key context `{"organization_id": "org_456"}` → Uses WorkOS-managed KEK ## Benefits ### Enhanced Security - **Key Control**: Your customers maintain complete control over their encryption keys - **Isolation**: Customer keys remain separate from other tenants' data - **Audit Trail**: Customers have full visibility into their key usage and access patterns ### Compliance - **Regulatory Requirements**: Help customers meet compliance standards that require customer-controlled keys - **Data Sovereignty**: Enable customers to ensure encryption keys remain within their control - **Risk Management**: Reduce customer dependency on third-party key management ## Use Cases ### Multitenant Applications Allow different customers to use their own CMKs while maintaining a single Vault integration: ```javascript // Customer A data - uses Customer A's CMK await vault.createObject({ name: 'customer-a-pii', value: '{"fullname": "customer_a_name"}', context: { organization_id: 'customer_a' }, }); // Customer B data - uses Customer B's CMK await vault.createObject({ name: 'customer-b-pii', value: '{"fullname": "customer_b_name"}', context: { organization_id: 'customer_b' }, }); ``` ### Compliance Sensitive Data Allow customers to apply stricter key controls to specific data types: ```javascript // PCI data - uses customer's CMK await vault.createObject({ name: 'customer-123-payments', value: '{"creditCard": "4111-1111-1111-1111"}', context: { organization_id: 'customer_123', }, }); // General data - uses WorkOS-managed keys await vault.createObject({ name: 'customer-123-preferences', value: '{"preference": "dark_mode"}', context: { data_type: 'preferences', }, }); ``` ### Geographic Data Residency Allow customers to ensure their encryption keys remain in specific regions: ```javascript // EU data - uses customer's EU-based CMK await vault.createObject({ name: 'customer-789-pii', value: '{"userEmail": "user@example.eu"}', context: { organization_id: 'customer_789', }, }); ``` ## Configuration BYOK configuration is managed through your WorkOS dashboard and Admin Portal. Contact your WorkOS representative to enable BYOK for your application. ### Prerequisites - Your customers must have compatible key management systems (AWS KMS, Azure Key Vault, Google Cloud KMS) - Proper IAM permissions for WorkOS Vault to access customer keys ### Generate Admin Portal link Navigate to the organization of your customer who will configure their CMK. Generate a unique portal link by clicking "Invite admin" and selecting "Bring Your Own Key" from the feature selection. ![Generate admin portal link](https://images.workoscdn.com/images/d374bc73-7cdc-441c-b177-82c4ae604db7.png?auto=format&fit=clip&q=80) ### Share link with your customer's IT team The Admin Portal will walk an IT contact through the setup and configuration of the CMK. It includes screenshots for using the cloud provider of choice to create a key and set the appropriate permission in IAM policies to allow Vault to use the key. ![Share link with IT](https://images.workoscdn.com/images/7f237529-584b-4a98-b17e-2ce4bf6c1e08.png?auto=format&fit=clip&q=80) ### Confirm successful Admin Portal setup The final step of the Admin Portal setup flow will validate that Vault can use the CMK the IT contact configured. If they see "Setup is complete", Vault will use the customer's CMK whenever an operation includes their organization id as context. ![Confirm CMK setup success](https://images.workoscdn.com/images/f46f7009-3cf5-4706-a37e-691768d63440.png?auto=format&fit=clip&q=80) ### View CMK under Organization details A Key details card will appear under Organization details, which shows configuration information, CMK active state, and the key context associated with the CMK. ![View key details](https://images.workoscdn.com/images/54c026c7-f3b0-497a-bb48-83661ba1ae3e.png?auto=format&fit=clip&q=80) ## Single Sign-On {#sso} ### Single Sign-On Facilitate greater security, easier account management, and accelerated application onboarding and adoption. ## Choose your integration approach There are two ways to integrate Single Sign-On (SSO) with WorkOS: ### (A) With the standalone SSO API The standalone API (covered in this document), is a standalone API for integrating into an existing auth stack. ### (B) Using WorkOS AuthKit [AuthKit](/authkit) is a complete authentication platform which includes SSO out of the box. ## How Single Sign-On works Single Sign-On is the most frequently asked for requirement by organizations looking to adopt new SaaS applications. SSO enables authentication via an organization's [identity provider (IdP)](/glossary/idp). This service is compatible with any IdP that supports either the [SAML](/glossary/saml) or [OIDC](/glossary/oidc) protocols. It's modeled to meet the [OAuth 2.0](/glossary/oauth-2-0) framework specification, abstracting away the underlying authentication handshakes between different IdPs. ![Authentication Flow Diagram](https://images.workoscdn.com/images/90b84f08-3363-446a-8610-f7b2bd2ee2ca.png?auto=format&fit=clip&q=80)\[border=false] WorkOS SSO API acts as authentication middleware and intentionally does not handle user database management for your application. ## What you'll build In this guide, we'll take you from learning about Single Sign-On and POC-ing all the way through to authenticating your first user via the WorkOS SSO API. ## Before getting started To get the most out of this guide, you'll need: - A [WorkOS account](https://dashboard.workos.com/) - A local app to integrate SSO with. Reference these [example apps](/sso/example-apps) as you follow this guide. ## API object definitions [Connection](/reference/sso/connection) : The method by which a group of users (typically in a single organization) sign in to your application. [Profile](/reference/sso/profile) : Represents an authenticated user. The Profile object contains information relevant to a user in the form of normalized and raw attributes. ## (1) Add SSO to your app Let's build the SSO authentication workflow into your app. ### Install the WorkOS SDK WorkOS offers native SDKs in several popular programming languages. Choose a language below to see instructions in your application's language. ### Set secrets To make calls to WorkOS, provide the API key and, in some cases, the client ID. Store these values as managed secrets, such as `WORKOS_API_KEY` and `WORKOS_CLIENT_ID`, and pass them to the SDKs either as environment variables or directly in your app's configuration based on your preferences. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' ``` > The code examples use your staging API keys when [signed in](https://dashboard.workos.com) ### Add an endpoint to initiate SSO The endpoint to initiate SSO via the WorkOS API is responsible for handing off the rest of the authentication workflow to WorkOS. There are a couple configuration options shown below. You can use the optional `state` parameter to encode arbitrary information to help restore application state between redirects. - | Using organization ID Use the organization parameter when authenticating a user by their specific organization. This is the preferred parameter for SAML and OIDC connections. The example below uses the Test Organization that is available in your staging environment and uses a mock identity provider. It's created to help you test your SSO integration without having to go through the process of setting up an account with a real identity provider. - | Using connection ID You can also use the connection parameter for SAML or OIDC connections when authenticating a user by their connection ID. - | Using provider The provider parameter is used for OAuth connections which are configured at the environment level. > The supported `provider` values are `GoogleOAuth`, `MicrosoftOAuth`, `GitHubOAuth`, and `AppleOAuth`. If there is an issue generating an authorization URL, WorkOS will return the redirect URI as is. Read the [API Reference](/reference/sso/get-authorization-url) for more details. ### Add a callback endpoint Next, let's add the redirect endpoint which will handle the callback from WorkOS after a user has authenticated with their identity provider. This endpoint should exchange the authorization code returned by WorkOS with the authenticated user's profile. The authorization code is valid for 10 minutes. When adding your callback endpoint, it is important to always validate the returned profile's organization ID. It's unsafe to validate using email domains as organizations might allow email addresses from outside their corporate domain (e.g. for guest users). --- ## (2) Configure a redirect URI In the [Applications](https://dashboard.workos.com/environment/applications) section of the WorkOS Dashboard, open your application and go to the **Redirects** tab to configure allowed redirect URIs. Add your callback endpoint from the previous section. Multi-tenant apps will typically have a single redirect URI specified. You can set multiple redirect URIs for single-tenant apps. You'll need to be sure to specify which redirect URI to use in the WorkOS client call to fetch the authorization URL. > More information about wildcard characters support can be found in the [Redirect URIs](/sso/redirect-uris/wildcard-characters) guide. ![Redirects in the Dashboard](https://images.workoscdn.com/images/195dbff3-adbf-4010-b07c-ffc73ceeca68.png?auto=format&fit=clip&q=90) ### Identity provider-initiated SSO Normally, the default redirect URI you configure for your application is going to be used for all identity provider-initiated SSO sessions. This is because the WorkOS client is not used to initiate the authentication flow. However, your customer can specify a separate redirect URI to be used for all their IdP-initiated sessions as a `RelayState` parameter in the SAML settings on their side. Learn more about configuring IdP-initiated SSO in the [Login Flows](/sso/login-flows/idp-initiated-sso/configure-idp-initiated-sso) guide. --- ## (3) Test end-to-end If you followed this guide, you used the Test Organization available in your staging environment to initiate SSO. With that, you can already test your integration end-to-end. ![Test SSO WorkOS Dashboard](https://images.workoscdn.com/images/7b7407d7-dcc7-4fd4-859f-4ee4214d69c2.png?auto=format&fit=clip&q=80) Head to the _Test SSO_ page in the [WorkOS Dashboard](https://dashboard.workos.com/) to get started with testing common login flows, or read on about that in detail in the next guide. ### Test SSO Learn how to test your Single Sign-On integration end-to-end. ## Testing with the Test Identity Provider To confirm your Single Sign-On integration works correctly you can use the Test Identity Provider to simulate login flows end-to-end. Your staging environment includes a default Test Organization and active SSO connection configured with the Test Identity Provider. ![WorkOS Test Identity Provider](https://images.workoscdn.com/images/f3b0d507-2d6f-4ed8-a12f-e026c8a2987c.png?auto=format&fit=clip&q=80) ### Getting started Log into the [WorkOS Dashboard](https://dashboard.workos.com/) and navigate to the _Test SSO_ page to get started with the Test IdP. This page outlines a number of different SSO scenarios you can follow and provides all the necessary information to complete the tests. ![Test SSO WorkOS Dashboard](https://images.workoscdn.com/images/7b7407d7-dcc7-4fd4-859f-4ee4214d69c2.png?auto=format&fit=clip&q=80) ### Service provider-initiated SSO This case is likely the first [login flow](/sso/login-flows/sp-initiated-sso) you would test when implementing SSO in your app. The test simulates users initiating authentication from your sign-in page. In this scenario, the user enters their email in your app, gets redirected to the identity provider, and then is redirected back to your application. ### Identity provider-initiated SSO This test simulates users initiating authentication from their identity provider. It is a common [login flow](/sso/login-flows/idp-initiated-sso) that developers forget to consider. In the scenario, users log in to the identity provider directly, select your application from their list of SSO-enabled apps, and are redirected to your application upon successful authentication. > Ensure [AuthKit is disabled](https://dashboard.workos.com/environment/authentication/features) before testing. ### Guest email domain This test simulates users authenticating with an email domain different from the verified domain of the test organization, `example.com`. A relevant scenario is authenticating freelance users, whose email domain is not owned by the company. ### Error response This test simulates a generic [error response](/reference/sso/get-authorization-url/error-codes) from the user's identity provider. In this scenario, SSO authentication has failed for the user. Below is an example of the error-related parameters passed to the [redirect URI](/sso/redirect-uris) in your application. --- ## Testing with other identity providers Test Identity Provider saves time by providing an out of the box experience compared to the configuration process that someone using a real identity provider would have to go through to enable Single Sign-On for your app. If your integration works with the Test Identity Provider, you can be sure it will work with other identity providers. However, it may be helpful to also learn about the setup process that your customers will go through on their side, which varies depending on a specific identity provider. ### (1) Create an organization To get started, you will need to [create an organization](https://dashboard.workos.com/organizations) in the WorkOS Dashboard. Organizations in WorkOS represent your customer, so by creating an organization, you can test your SSO connection the way your customers will experience it. ![Create an organization dialog](https://images.workoscdn.com/images/2ef3565c-526a-42e6-9830-622e83b67ee5.png?auto=format&fit=clip&q=80) ### (2) Create a connection Go to the organization you created and click _Invite admin_. Select _Single Sign-On_ from the list of features. In the next step, enter an email address to send the setup link to, or click _Copy setup link_. The setup link goes to Admin Portal, where your customers get the exact instructions for every step they need to take to enable Single Sign-On with your app. > You can also integrate [Admin Portal](/admin-portal) directly into your app to enable self-serve setup of Single Sign-On and other enterprise features for your users. ![Invite an admin dialog](https://images.workoscdn.com/images/b9ab80fc-606a-417c-bade-3483ef48c2ae.png?auto=format&fit=clip&q=80) ### Follow the Admin Portal instructions To complete the integration, you'll have to also create an account with the identity provider you want to test with. After you have signed up with an identity provider of your choice, follow the corresponding Admin Portal instructions from the setup link. Once done, you can start testing your SSO integration with that identity provider. ![Admin Portal setup instructions](https://images.workoscdn.com/images/0ee15c3d-5356-4f41-a26a-440f95355b28.png?auto=format&fit=clip&q=80) The setup instructions you've seen in the Admin Portal are also available directly in the docs if you want to create a connection manually: --- ### Single Logout Learn how to implement Single Logout with WorkOS > Currently, Single Logout is only supported for [OpenID Connect connections](/integrations/oidc) and limited scenarios. > If you are looking to implement this feature, please reach out to [WorkOS support](mailto:support@workos.com). ## RP-initiated Logout With an Relying-Party-initiated (RP-initiated) logout, a user is logged out of your application and all other applications they are logged into via the identity provider. This is achieved by redirecting the user to the [Logout Redirect](/reference/sso/logout/redirect) endpoint. Before redirecting the user, you need to generate a logout token by calling the [Logout Authorize](/reference/sso/logout/authorize) endpoint with the user's profile ID which can be obtained from the [User Profile](/reference/sso/profile/get-profile-and-token) endpoint. Next, pass the logout token as a query parameter to the [Logout Redirect](/reference/sso/logout/redirect) endpoint. ![RP-initiated logout](https://images.workoscdn.com/images/63a9710b-ff61-456b-aea7-d572b3621271.png?auto=format&fit=clip&q=50) By following these steps, the user will be securely logged out of your application and all other associated applications through the identity provider. Note that, this feature is only supported for OpenID Connect providers that brings the `revocation_endpoint` and `end_session_endpoint` in the OIDC discovery document. --- ## IdP-initiated Logout For the Identity-Provider-initiated (IdP-initiated) logout, WorkOS provides the `https://auth.workos.com/sso/oidc/idp-logout/:external_key` endpoint which needs to be registered in the customer's Identity Provider as the logout endpoint for your application. When a user logs out of your application via the IdP, the IdP should call this endpoint which will redirect to a logout endpoint in your application. This logout endpoint should clear all the cookies in your application. You should contact [WorkOS support](mailto:support@workos.com) for both: - obtaining the `https://auth.workos.com/sso/oidc/idp-logout/:external_key` for registering in your customer's IdP - informing the logout endpoint in your application. ![IdP-initiated logout](https://images.workoscdn.com/images/aeda8074-7e61-4a3c-850e-278acd510bd8.png?auto=format&fit=clip&q=50) ### SAML Signing Certificates Verify the authenticity of SAML responses and requests. SAML signing certificates are X.509 certificates used in SAML responses to allow the [Service Provider (SP)](/glossary/sp) to verify the authenticity of a SAML response. Some [Identity Providers (IdP's)](/glossary/idp) may require or provide the option to use a SAML signing certificate for the SAML request as well. In these cases the IdP verifies the authenticity of the SAML request. ![SAML Flow Diagram](https://images.workoscdn.com/images/d9771da5-ee40-4e41-bc96-f393ee0af577.png?auto=format&fit=clip&q=80)\[border=false] SAML response signing certificates are generated by your customer's IdP and must then be uploaded to WorkOS manually or using a monitored metadata URL. Your customer can either upload the certificate themselves via the Admin Portal, or you can upload it for them via the WorkOS Dashboard if your customer provides it to you. Unlike SAML response signing, for request signing you will need to provide your customer with a metadata URL called the SP metadata URL. Your customer will then upload the SP metadata URL to their IdP, where it will either be monitored for updates automatically made by WorkOS, or it will be manually updated by your customer in their IdP. --- ## SAML Response Signing Certificate When the IdP sends a SAML response, the SP must verify the authenticity of the response, and that it has not been tampered with by an unauthorized third party. The SAML response signing certificate allows the SP to perform this verification. ### Sample scenario Consider the fictional SaaS company _HireOS_, which offers recruiting software to other businesses. _HireOS_ is an online application that allows its customers to track leads, candidates, and interviews. _HireOS_ is referred to as the SP by SAML. Now let's consider _HireOS_' newest enterprise customer: _Enterprise Corp_. _Enterprise Corp_ is a large enterprise company that wants to use _HireOS_ to manage their recruiting. _Enterprise Corp_ IT contacts need recruiters and other employees who will use _HireOS_ to log in using _Enterprise Corp_'s identity provider, Okta. Okta is one of many companies known as an IdP to SAML. ### Verifying the SAML response After identifying the user—whether from the SAML request or from IdP initiated SSO—Okta SAML will generate the SAML response, which includes SAML assertions, the X.509 certificate, and the signature value. Upon receiving the response from Okta SAML, _HireOS_ will verify that the response came from Okta SAML by decrypting the signature, using the public key on the X.509 certificate, and checking if the hash values match. ![SAML Response Diagram](https://images.workoscdn.com/images/96ec0449-2080-4b84-8574-43d1bc24c24a.png?auto=format&fit=clip&q=80)\[border=false] ### Planning considerations When planning your SAML integration, there are a few things to consider related to SAML response signing certificates. ### Certificate expiration Your SAML response signing certificate will eventually expire and must be kept up to date in order to maintain service. Your certificate's expiration time will vary, but typically, response certificates are valid anywhere from 1-5 years. If your certificate is uploaded in the WorkOS Dashboard, you can see when it expires by going to Organizations, selecting the Organization, and then clicking on the Connection containing the response certificate. If your company has a shared Slack channel with WorkOS, we will help ensure that your SAML response signing certificates stay up to date by automatically sending a notification before a certificate expires. ![WorkOS Dashboard UI showing a SAML certificate expiration date](https://images.workoscdn.com/images/eee34072-6363-498e-bb10-cc4f2171c98b.png?auto=format&fit=clip&q=90) ### Monitored metadata versus manual upload There are two options to upload your response certificate to a Connection, both of which can be done either in the WorkOS Dashboard, or by your customer using the Admin Portal. ### Renewing certificates To facilitate certificate renewal, WorkOS offers the ability to renew SAML certificates through the Admin Portal. When a certificate is nearing expiration (within 90 days), or has already expired, a notification will appear on the Dashboard Overview page with details about the certificate. ![Notification for expired certificate](https://images.workoscdn.com/images/5eba5473-fa61-4d57-bf60-bb9359d61797.png?auto=format&fit=clip&q=50) Alternatively, you are also able to filter connections that have either expired or expiring connections directly from the Organization page's filters. ![Organization page expired filter](https://images.workoscdn.com/images/f306979d-ab49-4c2a-832c-895d16a86041.png?auto=format&fit=clip&q=50) From the Connection page you can generate an Admin Portal link that WorkOS can email directly to the IT contact. By entering the IT contacts' email address, WorkOS will email them with a certificate renewal Admin Portal link, and they will be notified about future expiring certificates. Alternatively, you can copy the link and share it with them directly. ![Connection page for an expiring certificate](https://images.workoscdn.com/images/c7896f7f-fcde-4440-9f66-8f3dc8445568.png?auto=format&fit=clip&q=50) IT contacts will be guided through a step-by-step flow to renew their certificate; the exact steps will vary based on the IdP. ![IT contact flow for Entra ID](https://images.workoscdn.com/images/2c8334f2-3784-4e7d-8ba9-f4896da336cb.png?auto=format&fit=clip&q=50) ### Monitored metadata To streamline this process, you can instead choose to upload a metadata URL to WorkOS that we will automatically keep updated as metadata changes. If your customer's IdP refreshes a certificate, WorkOS will automatically pull in the updated metadata. Your customer can upload a metadata URL to the Admin Portal during setup. Alternatively, they can provide it to you to manually upload via the Dashboard. ![WorkOS Dashboard UI configuring a connection's metadata URL](https://images.workoscdn.com/images/6407b054-9f84-45cf-81bd-35c25b7af0b5.png?auto=format&fit=clip&q=90) ### Manual upload SP metadata such as the Entity ID, IdP SSO URL, and SAML response signing certificate can be uploaded manually through the Dashboard or the Admin Portal. This may be done either by uploading an XML metadata file, or by individually inputting metadata values. When metadata becomes out of date, such as an X.509 certificate expiring, new information must manually be uploaded. If you would like to upload the data for your customer, they must first send the relevant metadata to you. You can then upload it via the WorkOS Dashboard by navigating to the Organization and selecting the specific Connection. ![WorkOS Dashboard UI manually configuring a connection's Entity ID, IdP URL, and X509 certificate](https://images.workoscdn.com/images/5002b5ca-d94e-40a9-9dec-71575ba24a91.png?auto=format&fit=clip&q=90) --- ## SAML Request Signing Certificate When the SP sends a SAML request, the IdP must verify that the request is actually coming from the SP and has not been tampered with by an unauthorized third party. IdP's choose to handle this verification in different ways, and some use a SAML request signing certificate. Microsoft AD FS SAML uses a relying party trust, which is similar to a SAML request signing certificate, and the concepts covered in this article are applicable. In WorkOS, Connections that take advantage of a request certificate will expose an SP metadata URL that can be sent to the IdP in order to give it access to the signing certificate. ### Sample scenario Once again, let's consider the fictional SaaS company _HireOS_, which offers recruiting software to other businesses. _HireOS_ is referred to as the SP by SAML. _HireOS_' newest enterprise customer is called _Enterprise Corp_. _Enterprise Corp_ IT contacts need recruiters and other employees who will use _HireOS_ to log in using _Enterprise Corp_'s identity provider, Okta. Okta is one of many companies known as an IdP to SAML. ### Verifying the SAML request In SP initiated SSO, _HireOS_ will first send a SAML request to Okta SAML. If a request certificate is being used, then the X.509 certificate along with a signing signature will be attached to the request. Upon receiving the request, Okta SAML will verify that the request came from _HireOS_ by decrypting the signature using the public key on the X.509 certificate and confirming the hash values match. ![SAML Request Diagram](https://images.workoscdn.com/images/6f244bd0-3f76-434f-99c3-be8bcf65d3da.png?auto=format&fit=clip&q=80)\[border=false] ### Planning considerations When planning your SAML integration, there are a few things to consider related to SAML request signing certificates. ### Certificate expiration Your SAML request signing certificate will eventually expire and must be kept up to date in order to maintain service. WorkOS will automatically update the request signing certificate on the SP metadata URL before it expires. It is up to your customer and their IdP to either monitor the SP metadata URL, or manually keep it up to date. If your company has a shared Slack channel with WorkOS, you will automatically be notified when the X.509 certificate on the SP metadata URL is updated, so that you can check with your customer that they have the latest metadata. ### Monitored metadata versus manual upload There are potentially two options for your customer to upload SP metadata, and will vary based on their IdP. In both cases, you will need to provide your customer with the SP metadata URL, which can be found in the WorkOS Dashboard by going to Organizations, selecting the Organization, and then selecting the Connection. ![WorkOS Dashboard UI with SP metadata URL](https://images.workoscdn.com/images/5bab9063-e0cd-4bca-abe6-68db5162be5e.png?auto=format&fit=clip&q=90) ### Monitored metadata To streamline this process, your customer instead may choose to monitor our SP metadata URL. Their IdP will regularly check our URL for updates to the metadata. When WorkOS makes an update, such as refreshing an X.509 certificate that is expiring soon, their IdP will automatically make the change. ### Manual upload Your customer can manually download the SP metadata document from the URL, extract the certificate, and upload it to their IdP. When the certificate is getting ready to expire, they can repeat this process to give their IdP the most up to date certificate. ## Implementing SSO with WorkOS This document offers guidance to integrate Single Sign-On with our standalone API into your existing auth stack. You might also want to look at [AuthKit](/authkit), a complete authentication platform that leverages Single Sign-On functionality out of the box, following best practices. ### Sign-in Consent Learn about the sign-in consent screen, an extra layer of protection against login CSRF attacks and phishing attempts. The sign-in consent screen is an extra layer of protection against login CSRF attacks or phishing attempts. A user may click a link that appears legitimate, but which unknowingly leads them to signing in through a malicious identity provider controlled by an attacker. The sign-in consent screen mitigates this risk by displaying the user's email and the identity provider's domain, ensuring the user is aware of how they are signing in to the application. ## How it works The sign-in consent screen is an interstitial page that appears during the Single Sign-on flow, after the user has gone through the identity provider (IdP), before redirecting to the application. ![Sign-in consent screen](https://images.workoscdn.com/images/32760d6d-eb42-480f-92bc-fe6d2e8709ea.png?auto=format&fit=clip&q=80) This page displays to the user the `email` returned from the IdP, as well as the IdP origin. With this information, the user must either consent to or deny the sign-in flow. - **Consenting sign-in** leads to completing the SSO flow, where the authorization code is forwarded to the application callback. - **Denying the sign-in** will result in an SSO session failure and the user will be redirected to the application callback with a `signin_consent_denied` error. ## Enabling sign-in consent In order to activate the sign-in consent protection, you should go to the **Authentication** section and enable the sign-in consent checkbox in the Single Sign-On settings. ![Enable sign-in consent checkbox](https://images.workoscdn.com/images/0ab5bb9f-6acb-45d0-a351-468a7e57a428.png?auto=format&fit=clip&q=80) ## Handling the `signin_consent_denied` error We recommend using the `signin_consent_denied` error code to display useful information to the user, so that they can contact their admin and your support team for information about a possible phishing attempt. When a user denies the sign-in consent, your application's callback will receive an error response: ```url title="Redirect URI with signin_consent_denied error" https://your-app.com/callback?error=signin_consent_denied&error_description=User%20cancelled%20the%20authentication%20request&state=123456789 ``` For more information about error handling, see the [Get Authorization URL error codes](/reference/sso/get-authorization-url/error-codes) documentation. ## When sign-in consent is displayed WorkOS determines whether the sign-in consent screen should be displayed, based on the identity provider, user fingerprint, and SSO flow parameters. Once a user accepts the sign-in consent screen, the system remembers this approval and avoids displaying the page again for a better user experience. The sign-in consent screen is always displayed in the following scenarios: - **IdP-initiated flows**: The sign-in consent screen is always displayed for IdP-initiated flows (i.e. users clicking on a tile in their IdP), regardless of the identity provider, if the user has not previously approved it. - **Custom SAML or OIDC connections**: The sign-in consent screen is displayed for custom connections if the user has not previously approved sign-in consent. ## Branding The sign-in consent screen automatically inherits the Admin Portal branding and is served through your custom authentication API domain, if available. If you have AuthKit enabled, the sign-in consent screen will follow your AuthKit branding instead. Ensure you review the primary button color and logos before enabling this feature. This ensures a trusted experience for your customers. ## Availability The sign-in consent screen is available for both AuthKit and Standalone SSO users. It is enabled by default for new environments. ### SAML Security Considerations Learn about additional SAML features that WorkOS supports. SAML requests and responses each have their own unique confidentiality and integrity features. To use [SAML](/glossary/saml) with WorkOS, the only requirement is that the Identity Provider ([IdP](/glossary/idp)) signs the assertions within the SAML authentication response. However, you may have customers that have stricter configuration requirements or you may simply want to raise the security bar by following recommendations. This document details what security features are available, how they can benefit you, your customer and their identity provider. The parties involved in a SAML authentication request and response flow are: - Identity Provider - Service Provider ([SP](/glossary/sp)) - User Agent, i.e. a browser --- ## SAML Binding Methods WorkOS uses the HTTP Redirect binding to transmit SAML authentication requests from the SP to the IdP, and the HTTP POST binding to receive SAML responses from the IdP back to the SP: - Redirect binding sends the request via HTTP GET, with the SAML message included in the URL. - POST binding delivers the response via HTTP POST, with the SAML message in the form body. --- ## SP to IdP security features The SAML authentication request is a way for the SP to request confirmation that the user they're presented with is who they're claiming to be. It is relayed to the IdP via the user agent. ![SAML authentication request options](https://images.workoscdn.com/images/dc5df10c-50dc-4bb0-bede-26d16b197f20.png?auto=format&fit=clip&q=80) ### SAML request signing To address the opportunity to spoof or tamper with a SAML request to the IdP, the IdP may require that all SP's sign the request. To accommodate this there needs to be a pre-existing relationship between the SP and IdP where a key-pair is shared. The IdP holds the public key (for verifying the request) and the SP holds the private key (for signing the request). WorkOS recommends SAML request signing, this is especially important in cases where HTTPS is terminated or interrupted prior to reaching the IdP. All of our requests embed the `` timestamp to allow the IdP to reject stale requests, however to mitigate tamper of this value request signing must be used.\ (See [SAML 2.0 Security Considerations](https://docs.oasis-open.org/security/saml/v2.0/saml-sec-consider-2.0-os.pdf) sections 5.2.1.2, 6.5.1 for more detail). | Supported by WorkOS | Enabled by default | Usage recommendation | | ------------------- | ------------------ | --------------------------------- | | Yes | No | Use with any IdP that supports it | WorkOS supports SAML request signing for all compatible connection types. Please [contact WorkOS support](mailto:support@workos.com) to enable it. --- ## IdP to SP security features The SAML response is an XML document provided by an IdP containing details about a user so that an SP can authenticate them. It is relayed to the SP via the user agent. ![SAML authentication response options](https://images.workoscdn.com/images/f888365e-fa7d-4c1e-a76d-a19777e6cbb2.png?auto=format&fit=clip&q=80) For reference in understanding the following features, below is a simplified hierarchy of the XML elements in a SAML Response: ```xml title="SAML response" ... ``` ### Signed response assertions This is **required** by WorkOS for all SAML connections. It is a core requirement for SAML IdPs to implement as of SAML 2.0 (see [SAML 2.0 Profiles](https://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf) section 4.1.3.5). | Supported by WorkOS | Enabled by default | Usage recommendation | | ------------------- | ------------------ | --------------------------------------- | | Yes | Yes | All WorkOS SAML connections must use it | Signed response assertions are enabled in the setup steps when you [create a SAML connection](/integrations/saml). ### Signed response message envelope This is the complete signature over the SAML response payload. In combination with an assertion signature it will provide additional integrity protection and is recommended by WorkOS (For details on threats addressed see [SAML Security Considerations](https://docs.oasis-open.org/security/saml/v2.0/saml-sec-consider-2.0-os.pdf) sections 7.1.1.6, 7.1.1.7). | Supported by WorkOS | Enabled by default | Usage recommendation | | ------------------- | ------------------ | --------------------------------- | | Yes | No | Use with any IdP that supports it | Please [contact WorkOS support](mailto:support@workos.com) to enable signed response message envelope. ### Encrypted response assertion The SAML assertions in the SAML response may contain sensitive data, and therefore there is an option to encrypt them to preserve confidentiality. This feature is recommended in scenarios where the SAML response travels through HTTPS termination, so that accidental logging of sensitive data can be mitigated. | Supported by WorkOS | Enabled by default | Usage recommendation | | ------------------- | ------------------ | --------------------------------- | | Yes | No | Use with any IdP that supports it | Please [contact WorkOS support](mailto:support@workos.com) to enable encrypted response assertion. ### Encrypted response attributes The attribute statement is a sub-element of the assertion, some or all of the attributes in the statement can be encrypted as part of the SAML authentication protocol. | Supported by WorkOS | Enabled by default | Usage recommendation | | ------------------- | ------------------ | ------------------------------------ | | No | No | Use **encrypted assertions** instead | WorkOS does not currently support encrypted response attributes. It is recommended to use assertion encryption to envelope all the attributes if confidentiality is required. ## Implementing SSO with WorkOS This document offers guidance to integrate Single Sign-On with our standalone API into your existing auth stack. You might also want to look at [AuthKit](/authkit), a complete authentication platform that leverages Single Sign-On functionality out of the box, following best practices. ### Redirect URIs Learn what a redirect URI is and how it relates to Service Provider and Identity Provider initiated login flows. ## Introduction With a [WorkOS Service Provider (SP) initiated login flow](/sso), there are a series of exchanges that take place between a Service Provider (your application), WorkOS, and the IdP that's being used to authenticate the user as shown in the diagram below. The [Redirect URI](/glossary/redirect-uri) is the location to which the user gets returned to after successfully completing the authentication with their [Identity Provider (IdP)](/glossary/idp). With an Identity Provider (IdP) initiated login flow, the approach is similar but the user will begin the login flow by clicking on the tile within their IdP platform instead of from your application. ![Authentication Flow Diagram](https://images.workoscdn.com/images/90b84f08-3363-446a-8610-f7b2bd2ee2ca.png?auto=format&fit=clip&q=80) In WorkOS Production Environments, the Redirect URI to your application cannot use HTTP or localhost, however, Redirect URIs that use HTTP and localhost are allowed in Sandbox Environments. There should be at least one redirect URI configured and selected as a default for your application. In the [Applications](https://dashboard.workos.com/environment/applications) section of the WorkOS Dashboard, open your application and go to the **Redirects** tab to configure redirect URIs. If you try to route the authorization flow to a Redirect URI that is not yet defined for the application, it will result in an error and users will be unable to sign in, so it's important to define them in the dashboard first. ![Dashboard Redirect URIs](https://images.workoscdn.com/images/6da31d23-c823-4557-8403-b38b2700e4d2.png?auto=format&fit=clip&q=50) The Redirect URI can also be included directly in the Get Authorization URL call as a redirect\_uri parameter. When the Redirect URI is set in this fashion, it will override the default redirect URI configured for your application. --- ## Wildcard characters WorkOS supports using wildcard characters (`*`) in Redirect URIs to handle dynamic subdomains or variable ports during development. ![Dashboard updating the redirect URIs to use a wildcard in staging](https://images.workoscdn.com/images/12f99da0-ef62-4b09-acf8-b3d05b48f9e3.png?auto=format&fit=clip&q=50) ### Subdomains The `*` symbol can be used as a wildcard for subdomains; however, it must be used in accordance with the following rules: - The protocol of the URL **must not** be `http:` in production environments. - The wildcard **must** be located in the subdomain furthest from the root domain (e.g., `https://*.sub.example.com` will work, but `https://sub.*.example.com` will not). - The URL **must not** contain more than one wildcard. - A wildcard character **may** be prefixed and/or suffixed (e.g., `https://prefix-*-suffix.example.com`). - A wildcard **will not** match across multiple subdomain levels (e.g., `https://*.example.com` will not match `https://sub1.sub2.example.com`). - Wildcards cannot be used with [public suffix domains](https://publicsuffix.org) (e.g., `https://*.ngrok-free.app` will not work). - The wildcard will match letters, digits, hyphens, and underscores. - A URL with a wildcard cannot be set as the default redirect URI. ### Ports To support [RFC 8252](https://datatracker.ietf.org/doc/html/rfc8252#section-7.3) ("OAuth 2.0 for Native Apps") and local development, a wildcard may be used in place of the port number. - This is strictly limited to `localhost` and loopback IP addresses (e.g., `127.0.0.1`). - Example: `http://localhost:*/auth/callback` is valid. ## Implementing SSO with WorkOS This document offers guidance to integrate Single Sign-On with our standalone API into your existing auth stack. You might also want to look at [AuthKit](/authkit), a complete authentication platform that leverages Single Sign-On functionality out of the box, following best practices. ### Login Flows Learn the differences between SP‑initiated and IdP‑initiated SSO. The instructions in the [Quick Start guide](/sso) focus on setting up Service Provider (SP)-initiated SSO. In these scenarios, when a user attempts to login, they navigate to an application (a service provider) and are then redirected to the [Identity Provider (IdP)](/glossary/idp) for authentication, via the WorkOS API. Alternatively, most users are able to start the process from the Identity Provider itself. Organizations will often provide an IdP dashboard where employees can select any of the eligible applications that they can access via the IdP, similar to the screenshot below. Clicking on a tile results in an IdP-initiated login flow, since the user initiates the login from the Identity Provider, not the application. ![Screenshot of the Okta dashboard](https://images.workoscdn.com/images/1489f46f-bbcd-4e47-a217-3a45f0f795aa.png?auto=format&fit=clip&q=50) --- ## SP-initiated SSO With an SP-initiated login flow, the user begins the authentication process from your application. You can control where the user will be redirected after login by specifying the `redirectURI` parameter when making the [Get Authorization URL](/reference/sso/get-authorization-url) call. Additionally, this call can take an optional `state` parameter - this parameter will be returned in the callback after authentication, where your application can use it to verify the validity of the response or to pass any state from the originating session. One common practice is to route requests from different Organizations to a single Redirect URI, but instead utilize the `state` parameter to deep link users into the application after the authentication is completed. --- ## IdP-initiated SSO If you follow the instructions in the [Quick Start guide](/sso), IdP-initiated login flows will automatically be available, and users will be able to find a tile for your application within their IdP, similar to the screenshot above. Clicking on the tile will send an IdP-initiated SSO response to your application's callback endpoint. ### Configure IdP-initiated SSO Normally, IdP-initiated logins are sent to the default Redirect URI of your default application. To customize this, configure a `RelayState` in the IdP as URL parameters. Two parameters are supported: - `client_id` routes the user to a specific [application](/authkit/applications) ```text client_id=client_123456789 ``` - `redirect_uri` sends the user to an alternate Redirect URI from those configured in the [Applications](https://dashboard.workos.com/environment/applications) section of the WorkOS Dashboard. Open your application and go to the **Redirects** tab to manage these URIs. ```text redirect_uri=https://example.com/callback ``` Any other values in the `RelayState` are ignored. Your application will also be able to retrieve the [Profile object](/reference/sso/profile) for the user upon successful authentication. If your IdP is unable to provide a `redirect_uri` in its default `RelayState`, or if you would like to generate a custom redirect URI for each user after they sign in, you can use the [Profile object](/reference/sso/profile) to dynamically generate a redirect URI. ```json title="Example Profile" { "id": "prof_01DMC79VCBZ0NY2099737PSVF1", "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", "connection_type": "okta", "email": "todd@example.com", "first_name": "Todd", "idp_id": "00u1a0ufowBJlzPlk357", "last_name": "Rundgren", "object": "profile", "custom_attributes": {} } ``` The Profile object includes the `connection_id` which identifies the connection that the profile is associated with in WorkOS. We recommend using the connection information for routing requests in an IdP-Initiated flow. ### Disable IdP-initiated SSO (Beta) We have recently added Beta support for fully disabling IdP-initiated SSO logins for a connection. Once disabled, any attempted IdP-initiated requests will fail with an `idp_initiated_sso_disabled` error. > Disabling IdP-initiated SSO is currently in invite-only beta, please reach out to [WorkOS support](mailto:support@workos.com) if you'd like to use it or learn more about it. For applications that need to support IdP-initiated workflows, but would like to mitigate the security risks of unsolicited SAML responses, WorkOS recommends the following: - Disable IdP-initiated SSO for your connection. - Adjust your callback method to capture the `idp_initiated_sso_disabled` error. - Start a new SP-initiated request from the callback when the error is detected. The error callback will include the connection and organization ID's, which can be used to request a new authorization URL for the SP-initiated request. The new request will generally be transparent to the user, as they are already logged in to the Identity Provider. ## Implementing SSO with WorkOS This document offers guidance to integrate Single Sign-On with our standalone API into your existing auth stack. You might also want to look at [AuthKit](/authkit), a complete authentication platform that leverages Single Sign-On functionality out of the box, following best practices. ### Launch Checklist Make sure you're ready to take your app to production. ## Implement complementary enterprise features - Integrate the WorkOS [Admin Portal](/admin-portal) to enable your users to onboard and set up SSO themselves. - Integrate the WorkOS Directory Sync API for automatic user updating, provisioning, and deprovisioning. ### Before you start This document offers guidance to integrate Single Sign-On with our standalone API into your existing auth stack. You might also want to look at [AuthKit](/authkit), a complete authentication platform that leverages Single Sign-On functionality out of the box, following best practices. ## Create an IP Allowlist WorkOS makes use of Cloudflare to ensure security and reliability of all operations. If you are looking to create a list of allowed IP addresses for redirect requests, you can use the IP Ranges listed in the [Cloudflare documentation](https://www.cloudflare.com/ips/). ## Go-live checklist - \[ ] Implement an SSO UI/UX. See our guide for ideas – [UI/UX Best Practices for IdP & SP-Initiated SSO](https://workos.com/blog/ui-ux-best-practices-for-idp-and-sp-initiated-sso) - \[ ] [Test the end-to-end SSO](/sso/test-sso) experience in your Staging environment. - \[ ] Unlock your Production environment by adding your billing information > Only enterprise connections in your Production environment will be charged. OAuth connections in Production will be free. - \[ ] Set your Production Client's ID and API Key as environment variables - \[ ] Secure your Production Project's API key - \[ ] Configure production redirect URI(s) for your application. Verify the default redirect URI is correct - \[ ] Ensure that your application can receive redirects from WorkOS. Depending on your network architecture, you may need to allowlist incoming redirect traffic from `api.workos.com`. - \[ ] Add Connections for your customers in the Production Environment ## Frequently asked questions ### How should an application handle the first time a user authenticates using WorkOS? If a user is authenticating to your application for the first time via SSO and doesn't have an account, you can implement just-in-time provisioning to create a user when authentication is complete. You can also leverage [Directory Sync](/directory-sync) to pre-provision users with API endpoints or webhooks. In this case, the user will already be created in your application when they authenticate for the first time. ### Can we add SSO authentication for a current user in an application? If a user is authenticating to your application via SSO, but already has an account (with username/password for example), you can "upgrade" them to SSO. Usually the emails are the same for both methods of authentication, so you can match on email address. Once SSO via WorkOS is enabled, you can restrict users to sign in with only SSO. ### How does WorkOS manage user attributes from an identity provider? WorkOS normalizes user attributes so you can expect known values such as `id`, `email`,`firstName`, and `lastName`. ### Is the user attribute mapping configurable in WorkOS? Yes. For example, let's say the `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname` attribute contains the user email rather than the `surname` as the attribute name suggests. In these edge cases, WorkOS will identify any attributes that are misconfigured and recommend correct mapping in the "Attribute Mapper" section of the "Connection info" page. ### What does the "Allow Profiles Outside Organization" option do? By default, WorkOS restricts user profiles for SAML Connections to profiles that have email domains that are in the set of [User Email Domains](/reference/domain-verification) on the Organization. Enabling this option removes this restriction and allows user profiles with any email address to sign in through Connections under this Organization. If this option is enabled, your code can not exclusively trust the returned `email` attribute on user profiles to be a verified email address. Instead, you must use the `organization_id` or `connection_id` in order to verify that the profile belongs to whom it claims. ### What does "There are 0 profiles awaiting reconciliation" refer to? This refers to the number of user profiles that have inconsistent attribute mappings, and that need to be updated in order to successfully authenticate. ### How do I integrate WorkOS SSO with my native mobile application? When it comes to mobile applications, our typical advice in implementing SSO authentication goes like this: 1. Generate the authentication URL and route the user to a browser or browser fragment in order to authenticate. 2. The end user authenticates via the native UI of their IdP within that browser. 3. Upon successful authentication, deep-link the user back into your native application. ### Just-In-Time User Provisioning Learn how to provision users in your app using Just-In-Time user provisioning. ## Introduction User provisioning is the process of creating a user account and associated identity information. There are various ways for an application to provision users. This guide explores user provisioning strategies and offers a deep dive into SSO-based just-in-time (JIT) user provisioning. ## Definitions **User provisioning** : Provisioning is the process of creating a user and setting attributes for them inside an app. **JIT user provisioning** : Just-in-time user provisioning creates a user in an app when the user attempts to sign in for the first time. The account and respective role don't exist until the app creates them – just-in-time. **Identity** : An identity is a collection of attributes associated with a user or entity in an identity provider. For example, an identity includes at least one unique identifier, such as id, and user profile attributes, such as name and email. **Role** : A primitive in your app that defines specific permissions for the users. Roles are often defined as an ability or a job title, for example, "Editor" or "Accountant". ## User provisioning strategies User provisioning is the process of creating a user account with associated identity data in your app. Your app needs to determine a unique identifier for an identity, create a unique account for that user, and link the identity profile attributes to that user's account. There are many strategies to provision users in an app, but the main three are: 1. Self-registration 2. Provisioning users via [Directory Sync](/directory-sync) 3. JIT provisioning via SSO The type of provisioning needed will depend on your app's architecture and level of enterprise feature support: | Strategy | Description | Usage | | ---------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | Self-registration | Users fill out a registration form to create an account in the app | For users that don't have an SSO service, usually the first authentication mechanism built in an app | | Pre-provisioning users | Use a service like Directory Sync to create users in the app | Required by large enterprises to automatically provision users | | JIT provisioning | Create a user account when a user signs in via SSO for the first time | Leverage user identity from an SSO provider to create an account in your app | ## What is JIT provisioning? JIT provisioning creates a user account with associated identity information when a user authenticates via SSO for the first time. IT contacts often use JIT provisioning to quickly set up accounts in an app. Typically, apps that implement only SSO will have JIT provisioning support as the alternative is self-registration by individual users or manual entry of all users by the IT contact. ### Sample scenario Consider the fictional SaaS company _HireOS_, which offers recruiting software to other businesses. _HireOS_ is an online app allowing customers to track leads, candidates, and interviews. _HireOS_ has integrated SSO using WorkOS and supports JIT provisioning. For example, a _HireOS_ customer would like their users to have accounts automatically provisioned in _HireOS_ when they first log in. The customer's IT contact will only need to assign the users to the _HireOS_ SAML app in their identity provider. When users log into _HireOS_ via SSO, they will have accounts created in _HireOS_, just in time. A usual account setup flow using JIT provisioning follows these steps: 1. An IT contact self-registers via username and password to create a team account in _HireOS_. 2. The IT contact configures the _HireOS_ team account to use SSO as the authentication mechanism. 3. The IT contact enables JIT provisioning for this team account by clicking the "Enable JIT Provisioning" checkbox. 4. The IT contact adds the users that should get access to _HireOS_ to the app in the identity provider. 5. When a user logs into _HireOS_ with the correct email domain and authenticates via SSO, _HireOS_ creates the user account upon successful first-time login. ## JIT provisioning with WorkOS SSO When a user authenticates to your app via SSO for the first time, and JIT provisioning is enabled, your app provisions a new user account. You can create the account by saving the identity information (the WorkOS SSO profile) directly on your app's user account. Or, you can create a separate identity from the WorkOS SSO profile related to this new user account. This logic allows users to have multiple identities if your app supports several login methods per user. You can use the WorkOS SSO profile `id` attribute as the unique identifier for this identity from WorkOS. WorkOS ensures the profile is unique per SSO connection via the `idp_id`. In addition, your app can use either the `connection_id` or `organization_id` to tie the identity to a team account. ```json language="json" title="SSO user profile" { "object": "profile", "id": "prof_01DMC79VCBZ0NY2099737PSVF1", "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", "connection_type": "OktaSAML", "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", "email": "todd@example.com", "first_name": "Todd", "last_name": "Rundgren", "idp_id": "00u1a0ufowBJlzPlk357", "role": { "slug": "admin" } } ``` You may want to grant new users roles in your application via JIT provisioning. For more information on mapping role data between the IdP and your app, see the [Mapping Roles](/sso/identity-provider-role-assignment) guide. ### New account creation When your app receives a WorkOS SSO profile, it is standard to perform the following series of checks: 1. Find an identity with the profile `id` or `idp_id`. If found, log in the corresponding user. 2. If you cannot find an identity, try to find a user with the same `email` as the profile. If found, create an identity for the user and log them in. 3. Otherwise, create a new identity using the WorkOS SSO profile, create a new user, and associate this identity with the user account. ### Linking an existing user If an admin adds SSO authentication to their team account after they've had users register, your app can link these new SSO identities to the current user accounts, just-in-time. A linking field (e.g. `email`) should be established to find a current user with the incoming WorkOS SSO Profile. Then, the identity information can be linked with the existing user account via a persistent identifier in case of an email change later. ## Implementing SSO with WorkOS This document offers guidance to integrate Single Sign-On with our standalone API into your existing auth stack. You might also want to look at [AuthKit](/authkit), a complete authentication platform that leverages Single Sign-On functionality out of the box, following best practices. ### FAQ for IT teams Answers to common questions from your customer's IT team. ## What is WorkOS? WorkOS is a software company that provides a suite of products to make an app enterprise-ready. These products include Single Sign-On, Directory Sync, and AuthKit (user management), among others. Developers integrate WorkOS services into their apps in order to provide a secure authentication and user provisioning experience. It's trusted by companies like Webflow, Plaid, Vercel, and many others. ## What data does WorkOS store? For Single Sign-On, WorkOS stores the user profile from the identity provider. This includes the user's name, email and IP address. For Directory Sync, WorkOS will store the data that the identity provider sends. The shape and content of that data is at the discretion of the identity provider. For more information, view our [Privacy Policy](https://workos.com/legal/privacy) ## How do developer apps communicate with WorkOS? Developers integrate with WorkOS using its Rest API and the related SDKs. You can find a list of all WorkOS API endpoints in the [API reference](/reference). ## What IP addresses does WorkOS use? WorkOS uses Cloudflare to ensure security and reliability of all operations. If you are looking to create a list of allowed IP addresses for the WorkOS API, you can use the IP ranges listed in the [Cloudflare documentation](https://www.cloudflare.com/ips/). ## Is WorkOS certified for SOC 2 Type II, SOC 3 and SIG Lite? Yes, WorkOS is compliant with all the above and regularly undergoes penetration testing. ## Is WorkOS GDPR compliant? Yes, WorkOS is GDPR compliant. Reach out to [support](mailto:support@workos.com) to request deletion of data. ### Identity Provider Role Assignment Learn how to map role data from identity providers to roles in your app with SSO. ## Introduction A role represents a logical grouping of permissions, defining access control levels for users within your application. Roles are identified by a unique, immutable slug and are assigned to [SSO user profiles](/reference/sso/profile) through their identity provider group memberships. These group role mappings can be configured on the WorkOS dashboard. To utilize Identity Provider (IdP) role assignment, you must first [configure roles](/rbac/configuration). ## SSO group role assignment Users are assigned to groups via the identity provider. Groups usually correspond to roles in your app. Therefore, IT contacts will often map a group one-to-one to a role. During authentication, a user's identity provider group memberships can be read via attributes. This enables you to define SSO groups that correspond to IdP groups and set role assignments for those groups in the WorkOS Dashboard. Based on these settings, SSO user profiles returned from WorkOS will include a role attribute that reflects their highest priority group membership. The SSO user profile role is calculated during each sign-in. ![Session page showing user profile with role defined](https://images.workoscdn.com/images/ceea13ba-bf6b-4ea1-a25c-0a08e8833fb0.png?auto=format&fit=clip&q=50) > Supported in both SAML and OIDC-based connection types, except for Google OIDC due to [a limitation](https://issuetracker.google.com/issues/133774835?pli=1) with the groups claim. ### Sample scenario Consider the fictional SaaS company _HireOS_. _HireOS_ has set up an SSO Connection and configured group-based role assignment. For example, a _HireOS_ customer would like to assign their engineering team to the application. The customer's IT contact would take the following steps: 1. Create an "Engineering" group using their identity provider. 2. Configure the `groups` attribute in their SAML app to return the group memberships. 3. Provide the developer with the IdP Group ID for the "Engineering" group. In the WorkOS dashboard, the developer can then assign users of that group to the role "Engineer". 1. Navigate to the _Connection_ section of the WorkOS dashboard. ![SSO group role assignment card](https://images.workoscdn.com/images/28606b9b-fd5b-4219-8b8f-3a640295e784.png?auto=format&fit=clip&q=50) 2. Create an SSO group defining the IdP Group ID for the "Engineering" group. Then, assign this group to the "Engineer" role. ![Dialog to create connection group with role assignment](https://images.workoscdn.com/images/648410f3-1b82-4ebd-97f3-a8f6edbdd27e.png?auto=format&fit=clip&q=50) From this point on, whenever a user in the "Engineering" group authenticates via SSO, they will be granted the "Engineer" role for that session from the WorkOS API. The role will be returned in the [profile response](/reference/sso/profile). ```json language="json" title="SSO user profile" { "object": "profile", "id": "prof_01DMC79VCBZ0NY2099737PSVF1", "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", "connection_type": "OktaSAML", "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", "email": "todd@example.com", "first_name": "Todd", "last_name": "Rundgren", "idp_id": "00u1a0ufowBJlzPlk357", "role": { "slug": "engineer" }, "roles": [ { "slug": "engineer" } ] } ``` > When a user is not a member of any groups or their groups do not match any SSO group role assignments, the user will be granted the [default role](/rbac/configuration/configure-roles/default-role) in the SSO profile. ### Multiple roles When [multiple roles is enabled](/rbac/configuration/configure-roles/multiple-roles), a user can be assigned multiple roles from their identity provider group memberships. If a user belongs to multiple mapped groups, they will receive all corresponding roles in their SSO profile. For example, if a user is a member of both "Engineering" and "Design" groups, and both groups are mapped to roles, the user will receive both the "Engineer" and "Designer" roles. If a user is not a member of any groups with explicit mappings, they will receive the [default role](/rbac/configuration). #### Use cases By default, multiple roles is disabled and users can only have a single role per entity. It's recommended to start with a single-role setup for simplicity, where it's easier to maintain consistent and correct access patterns. You might want to enable multiple roles when you need: - **Cross-department collaboration**: e.g., designers who need some engineering permissions. - **Additive, disjoint permissions**: independent permission sets that should stack. - **Temporary access**: grant time-bound extra capabilities without creating hybrid roles. ### Role assignment in Admin Portal Once [roles](/rbac/configuration) are configured for your application, enable SSO group role assignment in [Admin Portal](/admin-portal) to allow IT contacts to assign roles to groups during SSO connection setup. If enabled, all Admin Portal sessions for SSO connections will have the ability to configure and assign roles to groups. ![Enable SSO group role assignment dashboard setting](https://images.workoscdn.com/images/04f86ccc-87a1-4db6-bd54-54a685d409ef.png?auto=format&fit=clip&q=50) This is an environment-level setting, but can be configured per organization via the _Roles_ tab under an organization in the WorkOS Dashboard. ## Considerations Your customers will store role information in different forms, depending on their preferred provisioning workflow. WorkOS allows for flexibility in how you source role data. However, there are some considerations to keep in mind when using SSO-based connection groups for role assignment. ### Drawbacks **Strictly** assigning roles during [JIT user provisioning](/sso/jit-provisioning) has a few caveats: - Your customer must explicitly map the SAML `groups` attribute in the SSO setup so that you can retrieve that attribute in the SSO profile. - SSO groups need to be manually defined. - Your app will receive updates to this user's group data only once they sign-in with SSO again. This delay can allow unauthorized users to access resources using a stale role. ### Directory group role assignment Directory Sync supports [group-based role assignment](/directory-sync/identity-provider-role-assignment/directory-group-role-assignment) and avoids the pitfalls mentioned above. For organizations with a directory, this method of group-based role assignment is preferred. It's recommended to use only one method of role assignment—either from a Directory or an SSO Connection—to avoid overlap. ### Example Apps View sample Single Sign-On apps for each SDK. You can view minimal example apps that demonstrate how to use the WorkOS SDKs to authenticate users via SSO: ### Domains Understand how Organization domains are used with SSO. ## Organizations When an [Organization](/reference/organization) is created in the WorkOS Dashboard or the [Create Organization API](/reference/organization/create), one or more domains can be associated with the organization. Domains added to an organization need to be verified in order to activate SSO. When creating an organization via the API, domains can be initially added as either `'verified'` if already trusted, or `'pending'` if further verification is required. If added as `'pending'`, the domain can later be verified via the WorkOS Dashboard, by an IT contact via the self-serve [Admin Portal](/domain-verification/) flow, or through successful [DNS verification](/domain-verification/api). > Domains manually added in the WorkOS Dashboard are automatically considered verified. ## Email validation During authentication, WorkOS uses these domains to verify the user signing in through the organization's [Connection](/reference/sso/connection) belongs to one of these domains. If the domain of the user's email address does not match one of the organization's domains (or the organization has no verified domains) they will be sent to your [Redirect URI](/sso/redirect-uris) with a [`profile_not_allowed_outside_organization`](/reference/sso/get-authorization-url/error-codes) error. Rejecting users with non-matching email domains prevents the impersonation of users in other organizations. This would otherwise be possible since many Identity Providers allow IT contacts to create user accounts with _any_ email address, regardless of whether the IT contact actually controls the email address or its domain. For example, an IT contact of an organization with the domain `foo.com` can create a user account for `user@bar.com` in their Identity Provider and then sign in as that user. If the application were to receive the profile and naively look up the user record using _only_ the email address, then the IT contact will have gained access to the `user@bar.com` account. Since WorkOS cannot guarantee every application handles this scenario correctly, **the default behavior is to reject profiles when its email address does not match the associated organization's domains.** ## Allowing any domain Some applications may have organizations whose users sign in using a list of domains that cannot be statically defined, or a set of domains so large as to be cumbersome to configure. A common use-case is non-domain guests. Imagine an organization hires a design consultancy and requires the designers to sign in using the organization's IdP. While the organization can create accounts in their IdP for these guests, they cannot add the designer's domain to the WorkOS organization since they cannot verify ownership of it. The default organization domain verification policy will prevent these designer's from signing in. If your application has a similar use-case, [contact support](mailto:support@workos.com) and we can work with you to relax the default organization domain verification policy. SSO will no longer require any domains to be added to the organization. This change can be made for any of your environments and will affect all organizations in the environment. ## Implement profile validation Your application will be responsible for validating the email addresses of users using SSO, and checking the appropriate fields from the SSO profile. Important data from the SSO profile includes the `id` and the `organization_id`. Generally applications will store the Profile `id` alongside its users, such as a column on a `users` table. Similarly, the `organization_id` will be stored on the matching entity, such as a `teams` or `workspace` table; whichever represents a collection of users that are related to each other. ```json language="json" title="SSO profile" { "object": "profile", "id": "prof_01DMC79VCBZ0NY2099737PSVF1", "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", // Your application should restrict any email-based JIT user // provisioning to within the organization that matches this ID. "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", // Only match based on email or email domain unless you are // filtering potential matches by the organization ID above. "email": "todd@example.com" // ... } ``` Here's an updated version of the WorkOS callback endpoint from the [Quick Start guide](/sso/1-add-sso-to-your-app/add-a-callback-endpoint) with examples of these checks added: ```javascript langauge="JavaScript" title="WorkOS callback" const { WorkOS } = require('@workos-inc/node'); const workos = new WorkOS(process.env.WORKOS_API_KEY); app.get('/callback', async (req, res) => { const { profile } = await workos.sso.getProfileAndToken({ code: req.query.code, clientId: process.env.WORKOS_CLIENT_ID, }); // Your application should have a resource that is analogous to the WorkOS // organization, like a "team" or "workspace". const team = TeamsService.findByWorkOsOrganizationId(profile.organizationId); if (!team) { return res.status(401).send({ message: 'Unauthorized', }); } // Your application should use the Profile ID to determine whether there is an // existing user linked to the SSO profile, within the scope of the "team" or // "workspace" associated with the WorkOS organization. // // If none is found, you can then fall back to the `email` address. If one is // found you should link the profile ID to the user for subsequent sign-ins. // // Finally, if no user exists with the email either, you can implement // JIT-provisioning and create a new user record, persisting both the `email` // and the ID from the profile. const { user } = team.users.findOrCreateByWorkOsProfile(profile); // Make sure to verify the user's email address. You may choose to skip // email verification in order to improve UX, but should only do so if // the new user's email address matches an expected domain for the "team". if (!user.emailVerified) { res.redirect('/verify-email'); } else { // Start a session for the user. // ... res.redirect('/'); } }); ``` > The above example makes use of JIT-provisioning, which you can read more about in more our dedicated [JIT-provisioning guide](/sso/jit-provisioning). With the above checks in place, your application can safely sign in and verify users through SSO from any domain. ## Custom ACS domains While your users will authenticate with SSO using your application, they might briefly see the WorkOS [ACS URL](/glossary/acs-url). This can be configured in the production environment to a custom domain of your choosing. For more information see the [Custom Domains](/custom-domains) documentation. ### IdP Attributes Configure how identity provider attributes map to SSO Profiles and Directory Users. ## Introduction The [IdP Attributes page](https://dashboard.workos.com/environment/identity-provider-attributes) in the WorkOS Dashboard is where you configure which attributes are collected from identity providers (IdPs) and how they map to [SSO Profile](/reference/sso/profile) and [Directory User](/reference/directory-sync/directory-user) objects. WorkOS automatically normalizes a standard set of attributes from identity providers into SSO Profiles. More unique cases can be mapped by your customer's IT contact. In this guide, you'll learn how to configure standard, predefined, and custom attributes. > For Directory Sync-specific attribute details, see [User Attributes](/directory-sync/attributes). ## Definitions **Standard attributes** : The most common user information, normalized across providers. **Predefined attributes** : Detailed user attributes for specific use cases, normalized across providers. You can opt-in to each attribute you'd like IT contacts to map during SSO connection configuration. **Custom attributes** : For unique cases, you can create custom attributes your customers can map when setting up an SSO connection. ## Standard attributes Every SSO Profile comes with the following standard attributes. These are the core set of attributes that are common across all identity providers. These are structured fields with a guaranteed schema in the top-level SSO Profile payload. | Attribute | Type and description | Status | | ------------ | ---------------------------------------------------------------------------------------------------------------------- | ----------------- | | `idp_id` | The user's unique identifier, assigned by the identity provider. Different identity providers use different ID formats | Strictly required | | `email` | The user's email | Strictly required | | `first_name` | The user's first name | Configurable | | `last_name` | The user's last name | Configurable | | `name` | The user's full name | Configurable | `idp_id` and `email` are always required for SSO Profiles. The `first_name`, `last_name`, and `name` attributes can be configured per environment. By default, `first_name` and `last_name` are enabled and required, while `name` is disabled and optional. --- ## Custom attributes For more detailed user information, you can opt-in to additional predefined attributes and define your own custom attributes. These attributes will appear in the custom attributes field on [SSO Profile](/reference/sso/profile) objects and can be configured in the [WorkOS Dashboard](https://dashboard.workos.com/). > When using AuthKit, SSO Profile custom attributes are also available on the organization membership's `custom_attributes` field. See [JWT Templates](/authkit/jwt-templates) for how to include these in your access tokens. ### Predefined attributes When enabled, IT contacts will be asked to map these attributes during SSO configuration in [Admin Portal](/admin-portal). These fields are always optional if enabled. These fields are named and schematized by WorkOS – they cannot be renamed. | Attribute | Type and description | Status | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------- | | `addresses` | The user's list of address objects (`street_address`, `locality`, `region`, `postal_code`, `country`, `primary`, `raw_address`) | Optional | | `cost_center_name` | The user's cost center name | Optional | | `department_name` | The user's department name | Optional | | `division_name` | The user's division name | Optional | | `emails` | The user's list of email objects (`type`, `value`, `primary`) | Optional | | `employee_type` | The user's employment type | Optional | | `employment_start_date` | The user's start date | Optional | | `job_title` | The user's job title | Optional | | `manager_email` | The email address for the user's manager | Optional | | `username` | The user's username | Optional | #### Enable or disable a predefined attribute Predefined attributes can be enabled or disabled in the [WorkOS Dashboard](https://dashboard.workos.com/) on the Identity Provider Attributes page. ![WorkOS Dashboard UI showing editing predefined attributes](https://images.workoscdn.com/images/73b775ed-c3ef-4c81-bb56-7b040d3d073a.png?auto=format&fit=clip&q=50) > For SSO Profiles, making changes to IdP attributes will take effect upon next sign-in. ### Custom attributes Custom attributes can be utilized to enrich SSO Profiles with additional data from the identity provider. You can create attributes that appear as fields in the [Admin Portal](https://workos.com/admin-portal). Your customers can map these fields to the correct values in their system when setting up SSO with their identity provider. #### Create a custom attribute Custom attributes can be created in the [WorkOS Dashboard](https://dashboard.workos.com/) on the Identity Provider Attributes page. ![WorkOS Dashboard UI showing custom attribute creation](https://images.workoscdn.com/images/c1d00c4c-4dea-415e-a8f8-c870317410df.png?auto=format&fit=clip&q=50) > For SSO Profiles, making changes to IdP attributes will take effect upon next sign-in. #### Delete a custom attribute When a custom attribute is deleted, [SSO Profiles](/reference/sso/profile) will retain these existing attribute values until the next sign-in. #### Editing attribute mappings If attribute data for a particular SSO connection has changed and is no longer mapped properly, you or IT contacts can edit the attribute mappings via the [WorkOS Dashboard](https://dashboard.workos.com/) connection page or [Admin Portal](https://workos.com/admin-portal), respectively. ![WorkOS Dashboard UI showing editing attribute mappings for a connection](https://images.workoscdn.com/images/09395b6c-d037-440f-a17e-ef0507868532.png?auto=format&fit=clip&q=50) ### Custom attribute mapping in Admin Portal You can control the visibility of custom attribute mapping for Directory Sync and Single Sign-On flows in the Admin Portal at the environment and organization level. The environment-level setting is controlled on the Identity Provider Attributes page in the [WorkOS Dashboard](https://dashboard.workos.com/). ![WorkOS Dashboard UI showing editing custom attribute mapping in Admin Portal setting](https://images.workoscdn.com/images/23ee5439-6cbb-4c18-ac39-0870d63bfc0b.png?auto=format&fit=clip&q=50) Organization-level settings are controlled on an individual organization's Attributes tab in the [WorkOS Dashboard](https://dashboard.workos.com/). Organizations mirror the environment-level settings by default. ## Raw attributes \[Deprecated] The `raw_attributes` field on [SSO Profile](/reference/sso/profile) objects is deprecated and will **stop returning data on April 15, 2026**. [Custom attributes](/sso/attributes/custom-attributes/custom-attributes) are the recommended replacement. Define the attributes you need in the [WorkOS Dashboard](https://dashboard.workos.com/), and your customers' IT contacts can map them during SSO connection setup in the [Admin Portal](/admin-portal). Contact support [via email](mailto:support@workos.com) or Slack if you need help with the migration. We also have tooling to automate the WorkOS-side configuration on your behalf. For a full migration walkthrough covering Directory Sync, SSO, and AuthKit, see the [migration guide](/deprecations/raw-attributes). --- ## Frequently asked questions ### Which identity providers support mapping additional predefined and custom attributes? Additional predefined and custom attributes are supported for all SAML SSO connections. ### Can our customers add their own custom attributes outside of what is defined in the WorkOS Dashboard? We do not currently support this functionality. Custom attributes must be defined in the WorkOS Dashboard first. Please reach out to [support](mailto:support@workos.com) if you have a specific use case that you would like to discuss. ### What happens if an attribute cannot be mapped from the IdP? Attributes that cannot be mapped for a particular [SSO Profile](/reference/sso/profile) will result in a `null` value for the attribute. ### Sign-In UX User experience considerations for Single Sign-On. ## Introduction Now that we've seen how the Single Sign-On (SSO) APIs work, you may want to consider how to best integrate this new flow in the sign-in experience for your users. This guide will walk you through a few different approaches you could take in your application: - Separate SSO flow - Separate email and password fields - Auto-hide the password field Throughout this guide, let's consider the following scenario: - You are building an app called _Demo App_ - An organization named _Foo Corp_ is using Single Sign-On with Okta as the [IdP](/glossary/idp) ### Implementing SSO with WorkOS This document offers guidance on UX best practices when integrating SSO with the standalone API. You might instead consider [WorkOS AuthKit](/authkit), a complete authentication platform which handles all of the UX complexity for you. ## Separate SSO flow A basic approach would be to create a link or button on your login page with a **Sign in with SSO** or **Use Single Sign-On** option. This method differentiates the flows for the user explicitly. You may still look up the domain if they try to sign in with their corporate email and redirect them to the appropriate flow too—see the demo below as an example. As this adds yet another button, one thing to be mindful with this approach is the [NASCAR problem](https://indieweb.org/NASCAR_problem) where a cluster of 3rd party branded buttons creates both visual noise and confusion. Consider only offering a couple of options that are relevant to your user base. ## Separate email and password fields Instead of asking users for their email and password in one screen, you could first ask them for their email. This method gives you an opportunity to check if a particular domain is SSO-enabled and redirect the user to the appropriate SSO flow. It is a very popular approach employed by many applications (including WorkOS itself, Apple, and Google). ## Auto-hide the password field Finally, as an extension to the previous approach, you can automatically hide the password field if the user's domain is SSO-enabled. This feature is a bit more complicated to implement, but provides a more seamless experience for users. ### SSO Session Lifecycle Understanding SSO session statuses and their meaning. ## Introduction WorkOS creates a session to track each Single Sign-On (SSO) authentication flow. Sessions can originate from different sources depending on how the flow is initiated: - **Service Provider (SP)**: Your application initiates the flow by redirecting users to WorkOS. - **Identity Provider (IdP)**: The IdP initiates the flow, sending users directly to WorkOS. This applies only to SAML connections. OIDC connections are always SP-initiated. - **Admin Portal**: Test sessions are initiated through the WorkOS Admin Portal to verify SSO configuration. As the user interacts with the IdP and the authentication progresses, the session transitions through various statuses. Understanding these statuses helps you monitor authentication activity and troubleshoot issues in your SSO implementation. ## Session Statuses ### In progress A session is marked as when the authentication flow has been initiated but not yet completed. This status indicates that the user is currently interacting with the IdP or that the authorization code exchange is pending. Sessions in this state are waiting for one or more of the following: - The user to complete authentication at the IdP - The IdP to send a response back to WorkOS - Your application to exchange the authorization code for tokens ### Success A session is marked as when the entire authentication flow completes successfully. This means: - The IdP authenticated the user - WorkOS validated the IdP response - Your application exchanged the authorization code for tokens - User profile data was successfully retrieved ### Failed A session is marked as when the authentication flow encounters an error. Common causes include: - Invalid or expired certificates - Invalid or malformed IdP response - Profile attribute mapping misconfiguration - Profile attribute validation errors - CSRF token validation failure - User denied access at the IdP - IdP returned an authentication error When a session fails, you can view the error details in the WorkOS Dashboard to understand what went wrong. ### Timed out A session is marked as when it remains in the "In progress" state for too long without completing. By default, sessions time out after 5 minutes. Timeouts typically occur when: - The user abandons the authentication flow at the IdP - The user closes their browser before completing authentication - Network issues prevent the IdP response from reaching WorkOS ## Test Sessions When testing SSO connections through the Admin Portal, sessions are tracked with special test statuses: ### Test successful A test session is marked as when the IdP response is received and validated. This confirms that the SSO connection is properly configured and the IdP is sending valid responses. ### Test failed A test session is marked as when validation errors occur during the test. This helps identify configuration issues before rolling out SSO to your users. Test sessions are not subject to the standard timeout behavior, allowing you to take your time when verifying your SSO configuration. ## Tracking SSO sessions You can track SSO sessions in the WorkOS Dashboard by navigating to the Organization → Connection detail page and clicking on the "Sessions" tab. The Sessions section displays a list of sessions from up to 90 days back and can be filtered by session ID, profile email, status, origin, and timestamp. ![A screenshot showing the WorkOS Dashboard SSO screen and how to navigate to the "Sessions" tab.](https://images.workoscdn.com/images/b3f5bcb4-cc92-4753-a467-49e3eeff941f.png) Click on a session in the list to see session details, such as the request made to the IdP and the response. ![A screenshot showing the "Session Details" within the WorkOS Dashboard SSO screen.](https://images.workoscdn.com/images/b4c4e900-9fbb-43a0-96fb-d3ec3f453e87.png?auto=format&fit=clip&q=50) ## Monitoring SSO sessions with events You can monitor SSO sessions by subscribing to the `authentication.sso_*` events. Here's the list of events available: - `authentication.sso_started`: Emitted when a new SSO session is started. - `authentication.sso_succeeded`: Emitted when an SSO session is completed successfully. - `authentication.sso_failed`: Emitted when an SSO session fails. - `authentication.sso_timed_out`: Emitted when an SSO session times out. These events can be streamed to Datadog for observability and alerting. Check the [Stream events to Datadog](/events/observability/datadog) documentation for more details on how to stream events to Datadog and refer to the [events](/events/authentication) documentation for more details on each event and its payload. ## Sdks {#sdks} ### rust ## Installation ### ruby ## Installation ### python ## Installation ### php ## Installation ### node ## Installation ### laravel ## Installation ## Starter Kits Laravel provides official starter kits with WorkOS AuthKit integration built in: - [React Starter Kit](https://github.com/laravel/react-starter-kit/tree/workos) - [Vue Starter Kit](https://github.com/laravel/vue-starter-kit/tree/workos) - [Svelte Starter Kit](https://github.com/laravel/svelte-starter-kit/tree/workos) - [Livewire Starter Kit](https://github.com/laravel/livewire-starter-kit/tree/workos) ### java ## Installation ### go ## Installation ### elixir ## Installation ### dotnet ## Installation ### authkit-tanstack-start ## Installation ```bash npm install @workos-inc/authkit-tanstack-start ``` ## Usage The AuthKit TanStack Start SDK provides utilities for integrating AuthKit authentication into TanStack Start applications. Refer to the [AuthKit documentation](/authkit) for detailed usage instructions and examples. ### authkit-remix ## Installation ```bash npm install @workos-inc/authkit-remix ``` ## Usage The AuthKit Remix SDK provides utilities for integrating AuthKit authentication into Remix applications. Refer to the [AuthKit documentation](/authkit) for detailed usage instructions and examples. ### authkit-react ## Installation ```bash npm install @workos-inc/authkit-react ``` ## Usage The AuthKit React SDK provides React hooks and components for integrating AuthKit authentication into React applications. Refer to the [AuthKit documentation](/authkit) for detailed usage instructions and examples. ### authkit-react-router ## Installation ```bash npm install @workos-inc/authkit-react-router ``` ## Usage The AuthKit React Router SDK provides utilities for integrating AuthKit authentication into React Router 7+ applications. Refer to the [AuthKit documentation](/authkit) for detailed usage instructions and examples. ### authkit-nextjs ## Installation ```bash npm install @workos-inc/authkit-nextjs ``` ## Usage The AuthKit Next.js SDK provides server-side and client-side utilities for integrating AuthKit authentication into Next.js applications. Refer to the [AuthKit documentation](/authkit) for detailed usage instructions and examples. ### authkit-js ## Installation ```bash npm install @workos-inc/authkit-js ``` ## Usage The AuthKit JavaScript SDK provides a client-side library for integrating AuthKit authentication into vanilla JavaScript applications. Refer to the [AuthKit documentation](/authkit) for detailed usage instructions and examples. ### authkit-astro ## Installation ```bash npm install @workos/authkit-astro ``` ## Usage The AuthKit Astro SDK provides utilities for integrating AuthKit authentication into Astro applications. Refer to the [AuthKit documentation](/authkit) for detailed usage instructions and examples. ## API Reference {#reference} ### Getting started # Getting started The WorkOS API gives you everything you need to make your app enterprise-ready. Authenticate users, sync directories, enforce access controls, stream audit logs, and more -- all through a single integration. The API is organized around REST. It accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs. [Sign in](https://dashboard.workos.com/) to see code examples customized with your API keys and data. ```url title="API Base URL" https://api_workos_com ``` **Not a developer?** You can explore most of WorkOS without writing any code. The [WorkOS Dashboard](https://dashboard.workos.com/) lets you configure SSO connections, manage directories, set up audit log streams, and more -- all from a visual interface. ### WorkOS Connect # WorkOS Connect WorkOS Connect is a unified interface that simplifies authentication and authorization across customers, partners, and external SaaS tools. Read more about [how Connect integrates with AuthKit here](/authkit/connect). ### User information # User information Provides information about the [User](/reference/authkit/user) referenced by the access token's `sub` claim. Which claims are returned depends on the scopes originally granted when the access token was issued. This endpoint is authenticated by providing the previously acquired access token in the `Authorization` header. ### Token # Token This endpoint is called by WorkOS Connect Applications to get access tokens, ID tokens, and refresh tokens, depending on the `grant_type` provided when requested. This endpoint is authenticated by providing the WorkOS Application's client ID and client secret in the body of the request. There are four grant types available: - [Authorization code](/reference/workos-connect/token/authorization-code-grant) - [Refresh token](/reference/workos-connect/token/refresh-token-grant) - [Client credentials](/reference/workos-connect/token/client-credentials-grant) - [Device code](/reference/workos-connect/cli-auth/device-code-grant) Each is described in greater detail below. ### refresh-token-grant ### Refresh token grant Used by WorkOS Connect OAuth Applications to exchange a refresh token for new access tokens and/or ID tokens. The refresh token is provided when the initial `oauth2/authorize` request is made with the `offline_access` scope. The [access token](/reference/workos-connect/token/authorization-code-grant/access-token) and [ID tokens](/reference/workos-connect/token/authorization-code-grant/id-token) issued here are the same as those issued for the initial `authorization_code` grant. ### client-credentials-grant ### Client credentials grant Used by WorkOS Connect M2M Applications to exchange the app's credentials for access tokens. ### authorization-code-grant ### Authorization code grant Used by WorkOS Connect OAuth Applications to exchange an authorization code for access tokens, ID tokens, and refresh tokens. ### access-token #### Access token The access token for WorkOS Connect M2M Applications contains the following claims. ### id-token #### ID token The ID token, when requested with the `openid` scope, contains information about the user's identity, like name and email address. ### access-token #### Access token The access token for WorkOS Connect OAuth Applications contains the following claims. ### Standalone Connect # Standalone Connect Standalone Connect allows applications with existing authentication systems to use AuthKit as their OAuth authorization server. Instead of migrating your entire authentication stack, you can leverage WorkOS's OAuth infrastructure while keeping your existing user authentication as the source of truth. The Standalone Connect flow uses the following endpoints: | Endpoint | Host | Description | | --------------------------------------------------------------------------- | ------------------- | --------------------------------------- | | [`/oauth2/authorize`](/reference/workos-connect/authorize) | Your AuthKit domain | Initiates the OAuth flow | | [`/authkit/oauth2/complete`](/reference/workos-connect/standalone/complete) | `api.workos.com` | Completes external authentication | | [`/oauth2/token`](/reference/workos-connect/token/authorization-code-grant) | Your AuthKit domain | Exchanges authorization code for tokens | Read more in the [Standalone Connect guide](/authkit/connect/standalone). ### user-consent-options ## User Consent Options The `user_consent_options` can take an array of consent options that the user will be required to choose from on AuthKit's OAuth consent screen. The chosen option will then become available as a JWT claim on the issued access token. These options can be presented as either a flat or grouped set of options. ### complete ## Complete external authentication Completes an external authentication flow and returns control to AuthKit. This endpoint is used with [Standalone Connect](/authkit/connect/standalone) to bridge your existing authentication system with the Connect OAuth API infrastructure. After successfully authenticating a user in your application, calling this endpoint will: - Create or update the user in AuthKit, using the given `id` as its `external_id`. - Return a `redirect_uri` your application should redirect to in order for AuthKit to complete the flow Users are automatically created or updated based on the `id` and `email` provided. If a user with the same `id` exists, their information is updated. Otherwise, a new user is created. If you provide a new `id` with an `email` that already belongs to an existing user, the request will fail with an error as email addresses are unique to a user. ### Metadata # Metadata Connect exposes several metadata endpoints in order to be compatible with a wide array of clients that support discovery and automatic configuration. ### openid-configuration ### OpenID configuration This discovery endpoint provides the standard configuration for OpenID clients to interact with WorkOS Connect. ### oauth-authorization-server ### OAuth Authorization Server This endpoint provides [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749)-compatible OAuth Authorization Server metadata. Model Context Protocol (MCP) clients that support the latest version of the specification use this endpoint. [Read more here](/authkit/mcp) about how to use AuthKit as an authorization server for an MCP server. ### Token introspection # Token introspection Indicates whether the given token (access token or refresh token) is valid and active. Additionally, it provides details about the token. This endpoint is authenticated by provided the WorkOS Application's client ID and client secret in the body of the request. ### CLI Auth # CLI Auth CLI Auth for WorkOS Connect enables third-party applications to build command-line tools that integrate with your app's credentials using the [OAuth 2.0 Device Authorization Flow](https://datatracker.ietf.org/doc/html/rfc8628). The CLI Auth flow for Connect involves two main endpoints: 1. The **device authorization URL** initiates the flow by obtaining device codes, user codes, and verification URIs. 2. The **device access token URL** is where the device exchanges the device code for access and refresh tokens after the user authenticates. Read more about [CLI Auth here](/authkit/cli-auth/connect). ### device-code-grant ## Device code grant Exchanges a device code for access and refresh tokens as part of the device authorization flow for WorkOS Connect applications. This endpoint should be polled repeatedly until the user authorizes the request, declines it, or the device code expires. The returned tokens are similar to those provided by the [authorization code grant](/reference/workos-connect/token/authorization-code-grant). ### Authorize device # Authorize device Initiates the device authorization flow for WorkOS Connect applications. This endpoint implements the [OAuth 2.0 Device Authorization Flow](https://datatracker.ietf.org/doc/html/rfc8628) and is designed for CLI applications and other devices with limited input capabilities. This endpoint is used by third-party applications to authenticate users through WorkOS Connect. Users will be prompted to authorize the application's access to their data as part of the consent flow. ### Authorize # Authorize When authenticating a user for a WorkOS Connect application, this is the endpoint they should be redirected to. If they're not already logged in, the user will be redirected to the AuthKit login page. For a third-party application, AuthKit prompts the user to authorize access to the application the first time they use it, and again if the application requests new scopes or organization access. Existing consent skips the consent screen when requested scopes are the same as, or a subset of, scopes previously granted. ### Applications # Applications The Applications API allows you to programmatically manage Connect Applications and their associated client secrets. WorkOS Connect supports two types of applications: [OAuth](/reference/workos-connect/applications/oauth) and Machine-to-Machine [M2M](/reference/workos-connect/applications/m2m). ### update ## Update a Connect Application Update an existing Connect Application. For OAuth applications, you can update redirect URIs. For all applications, you can update the name, description, and scopes. ### oauth ## OAuth Applications [OAuth applications](/authkit/connect/oauth) are designed for web, mobile, desktop, and CLI applications where a user needs to authenticate. ### m2m ## Machine-to-Machine Applications [M2M applications](/authkit/connect/m2m) are designed for server-to-server authentication without user interaction. ### list ## List Connect Applications List all Connect Applications in the current environment with optional filtering. ### get ## Get a Connect Application Retrieve details for a specific Connect Application by ID or client ID. ### delete ## Delete a Connect Application Delete an existing Connect Application. ### create ## Create a Connect Application Create a new Connect Application. Supports both OAuth and Machine-to-Machine (M2M) application types. ### Client secrets # Client secrets Client secrets are used to authenticate Connect Applications when making requests to WorkOS APIs. When a client secret is first created, the response includes an additional `secret` field containing the plaintext secret. This is the only time the plaintext secret will be returned. ### list ## List Client Secrets List all client secrets associated with a Connect Application. The plaintext secret is never returned after creation. Only the secret hint is included. ### delete ## Delete a Client Secret Delete (revoke) an existing client secret. ### create ## Create a Client Secret Create a new client secret for a Connect Application. This is the only time the plaintext secret will be returned and must be stored securely. ### Widgets # Widgets Widgets are React components that provide complete functionality for common enterprise app workflows. ### get-token ## Generate a widget token Generate a widget token scoped to an organization and user with the specified scopes. ### Webhooks # Webhooks Webhook endpoints let WorkOS deliver event notifications directly to your application. Use these endpoints to create, list, and delete the webhook endpoints configured for your environment. For implementation guidance, including payload verification and local testing, see the [webhooks guide](/events/data-syncing/webhooks). ### update ## Update a Webhook Endpoint Update the properties of an existing webhook endpoint. ### list ## List Webhook Endpoints Get a list of all of your existing webhook endpoints. ### delete ## Delete a Webhook Endpoint Delete an existing webhook endpoint. ### create ## Create a Webhook Endpoint Create a new webhook endpoint to receive event notifications. ### Vault # Vault Vault provides centralized encryption and storage of sensitive data such as API keys, database credentials, or personally identifiable information (PII). All data is encrypted using keys automatically provisioned based on the provided context of the object. ### Encrypted object # Encrypted object Represents an encrypted object stored by Vault. ### versions ## List object versions Retrieve all versions for a specific object. ### Object version # Object version Represents a static version of an object stored by Vault. ### update ## Update an object Update the value of an existing encrypted object. ### metadata ## Describe an object Fetch metadata for an object without decrypting it. ### list ## List objects List all encrypted objects with cursor-based pagination. ### get ## Read an object by ID Fetch and decrypt an object by its unique identifier. ### get-by-name ## Read an object by name Fetch and decrypt an object by its unique name. ### delete ## Delete an object Delete an encrypted object. ### create ## Create an object Encrypt and store a new key-value object. ### Encryption key management # Encryption key management The key management APIs can be used to generate isolated encryption keys for local encryption and decryption operations. ### rekey-data-key ## Rekey a data key Re-encrypt an existing data key using the provided key context. Use this endpoint to migrate data keys from one key context to another without re-encrypting the underlying data. If the encrypted data key includes multiple key entries, Vault decrypts the data key with the first entry it can decrypt and re-encrypts it using the provided key context. ### encrypt-data ## Encrypt data Perform a local encryption option. A data key is generated based on the provided key context and used to encrypt the data. The operation happens locally and neither the plaintext nor encrypted data are sent over the network. ### decrypt-data ## Decrypt data Decrypt data that was previously encrypted with Vault. The data key in the ciphertext is decrypted using the Vault API and used to decrypt the remaining data. The decryption operations happen locally and neither the plaintext nor encrypted data are sent over the network. ### decrypt-data-key ## Decrypt a data key Decrypt a previously encrypted data key from WorkOS Vault. ### create-data-key ## Create a data key Generate a data key for local encryption based on the provided key context. The encrypted data key **MUST** be stored by the application, as it cannot be retrieved after generation. ### Testing the API # Testing the API You can test the API directly with cURL, or use the [Postman collection](https://www.postman.com/workos/workspace/workos-public/collection/25188762-79ce1172-4741-4f1d-a486-64380f9a599f?ctx=documentation) for convenience. > Check out the [guide](/postman) about the WorkOS API Postman collection to learn more about it. ### Single Sign-On # Single Sign-On The Single Sign-On API has been modeled to meet the [OAuth 2.0](/glossary/oauth-2-0) framework specification. As a result, authentication flows constructed using the Single Sign-On API replicate the OAuth 2.0 protocol flow. To automatically respond to changes in your SSO connections, use the [Connection events](/events/connection). ### json-web-key-set ## Get JWKS Returns the JSON Web Key Set (JWKS) containing the public keys used for verifying access tokens. ### Profile # Profile A Profile is an object that represents an authenticated user. The Profile object contains information relevant to a user in the form of normalized attributes. After receiving the Profile for an authenticated user, use the Profile object attributes to persist relevant data to your application's user model for the specific, authenticated user. To surface additional attributes on the Profile, refer to the [SSO custom attributes](/sso/attributes/custom-attributes) guide. ### get-user-profile ## Get a User Profile Exchange an access token for a user's [Profile](/reference/sso/profile). Because this profile is returned in the [Get a Profile and Token endpoint](/reference/sso/profile/get-profile-and-token) your application usually does not need to call this endpoint. It is available for any authentication flows that require an additional endpoint to retrieve a user's profile. ### get-profile-and-token ## Get a Profile and Token Get an access token along with the user [Profile](/reference/sso/profile) using the code passed to your [Redirect URI](/reference/sso/get-authorization-url/redirect-uri). ### Logout # Logout The Logout endpoints enable the RP-initiated logout functionality for users in your application. Refer to [Single Logout](/sso/single-logout/idp-initiated-logout) section for more details on how to handle RP-initiated or IdP-initiated logout. > Please note that the Logout feature is only available for Custom Open ID connections that provide > specific logout features. These features include the presence of the `revocation_endpoint` and `end_session_endpoint` > in the discovery document. ### redirect ## Logout Redirect Logout allows to sign out a user from your application by triggering the identity provider sign out flow. This `GET` endpoint should be a redirection, since the identity provider user will be identified in the browser session. Before redirecting to this endpoint, you need to generate a short-lived logout token using the [Logout Authorize](/reference/sso/logout/authorize) endpoint. ### authorize ## Logout Authorize You should call this endpoint from your server to generate a logout token which is required for the [Logout Redirect](/reference/sso/logout) endpoint. ### Get an authorization URL # Get an authorization URL Generates an OAuth 2.0 authorization URL to authenticate a user with SSO. You'll have to specify the user's connection, organization, or OAuth provider as a parameter. These connection selectors are mutually exclusive, and exactly one must be provided. The generated URL automatically directs the user to their identity provider. Once the user authenticates with their identity provider, WorkOS then issues a redirect to your redirect URI to complete the sign-in flow. ### redirect-uri ### Redirect URI In the [OAuth 2.0](/glossary/oauth-2-0) protocol, a redirect URI is the location that the user is redirected to once they have successfully authenticated with their identity provider. When redirecting the user, WorkOS will generate an authorization code and pass it to your redirect URI as a `code` query parameter, your app will use this code to [get the user's profile](/reference/sso/profile/get-profile-and-token). Additionally, WorkOS can pass a `state` parameter back to your application that you may use to encode arbitrary information to restore your application state between the redirects. ```url title="Redirect URI with query parameters" https://your-app.com/callback?code=01E2RJ4C05B52KKZ8FSRDAP23J&state=dj1kUXc0dzlXZ1hjUQ== ``` You'll need to configure the allowed redirect URIs for your application in the [Applications](https://dashboard.workos.com/environment/applications) section of the WorkOS Dashboard. Open your application and go to the **Redirects** tab. Without a valid redirect URI, your users will be unable to sign in. Make sure that the redirect URI you use as a parameter to get the authorization URL matches one of the redirect URIs configured for the application. Redirect URIs follow stricter requirements in production environments: - `HTTPS` protocol is required in production environments - `HTTP` and `localhost` are allowed in staging environments - The sole exception is the use of `http://127.0.0.1` in production environments to support native clients. #### Wildcards WorkOS supports using wildcard characters (`*`) in Redirect URIs to handle dynamic subdomains or variable ports during development. ##### Subdomains The `*` symbol can be used as a wildcard for subdomains; however, it must be used in accordance with the following rules: - The protocol of the URL **must not** be `http:` in production environments. - The wildcard **must** be located in the subdomain furthest from the root domain (e.g., `https://*.sub.example.com` will work, but `https://sub.*.example.com` will not). - The URL **must not** contain more than one wildcard. - A wildcard character **may** be prefixed and/or suffixed (e.g., `https://prefix-*-suffix.example.com`). - A wildcard **will not** match across multiple subdomain levels (e.g., `https://*.example.com` will not match `https://sub1.sub2.example.com`). - Wildcards cannot be used with [public suffix domains](https://publicsuffix.org) (e.g., `https://*.ngrok-free.app` will not work). - The wildcard will match letters, digits, hyphens, and underscores. - A URL with a wildcard cannot be set as the default redirect URI. ##### Ports To support [RFC 8252](https://datatracker.ietf.org/doc/html/rfc8252#section-7.3) ("OAuth 2.0 for Native Apps") and local development, a wildcard may be used in place of the port number. - This is strictly limited to `localhost` and loopback IP addresses (e.g., `127.0.0.1`). - Example: `http://localhost:*/auth/callback` is valid. ### error-codes ### Error codes If there is an issue generating an authorization URL, the API will return the original redirect URI with `error` and `error_description` query parameters. If provided, the `state` value will also be included. ```url title="Redirect URI with an error code" https://your-app.com/callback?error=organization_invalid&error_description=No%20connection%20associated%20with%20organization&state=123456789 ``` Possible error codes and the corresponding descriptions are listed below. | Error code | Description | | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `access_denied` | The identity provider denied the user's access to the client application, or the user declined the OAuth authorization request at the identity provider. | | `ambiguous_connection_selector` | A connection could not be uniquely identified using the provided connection selector (e.g., organization). This can occur when there are multiple SSO connections under the same organization. If you need multiple SSO connections for an organization, use the connection parameter to identify which connection to use for SSO. | | `connection_domain_invalid` | There is no connection for the provided domain. | | `connection_invalid` | There is no connection for the provided ID. | | `connection_strategy_invalid` | The provider has multiple strategies associated per environment. | | `connection_unlinked` | The connection associated with the request is unlinked. | | `domain_connection_selector_not_allowed` | This is a legacy error code that only applies if using the deprecated "domain" query parameter which is no longer valid for this endpoint. Use the "organization" or "connection" query parameters to target a connection instead. | | `idp_initiated_sso_disabled` | IdP-initiated SSO is disabled for the connection (see [Disable IdP-initiated SSO](/sso/login-flows/idp-initiated-sso/disable-idp-initiated-sso-beta)). | | `invalid_connection_selector` | A valid connection selector query parameter must be provided in order to correctly determine the proper connection to return an authorization URL for. Valid connection selectors are either `connection`, `organization`, or `provider`. | | `organization_invalid` | There is no organization matching the provided ID. | | `oauth_failed` | An OAuth authorization request failed for a user. | | `profile_not_allowed_outside_organization` | A profile was received that has an `email` that is outside the [organization's domain](/reference/domain-verification) and the organization does not allow this. To resolve this, add the missing domain to the organization's Domains. You can read about other options in the [SSO Domains guide](/sso/domains). | | `server_error` | The SSO authentication failed for the user. More detailed errors and steps to resolve are available in the Sessions tab on the connection page in the WorkOS Dashboard. | | `signin_consent_denied` | The user rejected the sign-in consent screen. This screen prompts the user to verify the email provided by the identity provider to confirm the legitimacy of the sign-in attempt. | ### Connection # Connection A connection represents the relationship between WorkOS and any collection of application users. This collection of application users may include personal or enterprise identity providers. As a layer of abstraction, a WorkOS connection rests between an application and its users, separating an application from the implementation details required by specific standards like [OAuth 2.0](/glossary/oauth-2-0) and [SAML](/glossary/saml). See the [events reference](/events/connection) documentation for the connection events. ### list ## List Connections Get a list of all of your existing connections matching the criteria specified. ### get ## Get a Connection Get the details of an existing connection. ### delete ## Delete a Connection Permanently deletes an existing connection. It cannot be undone. ### Roles # Roles The Authorization API provides endpoints for managing roles and permissions in your WorkOS environment. Use these endpoints to define access control structures that can be assigned to users, organization memberships, and more. ## Environment Roles Environment roles are defined at the environment level and apply to all organizations. They provide a consistent set of roles that can be used throughout your application. ## Custom Roles Custom roles are defined at the organization level and are specific to individual organizations. They allow organizations to create roles tailored to their needs. ### Environment role # Environment role An environment role is an access control resource defined at the environment level. Environment roles can be assigned to [organization memberships](/reference/authkit/organization-membership), [directory users](/directory-sync/identity-provider-role-assignment), and [SSO profiles](/sso/identity-provider-role-assignment). Environment roles provide a consistent set of roles across all organizations in your environment. Each role has a unique slug identifier. Roles can have permissions assigned to them. ### update ## Update an environment role Update an existing environment role. ### set-permissions ## Set permissions for an environment role Replace all permissions assigned to an environment role. This operation removes any existing permissions and assigns the provided permissions. To remove all permissions from a role, pass an empty array. ### list ## List environment roles List all environment roles in priority order. ### get ## Get an environment role Get an environment role by its slug. ### create ## Create an environment role Create a new environment role. The `slug` must be unique across all environment roles and can only contain lowercase letters, numbers, hyphens, and underscores. ### add-permission ## Add a permission to an environment role Add a single permission to an environment role. If the permission is already assigned to the role, this operation has no effect. ### Permission # Permission A permission represents an individual access right that can be assigned to roles. Permissions define what actions users with a given role can perform within your application. Permissions are defined at the environment level and can be assigned to both environment roles and custom roles. Each permission has a unique slug identifier that you use when assigning it to roles. ### update ## Update a permission Update an existing permission. Only the fields provided in the request body will be updated. ### list ## List permissions Get a list of all permissions in your WorkOS environment. ### get ## Get a permission Retrieve a permission by its unique slug. ### delete ## Delete a permission Delete an existing permission. System permissions cannot be deleted. ### create ## Create a permission Create a new permission in your WorkOS environment. The permission can then be assigned to environment roles and custom roles. The `slug` must be unique within the environment and must be lowercase, containing only letters, numbers, hyphens, underscores, colons, periods, and asterisks. ### Custom role # Custom role A custom role is an access control resource defined at the organization level. Custom roles allow individual organizations to create roles tailored to their specific needs, in addition to the environment roles that apply across all organizations. Like environment roles, custom roles can be assigned to [organization memberships](/reference/authkit/organization-membership), [directory users](/directory-sync/identity-provider-role-assignment), and [SSO profiles](/sso/identity-provider-role-assignment). Each custom role has a unique slug identifier within the organization and can have permissions assigned to it. ### update ## Update a custom role Update an existing custom role. Only the fields provided in the request body will be updated. ### set-permissions ## Set permissions for a custom role Replace all permissions assigned to a custom role. This operation removes any existing permissions and assigns the provided permissions. To remove all permissions from a role, pass an empty array. ### remove-permission ## Remove a permission from a custom role Remove a single permission from a custom role by its slug. ### list ## List custom roles Get a list of all roles that apply to an organization. This includes both environment roles and custom roles, returned in priority order. ### get ## Get a custom role Retrieve a role that applies to an organization by its slug. This can return either an environment role or a custom role. ### delete ## Delete a custom role Delete an existing custom role. The role must not have any active assignments or [IdP group role mappings](/rbac/idp-role-assignment). If the role has active assignments, you will receive a `409 Conflict` error with code `role_has_assignments`. If the role has group role mappings, you will receive a `409 Conflict` error with code `role_has_group_role_mappings`. ### create ## Create a custom role Create a new custom role. The role will be specific to the organization and can be assigned to organization memberships. The `slug` must be unique within the organization, begin with `org-`, and contain only lowercase letters, numbers, hyphens, and underscores. ### add-permission ## Add a permission to a custom role Add a single permission to a custom role. If the permission is already assigned to the role, this operation has no effect. ### Rate limits # Rate limits WorkOS APIs are rate limited to ensure that they are fast for everyone. If you find yourself getting 429 errors, double check your integration to make sure you aren't making unnecessary requests. ## General | Name | Path | Limit | | ------------ | ---- | -------------------------------------------- | | All requests | \* | 6,000 requests per 60 seconds per IP address | This rate limits applies to all environments, staging and production. Exceptions to the general rate limit are listed below. ## Single Sign-On | Name | Path | Limit | | ------------------------------------------------------------- | -------------- | -------------------------------------------- | | [Get Authorization URL](/reference/sso/get-authorization-url) | /sso/authorize | 1,000 requests per 60 seconds per connection | ## Directory Sync | Name | Path | Limit | | ----------------------------------------------------------- | ---------------- | ----------------------------------- | | [Directory Users](/reference/directory-sync/directory-user) | /directory\_users | 4 requests per second per directory | ## Organizations | Name | Path | Limit | | ----------------------------------------------------- | ----------------- | -------------------------------------- | | [Delete Organization](/reference/organization/delete) | /organizations/\* | 50 requests per 60 seconds per API key | ## AuthKit Rate limiting for AuthKit APIs are enforced on a per environment basis. | Name | Path | Limit | | ----------------------------------------------------------- | -------------------------------------------- | ---------------------------------------------------- | | Reads | /user\_management/\* | 1,000 requests per 10 seconds | | Writes | /user\_management/\* | 500 requests per 10 seconds | | [Authentication](/reference/authkit/authentication) | /user\_management/authenticate | 10 requests per 60 seconds per email or challenge ID | | [Magic Auth](/reference/authkit/magic-auth) | /user\_management/magic\_auth/send | 3 requests per 60 seconds per email | | [Email verification](/reference/authkit/email-verification) | /user\_management/:id/email\_verification/send | 3 requests per 60 seconds per user | | [Password reset](/reference/authkit/password-reset) | /user\_management/password\_reset/send | 3 requests per 60 seconds per email | ## Hosted AuthKit | Name | Limits | | ------------------------ | ---------------------------------------------------------- | | Reads | 1,000 requests per 10 seconds | | Writes | 500 requests per 10 seconds | | SSO sign-ins | 3 requests per 60 seconds per IP address | | Email sign-ins | 10 requests per 60 seconds per email and IP address | | Magic Auth sign-ins | 10 requests per 60 seconds per IP address and challenge ID | | Magic Auth code requests | 3 requests per 60 seconds per IP address and email | ### Radar # Radar Radar allows you to detect, verify, and block harmful behavior in real time. The Radar API supports the management of WorkOS Radar block and allow lists as well as standalone Radar use-cases. While Radar is natively integrated with AuthKit, you can also leverage Radar's risk decisioning engine outside of AuthKit to detect fraudulent sign-in and signup attempts in your own custom authentication flows using the [attempts API](/reference/radar/attempts). The Radar standalone API is currently in preview, [contact us](mailto:support@workos.com) to request access. ### Radar lists # Radar lists Radar supports explicitly blocking and allowing attempts based on attempt attributes. You can manage these lists via the Radar list management APIs ### update ## Add an entry to a Radar list Add an entry to a Radar list. ### delete ## Remove an entry from a Radar list Remove an entry from a Radar list. ### Attempts # Attempts A Radar attempt represents a sign-in or signup attempt and includes context such as IP address and user agent. The Radar engine assesses attempts for risk and returns a decision that you can use to drive behavior in your application. ### update ## Update a Radar attempt You may optionally inform Radar that an authentication attempt or challenge was successful using this endpoint. Some Radar controls depend on tracking recent successful attempts, such as impossible travel. ### create ## Create an attempt Assess a request for risk using the Radar engine and receive a verdict. ### Pipes # Pipes Pipes provides OAuth integrations with third-party providers that allow your users to securely connect their accounts to your application. Pipes handles the complete OAuth lifecycle including token refresh and credential storage. Read more in the [Pipes guide](/pipes). ### Provider # Provider A provider represents a third-party service that users can connect to through Pipes. Providers are configured in the WorkOS Dashboard and define the OAuth scopes and credentials used during the authorization flow. When listed for a specific user, each provider includes a `connected_account` field showing the user's connection status. ### list ## List providers for a user Retrieves a list of available providers and the user's connection status for each. Returns all providers configured for your environment, along with the user's [connected account](/reference/pipes/connected-account) information where applicable. ### list-for-organization ## List providers for an organization Returns a list of all providers available to the specified organization, along with any configured custom OAuth scopes, enabled state, and organization-managed credentials where applicable. ### configure ## Configure a provider for an organization Creates or updates an organization's provider configuration. Use this endpoint to enable or disable a provider, set custom OAuth scopes, or supply organization-managed OAuth credentials. ### Data integration # Data integration A data integration represents a configured connection to a third-party [provider](/reference/pipes/provider) through Pipes. Data integrations define the OAuth credentials, scopes, and settings used when users connect their accounts. For built-in providers, create a data integration by referencing the provider's slug. For custom providers, supply a `custom_provider` definition with the OAuth endpoints and configuration. ## Endpoints - [Create a data integration](/reference/pipes/data-integration/create) - [List data integrations](/reference/pipes/data-integration/list) - [Get a data integration](/reference/pipes/data-integration/get) - [Update a data integration](/reference/pipes/data-integration/update) - [Delete a data integration](/reference/pipes/data-integration/delete) ### update ## Update a data integration Updates a [data integration](/reference/pipes/data-integration) by its provider slug. Only the fields you include in the request body are updated; omitted fields are left unchanged. When `credentials` is provided, the stored client secret is rotated to the new value. The `custom_provider` block is only valid for custom-provider integrations. ### Error responses - **404 Not Found**: No data integration exists for the given slug. - **422**: Invalid credentials configuration or `custom_provider` supplied for a built-in provider integration. ### list ## List data integrations Lists the environment's data integrations configured with `custom` or `organization` credentials, including custom providers. ### get ## Get a data integration Retrieves a data integration by its slug. ### Error responses - **404 Not Found**: No data integration exists for the given slug, or the integration uses unsupported credentials. ### delete ## Delete a data integration Deletes a [data integration](/reference/pipes/data-integration) by its provider slug. Returns `204 No Content` on success. This operation is idempotent — deleting a non-existent integration returns a successful response. Deleting a data integration also removes all associated connected accounts. ### create ## Create a data integration Creates a [data integration](/reference/pipes/data-integration) for a provider. Set `credentials.type` to `custom` to use your own OAuth app credentials, or `organization` to have each organization supply its own. For a built-in provider, pass its slug as `provider`. For a custom provider, pass a new slug plus a `custom_provider` definition. ### Error responses - **404 Not Found**: The provider slug does not match a built-in provider (and no `custom_provider` was supplied). - **422**: Invalid credentials configuration (e.g., missing `client_id`/`client_secret` for `custom` type, or supplying them for `organization` type). ### Connected account # Connected account A connected account represents a user's authorized connection to a third-party [provider](/reference/pipes/provider) through Pipes. Connected accounts store the OAuth credentials and scopes granted during the authorization flow. When listing providers for a user, each provider includes a nested `connected_account` showing the user's connection status. ### upsert-api-key ## Upsert an API key for a connected account Creates or updates an API-key-based installation for the specified integration and user. If an installation already exists, the stored API key is rotated to the new value. ### update ## Update a connected account Updates a user's [connected account](/reference/pipes/connected-account) tokens, scopes, or state for a specific provider. ### Error responses - **404 Not Found**: No connected account exists for the given user and slug. ### get ## Get a connected account Retrieves a user's [connected account](/reference/pipes/connected-account) for a specific provider. ### get-authorize-url ## Get authorization URL Generates an OAuth authorization URL to initiate the connection flow for a user. Redirect the user to the returned URL to begin the OAuth flow with the third-party provider. ### delete ## Delete a connected account Disconnects WorkOS's account for the user, including removing any stored access and refresh tokens. The user will need to reauthorize if they want to reconnect. This does not revoke access on the provider side. The user may need to disconnect the application directly from the provider's settings. Returns a `204 No Content` response on success. ### create ## Create a connected account Imports a [connected account](/reference/pipes/connected-account) for a user by directly providing OAuth tokens. This is useful for migrating existing connections from another system. The `state` field is derived from the token combination when not explicitly set. If no tokens are provided, the state defaults to `needs_reauthorization`. ### Token validation When creating a connected account, the following token combination rules apply: - No tokens provided → `state` is set to `needs_reauthorization`. - `access_token` with `expires_at` and `refresh_token` → valid, `state` is `connected`. - `access_token` only (no `expires_at`) → valid, `state` is `connected`. - `access_token` with `expires_at` but no `refresh_token` → rejected (`422`). - `refresh_token` only (no `access_token`) → valid, `expires_at` is set to now. - `expires_at` only (no `access_token`) → rejected (`422`). ### Error responses - **409 Conflict**: A connected account already exists for this user, integration, and organization. - **422**: Invalid token combination or the data integration is not in a valid state. ### Credentials # Credentials Credentials allow you to make API calls to a connected third-party service on behalf of a user. For OAuth integrations, WorkOS handles token refresh automatically, so you always receive a valid, non-expired token. For API-key integrations, WorkOS returns the stored secret. ### vend-credentials ## Vend credentials for a connected account Returns credentials for a user's connected account. Branches on the installation's `auth_method`: OAuth installations return an access token (refreshed if needed); API-key installations return the stored secret. ### get ## Get an access token for a connected account Fetches a valid OAuth access token for a user's connected account. WorkOS automatically handles token refresh, ensuring you always receive a valid, non-expired token. ### Pagination # Pagination Many top-level resources have support for bulk fetches via list API methods. For instance, you can [list connections](/reference/sso/connection/list), [list directory users](/reference/directory-sync/directory-user/list), and [list directory groups](/reference/directory-sync/directory-group/list). These list API methods share a common structure, taking at least these four parameters: `limit`, `order`, `after`, and `before`. WorkOS utilizes pagination via the `after` and `before` parameters. Both parameters take an existing object ID value and return objects in either descending or ascending order by creation time. ### Organization # Organization An Organization is a top-level resource in WorkOS. Each Connection, Directory, and Audit Trail Event belongs to an Organization. An Organization will usually represent one of your customers. There is no limit to the number of organizations you can create in WorkOS. ### update ## Update an Organization Updates an organization in the current environment. You can include one or more domains to associate with the organization, but you should [verify the ownership](/authkit/domain-verification) of every domain before setting its state to `verified`. ### list ## List Organizations Get a list of all of your existing organizations matching the criteria specified. ### get ## Get an Organization Get the details of an existing organization. ### get-by-external-id ## Get an Organization by External ID Get the details of an existing organization by an [external identifier](/authkit/metadata/external-identifiers). ### delete ## Delete an Organization Permanently deletes an organization in the current environment. It cannot be undone. ### create ## Create an Organization Creates a new organization in the current environment. You can include one or more domains to associate with the organization, but you should [verify the ownership](/authkit/domain-verification) of every domain before setting its state to `verified`. ### Multi-Factor Authentication # Multi-Factor Authentication The multi-factor authentication (MFA) API can be used to add additional factors of authentication to existing authentication strategies. The API currently supports both time-based one-time passwords (TOTP) and SMS factors. ### Authentication Factor # Authentication Factor An object representing an Authentication Factor. ### get ## Get Factor Gets an Authentication Factor. ### enroll ## Enroll Factor Enrolls an Authentication Factor to be used as an additional factor of authentication. The returned ID should be used to create an authentication Challenge. ### delete ## Delete Factor Permanently deletes an Authentication Factor. It cannot be undone. ### Authentication Challenge # Authentication Challenge An object representing a Challenge of an Authentication Factor. ### verify ## Verify Challenge Verifies an Authentication Challenge. ### create ## Challenge Factor Creates a Challenge for an Authentication Factor. ### Magic Link # Magic Link The Magic Link API can be used to add Passwordless Authentication to your app. ### Passwordless session [Deprecated] # Passwordless session \[Deprecated] An object representing a passwordless authentication session. ### send-email ## Email a Magic Link \[Deprecated] Email a user the Magic Link confirmation URL. ### create ## Create Passwordless Session \[Deprecated] Create a Passwordless Session for a Magic Link Connection. ### Group # Group A Group is a collection of [Organization Memberships](/reference/authkit/organization-membership) within an [Organization](/reference/organization). Use Groups to organize users into organizational units. To list the groups that a specific Organization Membership belongs to, use [List Groups](/reference/authkit/organization-membership/list-groups). ### update ## Update a group Update an existing group. Only the fields provided in the request body will be updated. ### remove-member ## Remove a member from a Group Remove an organization membership from a group. ### list ## List groups Get a paginated list of groups within an organization. ### list-members ## List Group members Get a list of organization memberships in a group. ### get ## Get a group Retrieve a group by its ID within an organization. ### delete ## Delete a group Delete a group from an organization. ### create ## Create a group Create a new group within an organization. ### add-member ## Add a member to a Group Add an organization membership to a group. ### GroupRoleAssignment # GroupRoleAssignment A group role assignment connects a [Group](/reference/groups) to a [role](/reference/roles). When a role is assigned to a group, all members of that group gain the permissions included in that role. As organization memberships are added to or removed from the group, the role and its permissions automatically propagate to the current members. Group role assignments can also be scoped to a specific resource for [Fine-Grained Authorization](/reference/fga). When a resource is specified, members of the group receive the role's permissions on that resource and its descendants via [permission inheritance](/fga/roles-and-permissions). ### replace-group-role-assignments ## Replace all role assignments for a group Replace all role assignments for a group with the provided list. Existing assignments not in the list will be removed. ### remove-group-role-assignments ## Remove group role assignments by criteria Remove role assignments from a group that match the provided criteria. Returns 404 when no matching active assignment is found. ### remove-group-role-assignment ## Remove a group role assignment Remove a specific role assignment from a group by its ID. ### list ## List role assignments for a group List all role assignments granted to a group. Each assignment represents a role granted to the group on a resource. ### get ## Get a group role assignment Get a specific role assignment for a group by its ID. ### create ## Assign a role to a group Assign a role to a group on a specific resource. ### FGA (Fine-Grained Authorization) # FGA (Fine-Grained Authorization) The FGA API provides endpoints for managing fine-grained authorization in your WorkOS environment. Use these endpoints to create resources, assign roles, and check access permissions for your users. ## Resources Resources are instances of resource types that represent entities in your application—workspaces, projects, apps, or any other object that users can access. Resources form a hierarchy where permissions can be inherited from parent to child. ## Role Assignments Role assignments connect organization memberships to roles on specific resources. When a role is assigned to a user on a resource, they gain all permissions included in that role on that resource and its descendants. ## Access Checks Access check endpoints let you determine whether a user has a specific permission on a resource. You can also discover which resources a user can access, or which users have access to a specific resource. ### Role assignment # Role assignment A role assignment connects an organization membership to a role on a specific resource. When a role is assigned, the user gains all permissions included in that role on the resource and its descendants through permission inheritance. ### list ## List role assignments List all role assignments for an organization membership. This returns all roles that have been assigned to the user on resources, including organization-level and sub-resource roles. ### list-for-resource ## List role assignments for a resource List all role assignments granted on a specific resource instance. Each assignment includes the organization membership it was granted to. ### list-for-resource-by-external-id ## List role assignments for a resource by external ID List all role assignments granted on a resource, identified by its external ID. Each assignment includes the organization membership it was granted to. ### delete ## Remove a role assignment Remove a role assignment by specifying the role slug and resource. Access is revoked immediately. Removing an assignment also removes any permissions that were inherited by child resources through that assignment. You must provide either `resource_id` or both `resource_external_id` and `resource_type_slug` to identify the resource. ### delete-by-id ## Remove a role assignment by ID Remove a role assignment using its ID. Access is revoked immediately. Removing an assignment also removes any permissions that were inherited by child resources through that assignment. ### create ## Assign a role Assign a role to an organization membership on a specific resource. The user will immediately gain all permissions included in that role on the resource and its descendants. You must provide either `resource_id` or both `resource_external_id` and `resource_type_slug` to identify the resource. ### Resource # Resource A resource is an instance of a [resource type](/fga/resource-types) that represents an entity in your application. Resources can be workspaces, projects, apps, or any other object that users can access. Resources are organized in a hierarchy. When a role is assigned to a user on a parent resource, they automatically gain access to child resources through permission inheritance. ### update ## Update a resource Update an existing authorization resource. ### update-by-external-id ## Update a resource by external ID Update an existing authorization resource using its external ID. ### list ## List resources Get a paginated list of authorization resources. ### get ## Get a resource Retrieve the details of an authorization resource by its ID. ### get-by-external-id ## Get a resource by external ID Retrieve the details of an authorization resource by its external ID, organization, and resource type. This is useful when you only have the external ID from your system and need to fetch the full resource details. ### delete ## Delete a resource Delete an authorization resource. By default, this will fail if the resource has child resources or role assignments. Set `cascade_delete` to `true` to delete the resource along with all its descendants and role assignments. ### delete-by-external-id ## Delete a resource by external ID Delete an authorization resource using its external ID. By default, this will fail if the resource has child resources or role assignments. Set `cascade_delete` to `true` to delete the resource along with all its descendants and role assignments. ### create ## Create a resource Create a new authorization resource. The resource is associated with an organization and resource type. You can optionally specify a parent resource to place it in a hierarchy. The parent can be identified either by `parent_resource_id` or by the combination of `parent_resource_external_id` and `parent_resource_type_slug`. ### Access checks # Access checks Access check endpoints help you answer authorization questions: "Can this user perform this action on this resource?" and "What resources can this user access?" ### list-resources ## List resources for an organization membership Returns all child resources of a parent resource where the organization membership has a specific permission. This is useful for resource discovery—answering "What projects can this user access in this workspace?" You must provide either `parent_resource_id` or both `parent_resource_external_id` and `parent_resource_type_slug` to identify the parent resource. ### list-memberships ## List memberships for a resource Returns all organization memberships that have a specific permission on a resource. This is useful for answering "Who can access this resource?" You can filter by assignment type to distinguish between direct assignments (role assigned directly on the resource) and indirect assignments (permission inherited from a parent resource). ### list-memberships-by-external-id ## List memberships for a resource by external ID Returns all organization memberships that have a specific permission on a resource, using the resource's external ID. This is useful for answering "Who can access this resource?" when you only have the external ID. ### list-effective-permissions ## List effective permissions for an organization membership on a resource Returns all permissions the organization membership effectively has on a resource, including permissions inherited through roles assigned to ancestor resources. ### list-effective-permissions-by-external-id ## List effective permissions for an organization membership on a resource by external ID Returns all permissions the organization membership effectively has on a resource identified by its external ID, including permissions inherited through roles assigned to ancestor resources. ### check ## Check authorization Check if an organization membership has a specific permission on a resource. This endpoint considers all sources of access: - Direct role assignments on the resource - Inherited permissions from parent resources - Organization-scoped roles You must provide either `resource_id` or both `resource_external_id` and `resource_type_slug` to identify the resource. ### Feature Flags # Feature Flags Feature flags allow you to control feature availability for organizations in your application. Flags can either be enabled for individual organizations or all organizations in an environment. Read more about [how feature flags integrate with AuthKit here.](/feature-flags) ### Targeting # Targeting Targeting allows you to enable Feature Flags for specific users or organizations. When a flag is enabled for a target, that target will receive the flag's enabled value instead of the default value. ### remove ## Remove a feature flag target Removes a target from the feature flag's target list in the current environment. Currently, supported targets include users and organizations. ### list-for-user ## List enabled feature flags for a user Get a list of all enabled feature flags for the provided user. This includes feature flags enabled specifically for the user as well as any organizations that the user is a member of. ### list-for-organization ## List enabled feature flags for an organization Get a list of all enabled feature flags for an organization. ### add ## Add a feature flag target Enables a feature flag for a specific target in the current environment. Currently, supported targets include users and organizations. ### Feature Flag # Feature Flag A Feature Flag controls feature availability for organizations and users in your application. ### list ## List feature flags Get a list of all of your existing feature flags matching the criteria specified. ### get ## Get a feature flag Get the details of an existing feature flag by its slug. ### enable ## Enable a feature flag Enables a feature flag in the current environment. ### disable ## Disable a feature flag Disables a feature flag in the current environment. ### Events # Events Events represent activity that has occurred within WorkOS or within third-party identity and directory providers. They are used to keep your app in sync with WorkOS data. For more details on consuming events in your app, check out the [data syncing](/events/data-syncing) guide. Refer to the [Events](/events) page for a full list of events that WorkOS emits. ### list ## List events List events for the current environment. ### Errors # Errors WorkOS uses standard HTTP response codes to indicate the success or failure of your API requests. 200 : Successful request. 400 : The request was not acceptable. Check that the parameters were correct. 401 : The API key used was invalid. 403 : The API key used did not have the correct permissions. 404 : The resource was not found. 422 : Validation failed for the request. Check that the parameters were correct. 429 : Too many requests. Refer to the [Rate Limits](/reference/rate-limits) section. 5xx : Indicates an error with WorkOS servers. ### Organization domain # Organization domain An organization domain represents an [organization](/reference/organization)'s domain. Domains can be verified to assert that an organization owns the configured domain which is accomplished through DNS TXT record verification. Organization domains can be verified manually through the Dashboard, or by setting `state: 'verified'` when adding domains via the [Organization create](/reference/organization/create) or [update](/reference/organization/update) APIs. Domains can also be verified through [a self-serve flow](/domain-verification) via the Admin Portal. The organization that defines this domain policy exerts authentication policy control over that domain across your application. For this reason, it is important to verify ownership of manually added domains. Additionally, WorkOS does not allow addition of common consumer domains, like `gmail.com`. To automatically respond to changes in the organization domains, use [organization domain events](/events/organization-domain). ### verify ## Verify an Organization Domain Initiates verification process for an Organization Domain. ### get ## Get an Organization Domain Get the details of an existing organization domain. ### delete ## Delete an Organization Domain Permanently deletes an organization domain. It cannot be undone. ### create ## Create an Organization Domain Creates a new Organization Domain. ### Directory Sync # Directory Sync Directory Sync allows you to connect with directory providers to inform your application of any changes in their users, groups, or access rules. Using Directory Sync, one integration grants your application the ability to support multiple directory providers. Get real-time updates of any changes to the organization's access rules, groups, and users by integrating webhooks into your application. To automatically respond to changes in the connected directories and their users and groups, use the [Directory Sync events](/events/directory-sync). ### Directory user # Directory user A directory user represents an active organization user. Developers can receive [Webhooks](/events/directory-sync) as employees are added, updated or removed, allowing for provisioning and de-provisioning Users within an application. ### list ## List Directory Users Get a list of all of existing Directory Users matching the criteria specified. ### list-by-group ## List directory users by group Get a list of directory users that belong to a specific directory group. The response is bounded by the size of the requested group, which keeps payloads predictable. Starting May 1, 2026, the `groups` field on each returned user is empty by default for newly created teams — the caller already knows which group is being filtered. To fetch a user's complete group memberships, use the [List Directory Groups](/reference/directory-sync/directory-group/list) endpoint with a `user` filter. ### get ## Get a Directory User Get the details of an existing Directory User. ### Directory group # Directory group A directory group represents an organizational unit of users in a directory provider. ### list ## List Directory Groups Get a list of all of existing directory groups matching the criteria specified. ### get ## Get a Directory Group Get the details of an existing Directory Group. ### Directory # Directory A directory stores information about an organization's employee management system. Synchronizing with a directory enables you to receive changes to an organization's [user](/reference/directory-sync/directory-user) and [group](/reference/directory-sync/directory-group) structure. Directory providers vary in implementation details and may require different sets of fields for integration, such as API keys, subdomains, endpoints, usernames, etc. Where available, the WorkOS API will provide these fields when fetching directory records. ### list ## List Directories Get a list of all of your existing directories matching the criteria specified. ### get ## Get a Directory Get the details of an existing directory. ### delete ## Delete a Directory Permanently deletes an existing directory. It cannot be undone. ### Client libraries # Client libraries WorkOS offers native SDKs in several popular programming languages. Choose one language below to see our API Reference in your application's language. ### issue ## Generate a Client API token Generate a short-lived, session-bound token for the Client GraphQL API, scoped to an organization and user. ### AuthKit # AuthKit AuthKit is a user management platform that provides a set of user authentication and organization security features designed to provide a fast, scalable integration while handling all of the user management complexity that comes with advanced B2B customer needs. To automatically respond to AuthKit activities, like authentication and changes related to the users, use the corresponding [events](/events). ### update-user-data-installation ## Update a connected account Updates a user's [connected account](/reference/pipes/connected-account) tokens, scopes, or state for a specific provider. ### send-radar-sms-challenge ## Send a Radar SMS challenge Sends a one-time verification code over SMS to a user as part of a Radar challenge. Use the returned `verification_id` to authenticate the user with the `urn:workos:oauth:grant-type:radar-sms-challenge:code` grant type. ### list-redirect-uri ## List redirect URIs Lists the redirect URIs for an environment. ### list-cors-origin ## List CORS origins Lists the CORS origins for the current environment. ### create ## Create a redirect URI Creates a new redirect URI for an application. ### create-user-data-installation ## Import a connected account Imports a [connected account](/reference/pipes/connected-account) for a user by providing OAuth tokens directly. Use this to migrate existing connections or set up connections without going through the OAuth flow. ### create-cors-origin ## Create a CORS origin Creates a new CORS origin for the current environment. CORS origins allow browser-based applications to make requests to the WorkOS API. ### User # User Represents a user identity in your application. A user can sign up in your application directly with a method like password, or they can be [JIT-provisioned](/authkit/jit-provisioning) through an organization's SSO connection. Users may belong to [organizations](/reference/organization) as members. See the [events reference](/events/user) documentation for the user events. ### update ## Update a user Updates properties of a user. The omitted properties will be left unchanged. ### send-verification-email ## Send verification email Sends an email that contains a one-time code used to verify a user's email address. ### send-email-change ## Send email change code Sends an email that contains a one-time code used to change a user's email address. ### list ## List users Get a list of all of your existing users matching the criteria specified. ### get ## Get a user Get the details of an existing user. ### get-by-external-id ## Get a user by external ID Get the details of an existing user by an [external identifier](/authkit/metadata/external-identifiers). ### email-verification ## Verify email Verifies an email address using the one-time code received by the user. ### delete ## Delete a user Permanently deletes a user in the current environment. It cannot be undone. ### create ## Create a user Create a new user in the current environment. ### confirm-email-change ## Confirm email change Confirms an email change using the one-time code received by the user. ### list ## List authorized applications Get a list of all Connect applications that the user has authorized. ### delete ## Delete an authorized application Delete an existing Authorized Connect Application. ### Session tokens # Session tokens ### refresh-token ## Refresh token The refresh token can be used to obtain a new access token using the [authenticate with refresh token ](/reference/authkit/authentication/refresh-token) endpoint. Refresh tokens may only be used once. Refreshes will succeed as long as the user's session is still active. ### jwks ## JWKS URL This hosts the public key that is used for verifying access tokens. ### access-token ## Access token The access token that is returned in successful authentication responses is a JWT that can be used to verify that a user has an active session. The JWT is signed by a JWKS which can be retrieved from the [WorkOS API](/reference/authkit/session-tokens/jwks). ### Session helpers # Session helpers After authenticating and [storing the encrypted session as a cookie](/authkit/vanilla/nodejs/3-handle-the-user-session/save-the-encrypted-session), retrieving and decrypting the session is made easy via the session helper methods. ### refresh ## Refresh Refreshes the user's session with the refresh token. Passing in a new organization ID will switch the user to that organization. ### load-sealed-session ## Load sealed session Load the session by providing the sealed session and the cookie password. ### get-logout-url ## Get log out URL End a user's session. The user's browser should be redirected to this URL. Functionally similar to [Get logout URL](/reference/authkit/logout/get-logout-url) but extracts the session ID automatically from the session data. ### authenticate ## Authenticate Unseals the session data and checks if the session is still valid. ### Session # Session Represents an authenticated user's connection to your application. A session is created when a user signs in through AuthKit and contains information about the authentication method, device details, and session status. ### revoke ## Revoke Session Revoke a [user session](/reference/authkit/session). ### list ## List sessions Get a list of all active sessions for a specific user. ### Password reset # Password reset Create a password reset token for a user and reset the user's password. > When a user's password is reset, all of their active sessions are revoked. ### reset-password ## Reset the password Sets a new password using the `token` query parameter from the link that the user received. Successfully resetting the password will verify a user's email, if it hasn't been verified yet. ### get ## Get a password reset token Get the details of an existing password reset token that can be used to reset a user's password. ### create ## Create a password reset token Creates a one-time token that can be used to reset a user's password. ### Organization membership # Organization membership An organization membership is a top-level resource that represents a [user](/reference/authkit/user)'s relationship with an [organization](/reference/organization). A user may be a member of zero, one, or many organizations. See the [events reference](/events/organization-membership) documentation for the organization membership events. ### update ## Update an organization membership Update the details of an existing organization membership. ### reactivate ## Reactivate an organization membership Reactivates an `inactive` organization membership, retaining the pre-existing role(s). Emits an [organization\_membership.updated](/events/organization-membership) event upon successful reactivation. - Reactivating an `active` membership is a no-op and does not emit an event. - Reactivating a `pending` membership returns an error. The user needs to [accept the invitation](/authkit/invitations) instead. See the [membership management documentation](/authkit/users-organizations/organizations/membership-management) for additional details. ### list ## List organization memberships Get a list of all organization memberships matching the criteria specified. At least one of `user_id` or `organization_id` must be provided. By default only active memberships are returned. Use the `statuses` parameter to filter by other statuses. ### list-groups ## List groups Get a list of groups that an organization membership belongs to. ### get ## Get an organization membership Get the details of an existing organization membership. ### delete ## Delete an organization membership Permanently deletes an existing organization membership. It cannot be undone. ### deactivate ## Deactivate an organization membership Deactivates an `active` organization membership. Emits an [organization\_membership.updated](/events/organization-membership) event upon successful deactivation. - Deactivating an `inactive` membership is a no-op and does not emit an event. - Deactivating a `pending` membership returns an error. This membership should be [deleted](/reference/authkit/organization-membership/delete) instead. See the [membership management documentation](/authkit/users-organizations/organizations/membership-management) for additional details. ### create ## Create an organization membership Creates a new `active` organization membership for the given organization and user. Calling this API with an organization and user that match an `inactive` organization membership will activate the membership with the specified role(s). ### Multi-Factor Authentication Enroll users in multi-factor authentication for an additional layer of security. # Multi-Factor Authentication Enroll users in multi-factor authentication for an additional layer of security. MFA can be enabled via the [Authentication page](https://dashboard.workos.com/environment/authentication/features) in the WorkOS dashboard. ### list-auth-factors ## List authentication factors Lists the [authentication factors](/reference/authkit/mfa/authentication-factor) for a user. ### enroll-auth-factor ## Enroll an authentication factor Enrolls a user in a new [authentication factor](/reference/authkit/mfa/authentication-factor). ### authentication-factor ## Authentication factor Represents an authentication factor. ### authentication-challenge ## Authentication challenge Represents a challenge of an authentication factor. ### Magic Auth # Magic Auth Magic Auth is a passwordless authentication method that allows users to sign in or sign up via a unique, six digit one-time-use code sent to their email inbox. To verify the code, [authenticate the user with Magic Auth](/reference/authkit/authentication/magic-auth). ### get ## Get Magic Auth code details Get the details of an existing [Magic Auth](/reference/authkit/magic-auth) code that can be used to send an email to a user for authentication. ### create ## Create a Magic Auth code Creates a one-time authentication code that can be sent to the user's email address. The code expires in 10 minutes. To verify the code, [authenticate the user with Magic Auth](/reference/authkit/authentication/magic-auth). ### Logout # Logout End a user's session. The user's browser should be redirected to this URL. ### Get logout URL # Get logout URL ### Get logout URL from session cookie # Get logout URL from session cookie Generates the logout URL by extracting the session ID from the session cookie. Use this over `getLogoutUrl` if you don't have a saved reference to the session ID and you'd like the SDK to handle extracting the session ID from the cookie for you. ### JWT template # JWT template ### update ## Update JWT template Update the JWT template for the current environment. ### get ## Get JWT template Get the JWT template for the current environment. ### Invitation # Invitation An email invitation allows the recipient to sign up for your app and join a specific [organization](/reference/organization). When an invitation is accepted, a [user](/reference/authkit/user) and a corresponding [organization membership](/reference/authkit/organization-membership) are created. Users may be invited to your app without joining an organization, or they may be invited to join an organization if they already have an account. Invitations may be also issued on behalf of another user. In this case, the invitation email will mention the name of the user who invited the recipient. ### send ## Send an invitation Sends an invitation email to the recipient. ### revoke ## Revoke an invitation Revokes an existing invitation. ### resend ## Resend an invitation Resends an invitation email to the recipient. The invitation must be in a pending state. ### list ## List invitations Get a list of all of invitations matching the criteria specified. ### get ## Get an invitation Get the details of an existing invitation. ### find-by-token ## Find an invitation by token Retrieve an existing invitation using the token. ### accept ## Accept an invitation Accepts an invitation and, if linked to an organization, activates the user's membership in that organization. In most cases, use existing authentication methods like [`authenticateWithCode`](/reference/authkit/authentication/code), which also accept an invitation token. These methods offer the same functionality (invitation acceptance and membership activation) while also signing the user in. This method is useful for apps requiring a highly customized invitation flow, as it focuses solely on handling invitations without authentication. It's also helpful when users can be invited to multiple organizations and need a way to accept invitations after signing in. Your application should verify that the invitation is intended for the user accepting it. For example, by fetching the invitation using the [find-by-token endpoint](/reference/authkit/invitation/find-by-token) and ensuring the email matches the email address of the accepting user. ### Identities # Identities Represents [User](/reference/authkit/user) identities obtained from external identity providers. When a user authenticates using an external provider like [Google OAuth](/integrations/google-oauth), information from that provider will be made available as one of the user's Identities. You can read more about the process in our [identity linking guide](/authkit/identity-linking). > Applications should check the `type` before making assumptions about the shape of the identity. Currently only `OAuth` identities are supported, but more types may be added in the future. ### list ## Get user identities Get a list of identities associated with the user. A user can have multiple associated identities after going through [identity linking](/authkit/identity-linking). Currently only OAuth identities are supported. More provider types may be added in the future. ### Email verification # Email verification Email verification is a security feature that requires users to verify their email address before they can sign in to your application. It is enabled by default. Users signing in with Magic Auth, Google OAuth, Apple OAuth, or SSO are automatically verified. For other authentication methods, an email verification flow is required to confirm that the user's email address belongs to them. ### get ## Get an email verification code Get the details of an existing email verification code that can be used to send an email to a user for verification. ### CLI Auth # CLI Auth CLI Auth enables command-line applications to authenticate users through the web using the [OAuth 2.0 Device Authorization Flow](https://datatracker.ietf.org/doc/html/rfc8628). The CLI Auth flow involves two main endpoints: 1. The **device authorization URL** initiates the flow by obtaining a device code, user code, and verification URIs. 2. The **device access token URL** is where the device exchanges the device code for access and refresh tokens after the user authenticates. Read more about [CLI Auth here](/authkit/cli-auth). ### error-codes ### Error codes When polling the device code endpoint, you may receive various error responses before the user completes authorization or if authorization fails. These errors help your application understand the current state and take appropriate action. Possible error codes and the corresponding descriptions are listed below. | Error code | Description | | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `authorization_pending` | The authorization request is still pending as the user hasn't yet completed the user interaction flow. Continue polling at the specified interval. | | `slow_down` | The client is polling too frequently and should slow down. Increase your polling interval by at least 5 seconds and continue polling. | | `access_denied` | The user declined the authorization request. Stop polling and inform the user that authorization was denied. | | `expired_token` | The device code has expired (typically after 5 minutes). Stop polling and restart the authorization flow if needed. | | `invalid_request` | The request is missing a required parameter or includes an invalid parameter value. Check that `grant_type`, `device_code`, and `client_id` are provided and correct. | | `invalid_client` | Client authentication failed (e.g., unknown client, client authentication not included, or unsupported authentication method). | | `invalid_grant` | The provided device code is invalid, malformed, or has already been used. | | `unsupported_grant_type` | The grant type is not supported. Ensure you're using `urn:ietf:params:oauth:grant-type:device_code`. | ### Error response format All error responses are returned with a 400 status code and follow the OAuth 2.0 error response format. For example: ```json { "error": "authorization_pending", "error_description": "The authorization request is still pending as the user hasn't yet completed the user interaction flow." } ``` ### Device code Exchange a device code for access and refresh tokens during the CLI Auth flow. ## Device code Exchanges a device code for access and refresh tokens as part of the [CLI Auth](/authkit/cli-auth) flow. This endpoint should be polled repeatedly until the user authorizes the request, declines it, or the device code expires. ### Get a device authorization URL Initiate the CLI Auth flow by obtaining a device code and verification URLs. ## Get device authorization URL Initiates the CLI Auth flow by requesting a device code and verification URLs. This endpoint implements the OAuth 2.0 Device Authorization Flow ([RFC 8628](https://datatracker.ietf.org/doc/html/rfc8628)) and is designed for command-line applications or other devices with limited input capabilities. ### Authentication errors # Authentication errors Integrating the authentication API directly requires handling error responses for email verification, MFA challenges, Radar challenges, identity linking, and organization selection. One or more of these responses may be returned for an authentication attempt with any authentication method. Hosted AuthKit handles authentication errors for you and may be a good choice if you prefer a simpler integration. ### sso-required-error ## SSO required error This error indicates that a user attempted to authenticate into an organization that requires SSO using a different authentication method. It includes a list of SSO connections that may be used to complete the authentication. When this error occurs, you'll need to use one of the SSO connections from the error to [get the authorization URL](/reference/authkit/authentication/get-authorization-url) and redirect the user to that URL to complete the authentication with the organization's identity provider. ### radar-sms-challenge-error ## Radar SMS challenge error This error indicates that a user attempted to authenticate in an environment where WorkOS Radar determined the attempt should be verified with an SMS challenge. It includes a pending authentication token that should be used to complete the authentication. When this error occurs, [send a Radar SMS challenge](/reference/authkit/send-radar-sms-challenge) to deliver a one-time code to the user's phone number. To complete the authentication process, use the pending authentication token from the error, the `verification_id` returned by that endpoint, and the one-time code the user received to [authenticate with a Radar SMS challenge](/reference/authkit/authentication/radar-sms-challenge). ### radar-email-challenge-error ## Radar email challenge error This error indicates that a user attempted to authenticate in an environment where WorkOS Radar determined the attempt should be verified with an email challenge. It includes a pending authentication token and the ID of the Radar challenge that should be used to complete the authentication. When this error occurs, WorkOS sends a one-time code to the user's email address. To complete the authentication process, use the pending authentication token from the error, the `radar_challenge_id`, and the one-time code the user received to [authenticate with a Radar email challenge](/reference/authkit/authentication/radar-email-challenge). ### organization-selection-error ## Organization selection required error This error indicates that the user is a member of multiple organizations and must select which organization to sign in to. It includes a list of organizations the user is a member of and a pending authentication token that should be used to complete the authentication. When this error occurs, you'll need to display the list of organizations that the user is a member of and authenticate them with the [selected organization](/reference/authkit/authentication/organization-selection) using the pending authentication token from the error. ### organization-authentication-required-error ## Organization authentication required error This error indicates that a user attempted to authenticate with an authentication method that is not allowed by the organization that has a [domain policy](/authkit/organization-policies) managing this user. It includes all the possible methods the user can use to authenticate. When this error occurs, you'll need to present the user with these options so they can choose which method to continue authentication. ### mfa-enrollment-error ## MFA enrollment error This error indicates that a user who is not enrolled into MFA attempted to authenticate in an environment where MFA is required. It includes a pending authentication token that should be used to authenticate the user once they enroll into MFA. When this error occurs, you'll need to present an [MFA enrollment](/reference/authkit/mfa/enroll-auth-factor) UI to the user. Once the user has enrolled, present an MFA challenge UI to the user and authenticate them with their [TOTP code](/reference/authkit/authentication/totp) and the pending authentication token from this error. MFA can be enabled via the [Authentication page](https://dashboard.workos.com/environment/authentication/features) in the WorkOS dashboard. ### mfa-challenge-error ## MFA challenge error This error indicates that a user enrolled into MFA attempted to authenticate in an environment where MFA is required. It includes a pending authentication token and a list of factors that the user is enrolled in that should be used to complete the authentication. When this error occurs, you'll need to present an MFA challenge UI to the user and authenticate them with their [TOTP code](/reference/authkit/authentication/totp), the pending authentication token from this error, and a [challenge](/reference/mfa/challenge/create) that corresponds to one of the authentication factors. MFA can be enabled via the [Authentication page](https://dashboard.workos.com/environment/authentication/features) in the WorkOS dashboard. ### email-verification-required-error ## Email verification required error This error indicates that a user with an unverified email address attempted to authenticate in an environment where email verification is required. It includes a pending authentication token that should be used to complete the authentication. When this error occurs and the [email setting](/authkit/custom-emails) for email verification is enabled, WorkOS will automatically send a one-time email verification code to the user's email address and issue a pending authentication token. If the email setting is not enabled, [retrieve the email verification code](/reference/authkit/email-verification/get) to send the email verification email yourself. To complete the authentication process, use the pending authentication token from the error and the one-time code the user received to [authenticate](/reference/authkit/authentication) them and to verify their email address. The same applies when a user attempts to authenticate with OAuth or SSO, but there was already an account with a matching unverified email address. ### Authentication # Authentication Authenticate a user with a specified authentication method. ### totp ## Authenticate with a time-based one-time password Authenticates a user enrolled into MFA using time-based one-time password (TOTP). Users enrolled into MFA are required to enter a TOTP each time they sign in. When they attempt to authenticate with their credentials, the API will return an [MFA challenge error](/reference/authkit/authentication-errors/mfa-challenge-error) that contains a pending authentication token. To continue with the authentication flow, [challenge](/reference/mfa/challenge/create) one of the factors returned by the MFA challenge error response and present a UI to the user to enter the TOTP code. Then, authenticate the user with the TOTP code, the challenge from the factor, and the pending authentication token from the MFA challenge error. MFA can be enabled via the [Authentication page](https://dashboard.workos.com/environment/authentication/features) in the WorkOS dashboard. ### session-cookie ## Authenticate with session cookie Authenticates a user using an AuthKit session cookie. This method does not make a network call, but simply unseals an existing session cookie and decodes the JWT claims from the [access token](/reference/authkit/session-tokens/access-token). ### refresh-token ## Authenticate with refresh token Use this endpoint to exchange a refresh token for a new access token. Refresh tokens may be rotated after use, so a replacement refresh token is also provided. ### refresh-and-seal-session-data ## Refresh and seal session data Unseals the provided session data from a user's session cookie, [authenticates with the existing refresh token](/reference/authkit/authentication/refresh-token), and returns the sealed data for the refreshed session. ### radar-sms-challenge ## Authenticate with a Radar SMS challenge Completes an authentication that WorkOS Radar flagged for an SMS challenge. When a user attempts to authenticate and Radar determines the attempt should be verified, the API returns a [Radar SMS challenge error](/reference/authkit/authentication-errors/radar-sms-challenge-error) that contains a pending authentication token. [Send a Radar SMS challenge](/reference/authkit/send-radar-sms-challenge) to deliver a one-time code to the user's phone number and obtain a `verification_id`. Use the pending authentication token from the error, the `verification_id`, and the one-time code the user received to authenticate them. ### radar-email-challenge ## Authenticate with a Radar email challenge Completes an authentication that WorkOS Radar flagged for an email challenge. When a user attempts to authenticate and Radar determines the attempt should be verified, the API returns a [Radar email challenge error](/reference/authkit/authentication-errors/radar-email-challenge-error) that contains a pending authentication token and a `radar_challenge_id`, and WorkOS sends a one-time code to the user's email address. Use the pending authentication token from the error, the `radar_challenge_id`, and the one-time code the user received to authenticate them. ### password ## Authenticate a user with password Authenticates a user with email and password. ### organization-selection ## Authenticate with organization selection Authenticates a user into an organization they are a member of. When a user who is a member of multiple organizations attempts to authenticate with their credentials, the API will return an [organization selection error](/reference/authkit/authentication-errors/organization-selection-error) that contains a pending authentication token. To continue with the authentication flow, your application should display the list of organizations for the user to choose. Use the pending authentication token from the error and the organization the user selected in your UI to complete the authentication. ### magic-auth ## Authenticate with Magic Auth Authenticates a user by verifying the [Magic Auth code](/reference/authkit/magic-auth) sent to the user's email. ### email-verification ## Authenticate with an email verification code Authenticates a user with an unverified email and verifies their email address. A user with an unverified email address won't be able to authenticate right away. When they attempt to authenticate with their credentials, the API will return an [email verification required error](/reference/authkit/authentication-errors/email-verification-required-error) that contains a pending authentication token. If the [email setting](/authkit/custom-emails) for email verification is enabled, WorkOS will automatically send a one-time email verification code to the user's email address. If the email setting is not enabled, [retrieve the email verification code](/reference/authkit/email-verification/get) to send the email yourself. Use the pending authentication token from the error and the one-time code the user received to authenticate them and to complete the email verification process. ### code ## Authenticate with code Authenticates a user using AuthKit, OAuth or an organization's SSO connection. AuthKit handles all authentication methods, however it is conceptually similar to a social login experience. Like OAuth and SSO, AuthKit returns you a code that you can exchange for an authenticated user. See [Integrating with AuthKit](/authkit). ### Get an authorization URL # Get an authorization URL Generates an OAuth 2.0 authorization URL to authenticate a user with AuthKit or SSO. If you are using AuthKit, set the provider parameter to `"authkit"`, which will generate an authorization URL for your AuthKit domain. AuthKit will take care of detecting the user's authentication method, such as identifying whether they use Email + Password or Single Sign-On,and direct them to the corresponding login flow. Otherwise, to generate an authorization URL for a WorkOS SSO connection, you'll have to specify the user's connection, organization, or OAuth provider as a parameter. These connection selectors are mutually exclusive, and exactly one must be provided. The generated URL automatically directs the user to their identity provider. Once the user authenticates with their identity provider, WorkOS then issues a redirect to your redirect URI to complete the sign-in flow. ### redirect-uri ### Redirect URI In the [OAuth 2.0](/glossary/oauth-2-0) protocol, a redirect URI is the location that the user is redirected to once they have successfully authenticated with their identity provider. When redirecting the user, WorkOS will generate an authorization code and pass it to your redirect URI as a `code` query parameter, your app will use this code to [authenticate the user](/reference/authkit/authentication/code). Additionally, WorkOS can pass a `state` parameter back to your application that you may use to encode arbitrary information to restore your application state between the redirects. ```url title="Redirect URI with query parameters" https://your-app.com/callback?code=01E2RJ4C05B52KKZ8FSRDAP23J&state=dj1kUXc0dzlXZ1hjUQ== ``` You can use `state` to encode parameters like originating URL and query parameters. This is useful in a flow where unauthenticated users are automatically redirected to a login page. After successful sign in, users will be routed to your redirect URI callback route. From there you can extract the originating URL from `state` and redirect the user to their intended destination. You'll need to configure the allowed redirect URIs for your application in the [Applications](https://dashboard.workos.com/environment/applications) section of the WorkOS Dashboard. Open your application and go to the **Redirects** tab. Without a valid redirect URI, your users will be unable to sign in. Make sure that the redirect URI you use as a parameter to get the authorization URL matches one of the redirect URIs configured for the application. Redirect URIs follow stricter requirements in production environments: - `HTTPS` protocol is required in production environments - `HTTP` and `localhost` are allowed in staging environments - The sole exception is the use of `http://127.0.0.1` in production environments to support native clients. #### Wildcards WorkOS supports using wildcard characters (`*`) in Redirect URIs to handle dynamic subdomains or variable ports during development. ##### Subdomains The `*` symbol can be used as a wildcard for subdomains; however, it must be used in accordance with the following rules: - The protocol of the URL **must not** be `http:` in production environments. - The wildcard **must** be located in the subdomain furthest from the root domain (e.g., `https://*.sub.example.com` will work, but `https://sub.*.example.com` will not). - The URL **must not** contain more than one wildcard. - A wildcard character **may** be prefixed and/or suffixed (e.g., `https://prefix-*-suffix.example.com`). - A wildcard **will not** match across multiple subdomain levels (e.g., `https://*.example.com` will not match `https://sub1.sub2.example.com`). - Wildcards cannot be used with [public suffix domains](https://publicsuffix.org) (e.g., `https://*.ngrok-free.app` will not work). - The wildcard will match letters, digits, hyphens, and underscores. - A URL with a wildcard cannot be set as the default redirect URI. ##### Ports To support [RFC 8252](https://datatracker.ietf.org/doc/html/rfc8252#section-7.3) ("OAuth 2.0 for Native Apps") and local development, a wildcard may be used in place of the port number. - This is strictly limited to `localhost` and loopback IP addresses (e.g., `127.0.0.1`). - Example: `http://localhost:*/auth/callback` is valid. ### pkce ### PKCE The [Proof Key for Code Exchange](https://datatracker.ietf.org/doc/html/rfc7636) (PKCE) flow is an extension to the OAuth 2.0 Authorization Code flow. It enables public clients, like native apps or single-page apps, to perform the authorization code flow securely. If you are developing a client that makes API calls in public, you'll need to use this flow. In this flow, your client generates a code verifier which is a high-entropy cryptographic random string. A code challenge is derived by hashing the code verifier. Instead of using a client secret, provide the code challenge when [getting the authorization URL](/reference/authkit/authentication/get-authorization-url) and the code verifier when [authenticating a User](/reference/authkit/authentication/code). ### error-codes ### Error codes If there is an issue generating an authorization URL, the API will return the original redirect URI with `error` and `error_description` query parameters. If provided, the `state` value will also be included. ```url title="Redirect URI with an error code" https://your-app.com/callback?error=organization_invalid&error_description=No%20connection%20associated%20with%20organization&state=123456789 ``` Possible error codes and the corresponding descriptions are listed below. | Error code | Description | | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `access_denied` | The identity provider denied user access to the client application or the user denied an OAuth authorization request at the identity provider. | | `ambiguous_connection_selector` | A connection could not be uniquely identified using the provided connection selector (e.g., organization). This can occur when there are multiple SSO connections under the same organization. If you need multiple SSO connections for an organization, use the connection parameter to identify which connection to use for SSO. | | `connection_invalid` | There is no connection for the provided ID. | | `connection_strategy_invalid` | The provider has multiple strategies associated per environment. | | `connection_unlinked` | The connection associated with the request is unlinked. | | `invalid_connection_selector` | A valid connection selector query parameter must be provided in order to correctly determine the proper connection to return an authorization URL for. Valid connection selectors are either `connection`, `organization`, or `provider`. | | `organization_invalid` | There is no organization matching the provided ID. | | `oauth_failed` | An OAuth authorization request failed for a user. | | `server_error` | The SSO authentication failed for the user. More detailed errors and steps to resolve are available in the Sessions tab on the connection page in the WorkOS Dashboard. | ### API Keys # API Keys API keys provide a secure way for your application's users to authenticate with your API. IT contacts create API keys through the [API Keys Widget](/widgets/api-keys), and your application can validate these keys to authenticate API requests. Read more about [API keys in AuthKit](/authkit/api-keys). The `owner.type` field distinguishes organization-owned keys from user-owned keys. Organization-owned keys include an organization ID in `owner.id`. User-owned keys include the user ID in `owner.id` and the organization the key can access in `owner.organization_id`. The full API key value is returned only when a key is created. Later list, validate, and object responses include `obfuscated_value`, but not `value`. ### Validate API key Validate an API key and retrieve associated metadata. ## Validate API key Validates an API key and returns its associated metadata if the key is valid. Your application's API uses this endpoint to authenticate incoming requests that include an API key. The endpoint returns the complete API key object when validation succeeds, allowing you to access the key's permissions and owner information for authorization purposes. If the key is invalid, the endpoint returns `null` for the `api_key` field. ### list-for-user ## List API keys for a user Get a list of API keys owned by a specific user. ### list-for-organization ## List API keys for an organization Get a list of all API keys for an organization. ### expire ## Expire an API key Expire an API key immediately, schedule a future expiration, or clear a scheduled future expiration. ### delete ## Delete an API key Permanently deletes an API key. This action cannot be undone. Once deleted, any requests using this API key will fail authentication. ### create-for-user ## Create an API key for a user Create a new API key owned by a user. The user must have an active membership in the specified organization. ### create-for-organization ## Create organization API key Creates a new API key for the specified organization. The response includes the full API key value, which is only returned once at creation time. Make sure to store this value securely as it cannot be retrieved again. You can optionally specify permissions to control what actions the API key can perform. If no permissions are provided, the key will have no specific permissions assigned. ### Agent Registration # Agent Registration Agent Registration enables AI agents and programmatic clients to obtain identity credentials from an AuthKit-powered service. The registration flow issues a signed identity assertion that can be exchanged at the token endpoint for an access token or API key. ## Registration types - **`anonymous`** — No user identity. Receives limited scopes immediately and can optionally bind to a user via the claim ceremony. - **`service_auth`** — Requires the user's email. A claim ceremony is mandatory before trusted scopes are granted. - **`refresh`** — Rotates an expiring identity assertion using a refresh token from a previous registration. Read more about [Agent Registration here](/authkit/agent-auth). ### Register an agent Register an agent identity with one of the supported identity types. ## Register an agent Registers an agent identity using one of the supported identity types. The request body is a discriminated union — the `type` field determines which additional fields are required. ### Registration types - **`anonymous`** — No additional fields required. Returns an identity assertion immediately along with a claim token for an optional claim ceremony. - **`service_auth`** — Requires `login_hint`. Returns a claim token for a mandatory claim ceremony. The identity assertion is delivered after claim completion. - **`refresh`** — Requires `refresh_token`. Returns a fresh identity assertion with a rotated refresh token. ### Error responses - **`invalid_request`** — The request body is malformed or missing required fields for the specified type. - **`invalid_login_hint`** — The `login_hint` email is invalid or not recognized. - **`invalid_refresh_token`** — The refresh token is expired, revoked, or invalid. ### Start a claim Start a claim ceremony to bind an agent registration to a user. ## Start a claim Starts a claim ceremony by minting a claim attempt. The response includes a `verification_uri` that the agent presents to the user. The user signs in at that URL, and the claim page reveals a `user_code` for them to relay back to the agent. ### Error responses - **`invalid_claim_token`** — The claim token is expired, revoked, or invalid. Restart registration. - **`invalid_login_hint`** — The email address is invalid or does not match the registration. ### View a claim View claim details for a user who has signed in to the claim page. ## View a claim Retrieves claim details for the authenticated claim page. This endpoint requires a valid user access token in the `Authorization: Bearer` header and reveals the `user_code` that the user reads back to the agent. The `token` parameter is the attempt token embedded in the `verification_uri` from the claim attempt response. ### Error responses - **`invalid_token`** — The attempt token is expired or invalid. - **`unauthorized`** — The request is not authenticated with a valid user access token. - **`email_mismatch`** — The signed-in user's email does not match the registration's login hint. ### Complete a claim Complete a claim ceremony by submitting the user code relayed from the user. ## Complete a claim Completes the claim ceremony by submitting the `user_code` that the user read from the claim page. The agent provides the `claim_token` from its original registration response alongside the code relayed by the user. On success, the verified identity is delivered exactly once in the response — the agent must persist it immediately. ### Error responses - **`invalid_user_code`** — The user code is incorrect. Ask the user to re-read the code. - **`user_code_expired`** — The user code has expired. Start a new claim attempt. - **`claim_not_confirmed`** — The user has not yet signed in and viewed the code. Wait and retry. - **`claim_expired`** — The claim has expired. Restart registration. - **`claim_revoked`** — The claim was revoked. Restart registration. - **`already_claimed`** — The registration has already been claimed. Restart registration. ### Audit Logs # Audit Logs Audit Logs are a collection of events that contain information relevant to notable actions taken by users in your application. Every event in the collection contains details regarding what kind of action was taken (`action`), who performed the action (`actor`), what resources were affected by the action (`targets`), and additional details of when and where the action took place. ### Audit Log Schema # Audit Log Schema An object representing an Audit Log Schema. ### list ## List Schemas Get a list of all schemas for the Audit Logs action identified by `:name`. ### list-actions ## List Actions Get a list of all Audit Log actions in the current environment. ### create ## Create Schema Creates a new Audit Log schema used to validate the payload of incoming Audit Log Events. If the `action` does not exist, it will also be created. ### Audit Log Retention # Audit Log Retention Retention settings control how long Audit Log events are stored before being permanently deleted. You can configure the retention period on a per-organization basis. ### set ## Set Retention Set the event retention period for the given Organization. ### get ## Get Retention Get the configured event retention period for the given Organization. ### Audit Log Export # Audit Log Export An object representing an Audit Log Export. ### get ## Get Export Get an Audit Log Export. The URL will expire after 10 minutes. If the export is needed again at a later time, refetching the export will regenerate the URL. > The URL will expire after 10 minutes. If the export is needed again at a later time, refetching the export will regenerate the URL. ### create ## Create Export Create an Audit Log Export. Exports are scoped to a single organization within a specified date range. ### Audit Log Event # Audit Log Event An Audit Log Event represents a notable action taken within your application. Each event captures what happened, who did it, what was affected, and contextual information about when and where it occurred. ### create ## Create Event Create an Audit Log Event. This API supports idempotency which guarantees that performing the same operation multiple times will have the same result as if the operation were performed only once. This is handy in situations where you may need to retry a request due to a failure or prevent accidental duplicate requests from creating more than one resource. To achieve idempotency, you can add `Idempotency-Key` request header to a Create Event request with a unique string as the value. Each subsequent request matching this unique string will return the same response. We suggest using [v4 UUIDs](https://en.wikipedia.org/wiki/Universally_unique_identifier) for idempotency keys to avoid collisions. Idempotency keys expire after 24 hours. The API will generate a new response if you submit a request with an expired key. ### Get Audit Log Configuration # Get Audit Log Configuration The Audit Log Configuration endpoint provides a single view of an organization's audit logging setup. It includes retention settings (how long audit logs are stored), the audit log state (active, inactive, or disabled), and—if configured—the audit log stream, which sends events to external destinations like Splunk, Datadog, S3, Google Cloud Storage, or a custom HTTPS endpoint. The log\_stream field is optional and only appears if the organization has a stream configured. If no stream is set up, the response includes only the audit log retention and state information. ### API authentication # API authentication WorkOS authenticates your API requests using your account's API keys. API requests made without authentication or using an incorrect key will return a `401` error. Requests using a valid key but with insufficient permissions will return a `403` error. All API requests must be made over HTTPS. Any requests made over plain HTTP will fail. You can view and manage your API keys in the [WorkOS Dashboard](https://dashboard.workos.com/api-keys). ## Secure your API Keys API keys can perform any API request to WorkOS. They should be kept secure and private! Be sure to prevent API keys from being made publicly accessible, such as in client-side code, GitHub, unsecured S3 buckets, and so forth. API keys are prefixed with `sk_`. ## In Staging Your Staging Environment comes with an API key already generated for you. Staging API keys may be viewed as often as they are needed and will appear inline throughout our documentation in code examples if you are logged in to your WorkOS account. API requests will be scoped to the provided key's Environment. ## In Production Once you unlock Production access you will need to generate an API Key for it. Production API keys may only be viewed once and will need to be saved in a secure location upon creation of them. ### Agent Registration # Agent Registration ### validate-credential ## Validate an agent credential Validate an agent credential — an API key or access token — against the environment of the API key used to authenticate the request. This is a read-only check: it never consumes or mutates the credential. ### get-registration ## Get an agent registration Retrieve the details of an agent registration by ID. The registration is scoped to the environment of the API key used to authenticate the request. ### Admin Portal # Admin Portal The Admin Portal is a standalone application where your users can configure and manage WorkOS resources such as [Connections](/reference/sso/connection) and [Directories](/reference/directory-sync/directory) that are scoped to their [Organization](/reference/organization). ### Provider icons # Provider icons Icons for third-party providers are available through the WorkOS CDN. These icons cover identity providers, Directory Sync, and domain verification services used within the Admin Portal. ## List Provider Icons Get a list of all of existing provider icons. ## Get a Provider Icon To use an icon in your project, you can reference the CDN link directly. You can alternate between light and dark mode icons by changing the path in the URL or using CSS media queries. ```html title="Example icon" Okta icon ``` You can change the icons to grayscale by adding the `filter` CSS property. ```css title="Grayscale style" img { filter: grayscale(100%); } ``` ### Portal link # Portal link A portal link is a temporary endpoint to initiate an Admin Portal session. It expires five minutes after issuance. ```url title="Example Portal Link URL" https://setup.workos.com?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` ### generate ## Generate a Portal Link Generate a Portal Link scoped to an Organization. ## RBAC {#rbac} ### Role-Based Access Control (RBAC) Assign roles and manage access for users and organizations ## Introduction WorkOS Role-Based Access Control (RBAC) is an authorization system designed for managing access to applications using a flexible roles and permissions model. With WorkOS RBAC, teams can also define custom roles at the organization or tenant level, assign permissions to those roles, and enforce access policies at scale. RBAC also supports role assignment from identity provider (IdP) groups, making it easy to integrate with Single Sign-On (SSO) and Directory Sync workflows for seamless, enterprise-ready access control. ## Key features - Fully managed authorization service for defining and enforcing access controls across your application - Configure roles, permissions, and organization-scoped roles directly in the [WorkOS Dashboard](https://dashboard.workos.com) or using the [API](/reference/roles) - Seamless integration with [AuthKit user management](/authkit) by assigning roles via API and enforcing access through session JWTs - Support for enterprise features like organization-scoped roles and IdP role assignment via SSO and Directory Sync allowing your customers to automatically map roles from their identity provider to streamline enterprise onboarding - Fully integrated with [WorkOS Widgets](/widgets), including role management through the User Management Widget ## Additional resources - [The developer's guide to RBAC](https://workos.com/guide/the-developers-guide-to-rbac) - [8 Role-Based Access Control (RBAC) examples in action](https://workos.com/blog/role-based-access-control-example) - [How to build RBAC with WorkOS and Node](https://workos.com/blog/rbac-with-workos-and-node) ### Quick Start Set up roles & permissions to model your authorization requirements. Then use the SDK to make access checks from your application. ## Before getting started To get the most out of this guide, you should have: - A [WorkOS account](https://dashboard.workos.com/) - Your WorkOS [API Key](/glossary/api-key) ## What you'll build In this guide, we'll implement role-based access control for a simple B2B video sharing SaaS application, where users can view and create videos, and elevated roles can manage other users' roles and application settings. We will: 1. Map your application's access management model to a set of roles 2. Define permissions to control granular access to your application's resources 3. Associate permissions with roles, and configure default roles and priority order 4. If using AuthKit, assign roles to organization memberships and determine access via the [session JWT](/reference/authkit/session-tokens) 5. If using standalone SSO, access user roles through the [SSO Profile object](/reference/sso/profile) 6. If using standalone Directory Sync, access user roles through the [Directory User object](/reference/directory-sync/directory-user) ## API resource definitions [Role](/reference/roles) : Represents a logical grouping of access management rules. --- ## (1) Create roles The first step to RBAC is to determine the application's access management hierarchy. --- ## (2) Create permissions The first step to RBAC is to define Get provider-specific instructions by selecting the directory provider you want to test: --- ## Summary That's it! We've now setup a powerful RBAC system for our application. ### Integrating Role-Based Access Control Utilize Role-Based Access Control across WorkOS products ## Configure roles and permissions Before integrating with WorkOS Role-Based Access Control (RBAC), you'll need to [configure roles and permissions](/rbac/configuration) for your application in the [WorkOS Dashboard](https://dashboard.workos.com/). --- ## Integrating with AuthKit WorkOS RBAC seamlessly integrates with AuthKit to provide a complete user management solution. Using AuthKit, you can assign roles directly to organization memberships, source roles from your customer's identity provider (IdP), and read roles and permissions directly from session JWTs. ### Assigning roles In AuthKit, users are associated with [organizations](/reference/organization) via [organization memberships](/reference/authkit/organization-membership). Each organization membership has role(s), which represents a user's access level for that particular organization. Every organization membership is automatically assigned the [default role](/rbac/configuration/configure-roles/default-role) when added to an organization. You can modify an organization membership's role(s) via the [organization memberships API](/reference/authkit/organization-membership/create), [WorkOS Dashboard](https://dashboard.workos.com/), or via [IdP role assignment](/rbac/idp-role-assignment). [IdP role assignment](/rbac/idp-role-assignment) will always take precedence over roles assigned via API or the WorkOS Dashboard. For [SSO group role assignment](/sso/identity-provider-role-assignment/sso-group-role-assignment), the organization membership role updates each time the user authenticates. For [directory group role assignment](/directory-sync/identity-provider-role-assignment/directory-group-role-assignment) via [directory provisioning](/authkit/directory-provisioning), the organization membership's role updates each time we receive a directory event for the user. ### Single vs. multiple roles AuthKit, Directory Sync, and Single Sign-On all support both single and [multiple role](/authkit/roles-and-permissions/multiple-roles) paradigms. There are two ways to assign multiple roles: - **Group-based assignment**: if a user is a member of multiple groups with role mappings, they will receive all the roles. This applies to directory users, SSO profiles, and organization memberships when using [directory](/authkit/directory-provisioning) or [SSO JIT provisioning](/authkit/jit-provisioning/sso-jit-provisioning) in AuthKit. - **Manual assignment**: multiple roles can be assigned to [organization memberships](/reference/authkit/organization-membership) directly via the WorkOS Dashboard or [API](/reference/authkit/organization-membership/create). Multiple roles helps to avoid needing to create roles for every possible combination of permissions e.g., designer-engineer. This model fits teams where users span functions or need additive, temporary access. For most apps, start with **single-role** assignments for simplicity and predictability, and adopt multiple roles only when overlapping permission sets become common. ### Groups and group role assignments [Groups](/authkit/groups) provide a way to assign roles at the group level rather than to individual organization memberships. When you assign a role to a group, every member of that group receives the role automatically. As members are added or removed, their roles update accordingly. This is particularly useful for managing roles across teams or departments. Instead of assigning the same role to each member individually, assign it once to the group. Group-sourced roles are treated the same as directly assigned roles. They appear in the user's session token and count toward the effective permissions for the organization membership. In [multiple-roles mode](/authkit/roles-and-permissions/multiple-roles), all group roles are combined additively. In single-role mode, the highest-priority role wins across all sources. For full details, see [Group role assignments](/authkit/group-role-assignments). ### Using roles and permissions in your app Read a user's role(s) from their [organization membership](/reference/authkit/organization-membership) or from an [AuthKit session access token](/authkit/sessions/integrating-sessions/access-token). --- ## Integrating with Directory Sync For [standalone Directory Sync](/directory-sync), IT contacts manage roles through [directory group role assignment](/directory-sync/identity-provider-role-assignment). Their assigned role defines the user's access level for the particular [organization](/reference/organization) and is based on their directory group memberships. All [directory users](/reference/directory-sync/directory-user) have assigned roles. If no role is explicitly assigned through directory group role assignment, the user receives the [default role](/rbac/configuration/configure-roles/default-role). Roles are granted to directory users in real-time, when we receive updates to their group memberships. Role slugs are returned on [Directory User](/reference/directory-sync/directory-user) objects from the API. These can be used to assign a role to your internal user object. --- ## Integrating with Single Sign-On (SSO) For [standalone SSO](/sso), IT contacts manage roles via [SSO group role assignment](/sso/identity-provider-role-assignment). Their assigned role defines the user's access level for the particular [organization](/reference/organization). All [SSO profiles](/reference/sso/profile) have assigned roles. If no role is explicitly assigned through SSO group role assignment, the user receives the [default role](/rbac/configuration/configure-roles/default-role). Roles are granted to SSO profiles when the user authenticates. Role slugs are returned on [SSO Profile](/reference/sso/profile) objects from the API. These can be used to assign a role to your internal user object based on group memberships. ### IdP Role Assignment Map identity provider groups to roles to automatically assign roles to users ## Overview Identity Provider (IdP) role assignment is the process of mapping identity provider groups to roles to automatically assign roles to users. Users are assigned to groups via the identity provider. Groups usually correspond to roles in your app. Therefore, IT contacts will often map a group one-to-one to a role. This can be defined within the WorkOS dashboard or Admin Portal for your application to receive automatic role updates. ## Role assignment sources ### Directory Sync Roles can be assigned from the identity provider via Directory Sync through [directory group role assignment](/directory-sync/identity-provider-role-assignment/directory-group-role-assignment). IT contacts can map groups to roles in the Admin Portal during SCIM and Google Workspace directory setup. You can also manage these assignments in the [WorkOS Dashboard](https://dashboard.workos.com/). Enterprise organizations typically use SSO to manage user authentication and SCIM (Directory Sync) for user lifecycle management. While access management can be automated through either SSO or SCIM, SCIM is generally the preferred option due to its real-time synchronization capabilities. ### SSO Roles can be assigned from the identity provider via SSO through [SSO group role assignment](/sso/identity-provider-role-assignment/sso-group-role-assignment). IT contacts can map groups to roles in the Admin Portal during SSO connection setup. You can also manage these assignments in the [WorkOS Dashboard](https://dashboard.workos.com/). SSO group role assignment is supported in both SAML and OIDC-based connection types, except for Google OIDC due to [a limitation](https://issuetracker.google.com/issues/133774835?pli=1) with the groups claim. A key limitation of SSO-based role assignment is that changes made in the identity provider (IdP) only take effect after the user re-authenticates. In contrast, SCIM propagates changes immediately without requiring user interaction, enabling applications to revoke sessions and enforce access updates in real time. > If your organization has a directory connection configured, it is recommended to use the [directory for role assignment](/directory-sync/identity-provider-role-assignment/directory-group-role-assignment). ## AuthKit integration If you are [integrating with AuthKit](/authkit/roles-and-permissions/role-assignment), our full user management solution, roles are automatically assigned to the appropriate [organization membership](/reference/authkit/organization-membership). These roles are also reflected in the [user's session token](/authkit/sessions/integrating-sessions/access-token), ensuring consistent access control across your application. When using SSO group role assignment, roles are populated on the organization membership through SSO groups, allowing role assignment based on your customer's identity provider configuration each time a user authenticates. When using Directory Sync group role assignment, roles are populated on the organization membership through [directory provisioning](/authkit/directory-provisioning), allowing for seamless, real-time role assignment based on your customer's identity provider configuration. ## Priority order If a user is provisioned from multiple groups with conflicting roles, the role with the highest priority will be assigned. If using multiple roles, priority order should be ignored. ![Edit role priority dialog](https://images.workoscdn.com/images/3c6946c2-4ff1-41e4-b10f-568339dc3a2b.png?auto=format&fit=clip&q=50) ## Multiple roles When [multiple roles is enabled](/rbac/configuration/configure-roles/multiple-roles), users can receive multiple roles through identity provider group memberships. This applies to both [SSO group role assignment](/sso/identity-provider-role-assignment) and [Directory Sync group role assignment](/directory-sync/identity-provider-role-assignment). ### How multiple roles work with IdP assignment - **All applicable roles assigned**: Users receive all roles from groups they belong to that have explicit role mappings - **Union of permissions**: Users get the combined permissions from all assigned roles - **Priority order ignored**: When multiple roles are enabled, priority order is not used since users receive all applicable roles - **Minimum one role**: Every user must have at least one role - if no groups have explicit mappings, the user receives the [default role](/rbac/configuration) ### Example scenario If a user is a member of both "Engineering" and "Design" groups in their identity provider: - **Single role mode**: User receives the highest priority role (e.g., "Engineering") - **Multiple roles mode**: User receives both "Engineering" and "Designer" roles This prevents "role explosion" where you would otherwise need to create hybrid roles like "designer-engineer" for every possible combination. ## Explicit vs. default role assignments Explicit role assignments are created by manually mapping an IdP group to a role in the WorkOS Admin Portal or Dashboard. Default role assignments are created for any IdP group that does not have an explicit role mapping. Default group role assignments are always mapped to the configured [default role](/rbac/configuration/configure-roles/default-role). ## Role assignment in Admin Portal You can choose to show or hide the role assignment step in Admin Portal, and whether to show the steps for Directory Sync or SSO at an environment level on the _Authorization_ page in the [WorkOS Dashboard](https://dashboard.workos.com/). ![Role assignment in Admin Portal dialog](https://images.workoscdn.com/images/fe19e3ac-6370-404e-9590-cdb06b3de127.png?auto=format&fit=clip&q=50) For your customers that may have a different setup, you can override the role assignment in Admin Portal setting per-organization, on the _Roles_ tab of the organization page in the [WorkOS Dashboard](https://dashboard.workos.com/). For example, if most customers use Directory Sync but a few only use SSO, select "Directory groups" role assignment at the environment level, and select "Single Sign-On groups" at the organization level for the exceptions. ### Custom Roles Create and manage custom organization-scoped roles ## Overview Custom roles are roles scoped to a particular organization. They are managed via the _Roles_ tab under an organization in the [WorkOS Dashboard](https://dashboard.workos.com/) or using the [Custom Roles API](/reference/roles/custom-role). You can utilize custom roles regardless of whether you're integrating with AuthKit, SSO, or Directory Sync. ![Roles tab for organization](https://images.workoscdn.com/images/7faa176d-bfb9-405b-bb24-700201566ac6.png?auto=format&fit=clip&q=50) ### Why might I use custom roles? In some cases, an application's fixed set of roles may not meet the needs of certain organizations. For example, an organization may require a lesser privileged set of permissions for their members. Custom roles allow you to create roles with the organization's desired set of permissions, without affecting access control for other organizations. ### Creating custom roles By default, organizations have no custom roles and simply inherit the environment-level roles. You can create a custom role by clicking the "Create role" button on the organization's _Roles_ tab or using the [Custom Roles API](/reference/roles/custom-role/create). ![Create a custom role](https://images.workoscdn.com/images/fde65b6a-3a74-44bb-afc3-364e8a2041f1.png?auto=format&fit=clip&q=50) #### Custom role slugs Every custom role is identified by a `slug` that is unique within the organization. Slugs may only contain lowercase letters, numbers, hyphens, and underscores, and may not have leading, trailing, or consecutive separators. When creating a custom role via the [API](/reference/roles/custom-role/create), the `slug` field is optional: - **If you provide a `slug`**, it must begin with the `org-` prefix (for example, `org-billing-admin`). This prefix distinguishes organization-scoped custom roles from environment-level roles and is required for any explicitly supplied slug. - **If you omit the `slug`**, WorkOS generates one for you by combining a normalized form of the role's `name` with a 6-character suffix derived from the role's ID. For example, a role named `Billing Admin` would receive a slug like `billing-admin-a1b2c3`. The suffix guarantees uniqueness even when multiple roles share the same name, and auto-generated slugs do not include the `org-` prefix. Auto-generated slugs normalize the role name by converting it to lowercase, converting whitespace to hyphens, removing characters outside `[a-z0-9_-]`, and collapsing repeated separators. The name portion is truncated if necessary so the full slug stays within the maximum slug length. Slugs are immutable after creation, so choose an explicit `slug` if you need a stable, human-readable identifier to reference in your code; otherwise the auto-generated slug is a good default. When creating a role in the WorkOS Dashboard, the slug field is pre-filled from the name as you type and can be edited before submission. ### Custom role configuration Once you create the first role for an organization, that organization will have its own [default role](/authkit/roles-and-permissions/configure-roles-and-permissions/default-role) and [priority order](/authkit/roles-and-permissions/configure-roles-and-permissions/priority-order), independent from the environment. New roles added to the environment will be available to the organization and placed at the bottom of the organization's role priority order. ### Using custom roles Like environment-level roles, custom roles can be used in [role assignment](/authkit/roles-and-permissions/role-assignment), [sessions](/authkit/roles-and-permissions/role-aware-sessions), and the [organization membership API](/reference/authkit/organization-membership). No additional action is required to enable this behavior after creating custom roles. ### Deleting an environment role When attempting to delete an environment role that's the default role for one or more organizations, you'll be prompted to select a new default role for all affected organizations. Organization members previously assigned the deleted role will be assigned the new organization default role. ![Select a replacement role](https://images.workoscdn.com/images/5e6f3e51-5de5-4bb1-a850-52b2196282b9.png?auto=format&fit=clip&q=50) ### Configuration Configure roles and permissions ## Overview A role represents a logical grouping of permissions, defining access control levels for users within your application. Roles are identified by unique, immutable slugs and are assigned to users via [organization memberships](/authkit/users-organizations/organizations). Role assignments can be sourced manually or from Identity Provider (IdP) group mappings (SSO or Directory Sync). Permissions grant users privileged access to resources and actions in your application and are referenced in your code by unique, immutable slugs. A permission can be assigned to any number of roles. > Role and permission configuration applies to [all integrations](/rbac/integration). --- ## Configure roles Roles alone can be sufficient when your application only requires very coarse-grained access control. This is suitable if users only need to be separated into broad categories and there is minimal overlap between roles. Simple roles can be easier to manage, but are less flexible for complex access control scenarios. ![Roles section WorkOS Dashboard](https://images.workoscdn.com/images/09c8fb23-5748-4236-914e-79849ac03a9a.png?auto=format&fit=clip&q=50) You can manage roles in the _Authorization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/environment/authorization/) or using the [Roles API](/reference/roles). Role slugs are immutable and cannot be changed after creation. Environment role slugs are unique within an environment. [Custom role](/rbac/custom-roles) slugs are unique within an organization. ### Default role Role configuration occurs at the environment level. Each environment is seeded with a default `member` role, which is automatically assigned to every organization member. This default role cannot be deleted, but any role can be set as the default. If you need to set default roles or other role configurations at the organization level, refer to the [Custom roles](/rbac/custom-roles) section. ### Multiple roles All [integrations](/rbac/integration) support multiple roles across directory users, SSO profiles, and organization memberships. For any user, if role(s) are not explicit set, they will receive the default role. Multiple roles is disabled by default. To manage this setting, open the [Authorization](https://dashboard.workos.com/environment/authorization/configuration) configuration page and scroll to the _Multiple Roles_ section. > Multiple roles is an **environment-level** setting and applies to all organizations in that environment. ### Priority order Role priority order is used for [IdP role assignment](/rbac/idp-role-assignment) to resolve conflicts when a user belongs to multiple mapped groups. The highest-priority role wins. Priority order also determines which role will be assigned to users when migrating from a multiple roles to single role configuration in the environment. ### Delete roles When roles are deleted: - **Single-role (default):** All affected organization memberships, SSO profiles, and directory users are reassigned to the **default role**. - **Multiple-roles:** The deleted role is **removed** from each organization membership that has it, any other roles on the membership remain intact. Deletion is asynchronous, so updates may take a moment to propagate. > **Tip:** To migrate from one default role to another, set the new default, then delete the old one—users will be reassigned automatically. --- ## Configure permissions Permissions allow for more detailed and flexible management of access. They are particularly useful when: - You anticipate the need to frequently modify access rights or introduce new roles. - There is significant overlap in access rights between different roles, but with some variations. - You want to minimize code changes when modifying access rights. By abstracting access control checks to permissions, you can add or modify roles and their access rights without changing the application code. ### Create permissions You can manage permissions in the _Authorization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/environment/authorization/permissions) or using the [Permissions API](/reference/roles/permission). When configuring permissions, we recommend: - Defining a common naming scheme to use across all permissions for your application. Consider separating the resource and action with a delimiter, such as `users:view`. The following delimiters are permitted: `-.:_*`. - Keep permission slugs clear and concise. When assigned to roles, these slugs will included as part of session cookies in the [session JWT claims](/authkit/sessions/integrating-sessions/access-token), which is limited to a maximum size of 4KB in many modern web browsers. ### Assign permissions to roles Permissions can be assigned when creating a new role or when editing an existing role. ![Assign permissions to a role](https://images.workoscdn.com/images/f6fd6d9a-a7b0-4df7-908b-b657e669a3dc.png?auto=format&fit=clip&q=50) ## Pipes {#pipes} ### Pipes Enable your customers to connect their third-party accounts to your application. ## Introduction Pipes allows your users to securely connect their third-party accounts to your application. With Pipes, you can easily integrate with popular services like GitHub, Slack, Google, Salesforce, and many more without managing OAuth flows, token refresh logic, or credential storage. ## Configuring providers To make an provider available to your users, you will need to configure it in the WorkOS Dashboard. Visit the _Pipes_ section of the WorkOS Dashboard to get started. Click _Connect provider_ then choose the provider from the list. If you don't see the provider you need, you can [define a custom provider](/pipes/custom-providers) or reach out to [our team](mailto:support@workos.com). ### Custom Credentials Configure the provider with your own OAuth credentials: 1. **Create an OAuth application** within the provider's dashboard. 1. You can find instructions on setting up the provider in the documentation section of the setup modal. 2. Use the provided **redirect URI** when configuring the provider. 3. Set the **client ID and secret** from the provider. 4. Specify the required **scopes** for your application. 1. You may need to set these scopes in the provider configuration as well. 5. Provide an optional **description**. This will be used in the widget to inform users on how your application will use their data from the provider. Commonly used scopes are provided in-line, but you should consult each provider's documentation for the full list of available scopes. ## Provider management in your application The [Pipes Widget](/widgets/pipes) provides a pre-built UI for users to connect and manage their connected accounts. The widget shows the user which providers are available, and lets them easily initiate the authorization flow. It communicates with the WorkOS API and stores the connection information for the user. If there's ever a problem with the user's access token, the widget will let them know they need to reauthorize. ![Pipes widget screenshot](https://images.workoscdn.com/images/e84a33bb-0510-4d85-9041-33b1a0ce938c.png?auto=format&fit=clip&q=50) > The description in the widget is set in the provider's configuration in the WorkOS Dashboard. ## Fetching access tokens Once a user has connected a provider, you can [fetch access tokens](/reference/pipes) from your backend to make API calls to the connected service on their behalf. Pipes takes care of refreshing the token if needed, so you'll always have a fresh token. If there's a problem with the token, the endpoint will return information about the issue so you can direct the user to the correct it. This may require sending the user to re-authorize directly or via the page with the Pipes widget. ### Providers Explore the third-party providers available for Pipes integrations. Configure providers and find setup instructions in the [dashboard](https://dashboard.workos.com/environment/pipes). ### Organization-scoped providers Per-organization customization for a Pipe provider's scopes, credentials, and enablement. ## Overview A provider is generally configured once and made available with the same scopes and credentials for everyone. But some organizations have specific requirements. Organization-scoped providers let one organization override any of three things: - whether the provider is **enabled** - the **scopes** it requests - the OAuth **credentials** it uses This lets an organization's IT admin match their own security requirements — say, allowing only a subset of scopes, or requiring connections through the organization's own OAuth application. ## Configure organization credentials Most providers use an OAuth application you set up and control. Other providers require each organization to use its own credentials, so the customer authenticates against its own account. For these, set the provider to use organization credentials; each organization must then provide its own client ID and secret to enable the provider for its users. > Until an organization configures its credentials, that organization's users > can't connect. ![A provider's OAuth dialog in the WorkOS Dashboard with Customer credentials selected, showing default scopes and a description field, where each organization supplies its own OAuth credentials.](https://images.workoscdn.com/images/653860df-3523-4378-a069-9960768c6ecc.png?auto=format&fit=clip&q=50) ## Configure provider settings An organization's IT admin configures these settings through one of two surfaces you provide: the drop-in Pipes Admin widget, or the management API if you want to build your own UI. ### Management widget The [Pipes Admin widget](/widgets/pipes-admin) lets an admin tailor providers to their organization's needs. Admins need the `widgets:pipes:manage` permission. ### API To build your own UI instead, configure overrides through the API. Create or update one with a single request: See the [Configure a provider for an organization](/reference/pipes/provider/configure) endpoint for every field and response. ## View organization-scoped providers in the dashboard The WorkOS Dashboard shows which organizations use each provider, and who has disabled one or overridden its scopes. Open a provider's Organizations tab to see every organization that overrides it, and its status. ![The Organizations tab on a provider's detail page in the WorkOS Dashboard, listing each organization with its status — some enabled, some disabled — plus any scope overrides and last active time.](https://images.workoscdn.com/images/c9474dfc-8fb4-4eaa-a877-03a115719712.png?auto=format&fit=clip&q=50) Open an organization's Pipes tab to see the providers and overrides configured for it. ![An organization's Pipes tab in the WorkOS Dashboard, listing the providers available to that organization with each one's status — some enabled, one disabled — and any overrides.](https://images.workoscdn.com/images/38fce322-cb61-44db-9b65-f3e005fcb263.png?auto=format&fit=clip&q=50) ### Custom providers Define your own OAuth provider in Pipes when the one you need isn't in the WorkOS catalog. ## Introduction Custom providers let you connect an OAuth provider that isn't in the WorkOS catalog. Instead of choosing a pre-built provider, you supply the provider's OAuth endpoints and settings yourself. Once configured, a custom provider works just like a catalog provider: it appears in the [Pipes widget](/widgets/pipes), your users authorize it, and you [fetch access tokens](/reference/pipes) from your backend. A custom provider is different from [custom credentials](/pipes). Custom credentials let you use your own OAuth application with a provider that WorkOS already supports. A custom provider lets you define a provider that WorkOS doesn't yet support at all. ## Create a custom provider Open the [Pipes](https://dashboard.workos.com/environment/pipes) section of the WorkOS Dashboard and click _Connect provider_, then choose _Add a custom provider_. The wizard walks through the configuration in four steps. 1. **Provider details.** Enter a **name** for the provider, an optional **description** shown to users in the widget, and an **icon**. 2. **OAuth endpoints.** Enter the provider's **authorization URL** and **token URL**. If the provider issues refresh tokens from a different endpoint, set the **refresh token URL** as well. 3. **Credentials.** Create an OAuth application in the provider's dashboard and register the **redirect URI** shown in the wizard. Then enter the **client ID** and, if the provider requires one, the **client secret**. 4. **Scopes.** Add the scopes your application needs. Users grant these scopes when they authorize the connection. ## OAuth configuration reference Most providers work with the default settings, but you can adjust how WorkOS builds the authorization request and exchanges tokens to match your provider's requirements. | Field | Description | | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | **Name** | The display name shown in the dashboard and the Pipes widget. | | **Slug** | A unique identifier for the provider within your environment. | | **Description** | Optional text shown to users in the widget describing how their data is used. | | **Icon** | The icon shown next to the provider in the widget. | | **Authorization URL** | The endpoint users are redirected to in order to authorize the connection. | | **Token URL** | The endpoint WorkOS calls to exchange an authorization code for tokens. | | **Refresh token URL** | Optional. The endpoint WorkOS calls to refresh tokens, if different from the token URL. | | **Scopes** | The scopes requested during authorization. | | **Scopes required** | Whether at least one scope must be requested when authorizing. | | **Scope separator** | The character used to join multiple scopes in the request. Most providers use a space; some use a comma. | | **Client secret required** | Whether the provider requires a client secret. Disable for providers that authorize with PKCE only. | | **PKCE enabled** | Whether to use PKCE (with the `S256` challenge method) during the authorization flow. | | **Authenticate via** | How WorkOS sends client credentials when exchanging and refreshing tokens: in the **request body** or as a **basic authorization header**. | | **Token body content type** | The content type WorkOS uses for the token request body, such as `application/x-www-form-urlencoded` or `application/json`. | | **Additional authorization parameters** | Extra key-value pairs appended to the authorization URL, for providers that require provider-specific parameters. | ## Connect and fetch access tokens A custom provider appears in the [Pipes widget](/widgets/pipes) alongside your other providers. Users connect their account through the widget, which manages the authorization flow and stores the connection. Once a user has connected the provider, [fetch access tokens](/reference/pipes) from your backend to call the provider's API on their behalf. Pipes refreshes the token when needed, so you always have a fresh token. ## Edit or delete a custom provider Edit a custom provider's configuration at any time from its settings in the [Pipes](https://dashboard.workos.com/environment/pipes) section of the dashboard. Deleting a custom provider also removes its connected accounts. Existing access tokens stop working, and users will no longer see the provider in the widget. ### API key providers Connect providers that authenticate with an API key instead of OAuth. ## Overview Some providers authenticate with a single opaque API key instead of OAuth. Pipes supports these as a first-class authentication method: your users provide their key, WorkOS stores it securely, and you retrieve it from your backend using the same flow you already use for OAuth access tokens. ## Configuring an API key provider Visit the _Pipes_ section of the WorkOS Dashboard and click _Connect provider_, then choose the provider from the list. When adding a provider, you choose a single authentication method for the integration. When you choose API key, the only field you can set is an optional **description**, which is shown to your users in the widget to explain how your application will use their data. ![The Pipes "Add provider" modal showing the OAuth/API key method choice, with API key selected.](https://images.workoscdn.com/images/a53bc846-bc3e-411b-bdb9-990c6e650c2d.png?auto=format&fit=clip&q=50) > Organization admins can enable or disable an API key provider for their own > organization through [organization-scoped providers](/pipes/organization-scoped-providers). > There are no credentials or scopes to override—the key is supplied per user > when they connect. ## Setting an API key Users can set their key through the [Pipes widget](/widgets/pipes), which renders an API key entry form for any provider configured to use API keys. They paste their key and submit it; WorkOS stores the credential and the widget then shows the last four characters so they can confirm which key is connected and rotate it later. ![Pipes widget showing the API key entry form for an API key provider](https://images.workoscdn.com/images/aae36945-3ec1-478b-870a-bc401b7013ff.png?auto=format&fit=clip&q=50) You can optionally set or rotate a user's key from your backend with the [upsert API key](/reference/pipes/connected-account/upsert-api-key) endpoint. The same endpoint handles both the initial install and subsequent rotations—supplying a new secret replaces the stored one. ## Retrieving credentials Once a user has connected an API key provider, fetch their credential from your backend with the [vend credentials](/reference/pipes/access-token/vend-credentials) endpoint. ## Migrations {#migrate} ### Migrate from Supabase Auth Learn how to migrate users from Supabase Auth. ## Introduction The AuthKit API allows you to migrate your existing user data from a variety of existing sources. In this guide, we will walk through the steps to export, and then import your users from Supabase Auth. --- ## (1) Export Supabase data Supabase stores authentication data directly in your PostgreSQL database under the `auth` schema. This gives you full access to export user data, including password hashes, through direct database queries. ### Export users via SQL You can export users by querying the `auth.users` table directly in the [Supabase SQL Editor](https://supabase.com/docs/guides/database/overview#the-sql-editor) or by using a database client connected to your Supabase project. ```sql title="Export users from Supabase" SELECT id, email, encrypted_password, email_confirmed_at, phone, phone_confirmed_at, raw_user_meta_data, created_at FROM auth.users; ``` For a complete export that includes social login identities, join with the `auth.identities` table. ```sql title="Export users with social logins" SELECT u.id, u.email, u.encrypted_password, u.email_confirmed_at IS NOT NULL as email_verified, u.raw_user_meta_data->>'full_name' as full_name, u.raw_user_meta_data->>'name' as name, i.provider, i.provider_id FROM auth.users u LEFT JOIN auth.identities i ON u.id = i.user_id; ``` You can also export this data using `pg_dump` with your Supabase connection string, which will include the entire `auth` schema. ### Export passwords Supabase stores password hashes in the `encrypted_password` column of the `auth.users` table using the [bcrypt algorithm](https://en.wikipedia.org/wiki/Bcrypt). Unlike some other providers, Supabase gives you direct database access, so you can export password hashes without needing to contact support. --- ## (2) Import users into WorkOS ### Using the WorkOS migrations CLI The fastest way to import users is with the CLI: ```bash npx workos migrations import --csv supabase-users.csv ``` Or for a guided experience: `npx workos migrations wizard` Alternatively, with the data from your Supabase export, you can use the [Create User API](/reference/authkit/user/create) to import each user. The API is rate-limited, so for large migrations implement batching with appropriate delays. See the [rate limits documentation](/reference/rate-limits) for more information. Use the following mapping from Supabase fields to WorkOS API parameters: | Supabase | | WorkOS API | | ---------------------------------- | --- | --------------------------------- | | `email` | → | `email` | | `email_confirmed_at IS NOT NULL` | → | `email_verified` | | `raw_user_meta_data->>'full_name'` | → | `first_name`, `last_name` (split) | Here's an example migration script: ```typescript import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); interface SupabaseUser { email: string; email_verified: boolean; full_name?: string; // Omit this field if you are not importing passwords encrypted_password?: string; } function splitName(fullName?: string): { firstName?: string; lastName?: string; } { fullName = fullName?.trim(); if (!fullName) return {}; const parts = fullName.split(/\s+/); if (parts.length === 1) return { firstName: parts[0] }; return { firstName: parts[0], lastName: parts.slice(1).join(' '), }; } async function migrateUsers(supabaseUsers: SupabaseUser[]) { for (const user of supabaseUsers) { try { const { firstName, lastName } = splitName(user.full_name); const workosUser = await workos.userManagement.createUser({ email: user.email, emailVerified: user.email_verified, firstName, lastName, // Import the bcrypt password hash directly // Omit these fields if you are not importing passwords passwordHash: user.encrypted_password, passwordHashType: 'bcrypt', }); console.log(`Migrated user: ${user.email} -> ${workosUser.id}`); } catch (error) { console.error(`Failed to migrate user ${user.email}:`, error); } } } ``` ### Import passwords Supabase uses the bcrypt password hashing algorithm, which WorkOS supports. You can import password hashes during [user creation](/reference/authkit/user/create) or later using the [Update User API](/reference/authkit/user/update). Pass the following parameters to the API: - The `password_hash_type` set to `'bcrypt'` - The `password_hash` set to the `encrypted_password` value from your Supabase export Once imported, users can continue to sign in with their existing password without needing to reset it. ### Migrate social auth users If you have users who signed in through Supabase using social auth providers like [Google](/integrations/google-oauth) or [Microsoft](/integrations/microsoft-oauth), those users can continue to sign in with those providers after migration. Check out the [integrations](/integrations) page for guidance on configuring the relevant provider's client credentials. After your provider is configured, users can sign in with their provider credentials and will be automatically linked to a WorkOS user. WorkOS uses the **email address** from the social auth provider to determine this match. > Some users may need to verify their email address if email verification is enabled in your environment's authentication settings. Email verification behavior varies depending on whether the provider is known to verify email addresses. For example, users signing in using Google OAuth with a `gmail.com` email domain will not need to perform the extra verification step. --- ## (3) Special considerations There are several differences between Supabase Auth and WorkOS that you should consider when planning your migration. ### Organizations and multi-tenancy Supabase Auth does not have native support for organizations or multi-tenancy. Many Supabase applications implement multi-tenancy using Row Level Security (RLS) policies with a `tenant_id` column or by storing tenant information in `app_metadata`. WorkOS provides native [Organizations](/reference/organization) designed specifically for B2B applications. When migrating, you can: 1. Create Organizations using the [Create Organization API](/reference/organization/create) 2. Add users to their organizations using the [Organization Membership API](/reference/authkit/organization-membership/create) 3. Assign roles using the `roleSlug` parameter if you're using [roles and permissions](/authkit/roles-and-permissions) If you stored tenant IDs in Supabase's `app_metadata`, you can use those values to map users to their respective organizations: ```typescript import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); interface TenantMapping { supabaseTenantId: string; workosOrgId: string; } async function createMemberships( userIdMap: Map, tenantMappings: TenantMapping[], supabaseUsers: Array<{ id: string; app_metadata: { tenant_id?: string }; }>, ) { for (const user of supabaseUsers) { const tenantId = user.app_metadata?.tenant_id; if (!tenantId) continue; const workosUserId = userIdMap.get(user.id); const orgMapping = tenantMappings.find( (t) => t.supabaseTenantId === tenantId, ); if (!workosUserId || !orgMapping) continue; try { await workos.userManagement.createOrganizationMembership({ userId: workosUserId, organizationId: orgMapping.workosOrgId, }); } catch (error) { console.error(`Failed to create membership for user ${user.id}:`, error); } } } ``` ### Multi-Factor Authentication Supabase Auth supports [TOTP-based MFA](https://supabase.com/docs/guides/auth/auth-mfa) using authenticator apps and [Phone MFA](https://supabase.com/docs/guides/auth/auth-mfa/phone) using SMS codes. WorkOS supports TOTP-based MFA but does not support SMS-based second factors due to known security vulnerabilities with SMS, such as SIM swap attacks. Users who have enrolled TOTP factors in Supabase will need to re-enroll in MFA after migration, as TOTP secrets cannot be exported from Supabase. Users who were using SMS-based MFA will need to switch to TOTP-based authentication or use [email-based Magic Auth](/authkit/magic-auth) as an alternative. See the [MFA guide](/authkit/mfa) for more information on enrolling users. ### Enterprise SSO Both Supabase Auth and WorkOS support [SAML 2.0](https://supabase.com/docs/guides/auth/enterprise-sso/auth-sso-saml) for enterprise single sign-on. If you're currently using Supabase's SSO features, WorkOS offers equivalent and expanded capabilities through [Single Sign-On](/sso). When migrating enterprise customers who use SSO, you'll need to coordinate with them to reconfigure their Identity Provider (IdP) to point to WorkOS instead of Supabase. WorkOS provides [comprehensive documentation](/sso) for setting up SSO connections with various providers including Okta, Azure AD, and Google Workspace. ### Passwordless authentication Supabase supports [Magic Links](https://supabase.com/docs/guides/auth/auth-magic-link) and [OTP-based passwordless login](https://supabase.com/docs/guides/auth/passwordless-login/auth-email-otp). WorkOS provides similar functionality through [Magic Auth](/authkit/magic-auth), which delivers secure, one-click email-based authentication. Additionally, WorkOS supports [Passkeys](/authkit/passkeys) (WebAuthn) through AuthKit's hosted UI, offering: - **Progressive enrollment**: Users with password-based accounts can be prompted to create passkeys - **MFA integration**: Passkeys serve as both first and second factors when MFA is enabled - **Secure authentication**: Using biometric or PIN verification on the user's device ### Handling interim new users If your application allows users to sign up at any time, [consider the timing of your migration](/migrate/other-services/4-handling-interim-new-users). Users who sign up after you've exported data from Supabase but before you've switched to WorkOS for authentication will be omitted from the migration. Two main strategies to handle this: #### (A) Disable signups during migration Schedule an appropriate time for the migration and temporarily disable signup functionality using a feature flag. After the migration is complete and your application is using WorkOS for authentication, re-enable signups. #### (B) Use a dual-write strategy For applications that cannot disable signups, implement a dual-write strategy. When a new user signs up, create records in both Supabase and WorkOS using the [Create User API](/reference/authkit/user/create). This keeps WorkOS synchronized with new users while you complete the historical migration. Be aware that you'll need to keep user updates (email changes, password changes) synchronized between both systems until the migration is complete. --- ## Next steps With your users imported, you can start using WorkOS to manage authentication for your application. If you haven't already, take a look at the [AuthKit Quick Start guide](/authkit) to learn how to integrate AuthKit into your application. ### Migrate from Stytch Learn how to migrate users and organizations from Stytch. ## Introduction The WorkOS API allows you to migrate your existing user data from a variety of existing sources. In this guide, we will walk through the steps to export and import your B2B users, organizations, and enterprise configurations from Stytch. --- ## (1) Export data from Stytch Stytch allows customers to export organization and member data using their API endpoints. You can [export most data programmatically](https://stytch.com/docs/b2b/guides/migrations/exporting-from-stytch), though password hashes and complete SSO/SCIM connection configurations require contacting Stytch support. ### Exporting organizations and members Use the [Stytch Search Organizations API](https://stytch.com/docs/b2b/api/search-organizations) to retrieve all organizations in your Stytch project, then use the [Stytch Search Members API](https://stytch.com/docs/b2b/api/search-members) to export members for each organization. Both endpoints support pagination for projects with more than 1000 records and have a rate limit of 100 requests per minute. > The following exports B2B Users. To export Consumer Users, consult [this utility from Stytch](https://github.com/stytchauth/stytch-node-export-users). ```typescript title="Export organizations and members from Stytch" import { B2BClient } from 'stytch'; import { writeFile } from 'fs/promises'; const client = new B2BClient({ project_id: process.env.STYTCH_PROJECT_ID, secret: process.env.STYTCH_SECRET, }); async function exportOrganizations() { const allOrganizations: any[] = []; let cursor = ''; do { const response = await client.organizations.search({ cursor, limit: 1000, }); allOrganizations.push(...response.organizations); cursor = response.results_metadata.next_cursor; } while (cursor); return allOrganizations; } async function exportMembers(organizationIds: string[]) { const allMembers: any[] = []; let cursor = ''; do { const response = await client.organizations.members.search({ organization_ids: organizationIds, cursor, limit: 1000, }); allMembers.push(...response.members); cursor = response.results_metadata.next_cursor; } while (cursor); return allMembers; } (async () => { const organizations = await exportOrganizations(); const organizationIds = organizations.map((org) => org.organization_id); console.log(`Found ${organizations.length} organizations`); const members = await exportMembers(organizationIds); console.log(`Found ${members.length} members`); // Export all data to a JSON file await writeFile( 'stytch-b2b-export.json', JSON.stringify({ organizations, members }, null, 2), ); })(); ``` The Organization object includes `organization_id`, `organization_name`, `email_allowed_domains`, `sso_active_connections`, and `scim_active_connection` fields. The Member object includes `member_id`, `email_address`, `name`, `status`, `oauth_registrations`, `sso_registrations`, and `roles` fields. ### Exporting passwords If your Stytch members sign in using password-based authentication, you will need to [contact Stytch support](mailto:support@stytch.com) to export password hashes. After opening a request, they will provide an export of your hashed password data. The timeline for this process can vary. Stytch uses the `scrypt` password hashing algorithm for password storage. When you export passwords through Stytch support, verify the hash format they provide, as WorkOS supports multiple algorithms including `scrypt`, `bcrypt`, and `argon2`. --- ## (2) Import data into WorkOS Once you've obtained the necessary export data from Stytch, you can import it into WorkOS. ### Using the WorkOS migrations CLI The fastest way to import users is with the CLI: ```bash npx workos migrations import --csv stytch-users.csv ``` Or for a guided experience: `npx workos migrations wizard` Alternatively, use the WorkOS API directly. We recommend importing organizations first, then users with their organization memberships. ### Creating organizations Use the [Create Organization API](/reference/organization/create) to import each Stytch organization. Map `organization_name` to `name` and `email_allowed_domains` to `domainData` (with appropriate `state` values). ```typescript title="Import organizations into WorkOS" import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); async function importOrganization(stytchOrg: any) { const domainData = stytchOrg.email_allowed_domains?.map((domain: string) => ({ domain, state: 'pending', // or 'verified' if domains are pre-verified })) || []; const org = await workos.organizations.createOrganization({ name: stytchOrg.organization_name, domainData, }); return org; } // Import all organizations const orgIdMapping = new Map(); for (const stytchOrg of stytchOrganizations) { try { const workosOrg = await importOrganization(stytchOrg); orgIdMapping.set(stytchOrg.organization_id, workosOrg.id); } catch (error: any) { console.error(`[FAILED] ${stytchOrg.organization_name}`, error.message); } } ``` ### Creating users and memberships Use the [Create User API](/reference/authkit/user/create) to import each Stytch member, then use the [Organization Membership API](/reference/authkit/organization-membership/create) to link users to their organizations. You should filter members by status—typically only importing `active` members and potentially re-inviting `invited` or `pending` members. ```typescript title="Import users and create memberships" async function importUser(stytchMember: any) { // Parse name into first and last name const nameParts = stytchMember.name?.split(' ') || []; const firstName = nameParts[0] || ''; const lastName = nameParts.slice(1).join(' ') || ''; const user = await workos.userManagement.createUser({ email: stytchMember.email_address, emailVerified: stytchMember.email_address_verified, firstName, lastName, }); return user; } async function createMembership( workosUserId: string, workosOrgId: string, roleSlug: string = 'member', ) { return await workos.userManagement.createOrganizationMembership({ userId: workosUserId, organizationId: workosOrgId, roleSlug, }); } const userIdMapping = new Map(); for (const stytchMember of stytchMembers) { try { const workosUser = await importUser(stytchMember); userIdMapping.set(stytchMember.member_id, workosUser.id); const workosOrgId = orgIdMapping.get(stytchMember.organization_id); if (workosOrgId) { await createMembership(workosUser.id, workosOrgId); } else { console.warn(`No WorkOS org found for ${stytchMember.email_address}`); } } catch (error: any) { console.error(`[FAILED] ${stytchMember.email_address}`, error.message); } } ``` > User creation is rate-limited. See the [rate limits documentation](/reference/rate-limits) for details. Consider implementing retry logic and batching for large imports, or reach out to [support@workos.com](mailto:support@workos.com) to process large datasets in the background. ### Importing passwords If you exported password hashes from Stytch, you can import them during user creation or later using the [Update User API](/reference/authkit/user/update). Pass the `passwordHashType` parameter (e.g., `'scrypt'`, `'bcrypt'`) and the `passwordHash` value from your Stytch export. Once imported, users can sign in with their existing passwords without performing a password reset. ```typescript title="Import user with password hash" const user = await workos.userManagement.createUser({ email: stytchMember.email_address, emailVerified: stytchMember.email_address_verified, firstName, lastName, passwordHash: stytchPasswordHash, // From Stytch support export passwordHashType: 'scrypt', // Verify the actual format with Stytch support }); ``` --- ## (3) SSO connections Enterprise SSO connections cannot be exported from Stytch, but you can manually reconfigure connections. You have two options: configure each connection through the dashboard, or use the [Admin Portal](/admin-portal) to let customers self-service their SSO setup. The Admin Portal approach is recommended for larger migrations, as it reduces manual work and provides a familiar self-service experience for IT contacts. To manually configure a SAML connection, create the organization (if not already created), then set up a new SAML connection in the dashboard. ```typescript title="Create SSO connection programmatically" import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); // Generate Admin Portal link for customer to self-configure SSO const { link } = await workos.portal.generateLink({ organization: 'org_12345', intent: 'sso', returnUrl: 'https://yourapp.com/admin', }); // Send this link to the customer's IT contact console.log('Admin Portal link:', link); ``` The OIDC process is similar: create the organization, configure a new OIDC connection, obtain the callback URL, and work with the customer's IT team to update their OIDC application configuration. See the [OIDC integration guide](/integrations/oidc) for detailed instructions. For provider-specific guidance, consult the integration guides for [Okta SAML](/integrations/okta-saml), [Microsoft Entra ID SAML](/integrations/entra-id-saml), [Google Workspace SAML](/integrations/google-saml), or [Generic SAML](/integrations/saml). --- ## (4) Directory Sync Like SSO connections, SCIM directory sync connections must be reconfigured. [Directory Sync](/directory-sync) provides real-time user and group provisioning, automatic deprovisioning, custom attribute mapping, and support for 20+ identity providers including [Okta SCIM](/integrations/okta-scim), [Microsoft Entra ID SCIM](/integrations/entra-id-scim), [Google Workspace Directory](/integrations/google-saml), and [Custom SCIM v2.0](/integrations/scim) providers. For each Stytch SCIM connection, create a corresponding Directory Sync connection in the dashboard or using the [Admin Portal](/admin-portal) for self-service setup. ```typescript title="Generate Admin Portal link for Directory Sync" const { link } = await workos.portal.generateLink({ organization: 'org_12345', intent: 'dsync', returnUrl: 'https://yourapp.com/admin', }); ``` WorkOS sends webhooks for directory sync events like `dsync.user.created`, `dsync.user.updated`, `dsync.user.deleted`, and `dsync.group.updated`. Configure webhooks in the dashboard to receive these events and keep your application in sync with directory changes. ```typescript title="Handle directory sync events" app.post('/webhooks/workos', async (req, res) => { const event = req.body; switch (event.event) { case 'dsync.user.created': await createUserFromDirectory(event.data); break; case 'dsync.user.deleted': await deactivateUser(event.data.id); break; case 'dsync.group.updated': await syncGroupMemberships(event.data); break; } res.status(200).send(); }); ``` See the [Directory Sync guide](/directory-sync) for complete implementation details. --- ## (5) Authentication and access control Stytch B2B supports several authentication methods and access control features that have equivalent capabilities in AuthKit, though some migration adjustments are necessary. ### Authentication methods Both Stytch and WorkOS support traditional email and password authentication. After importing your users with their password hashes, users can sign in immediately with their existing credentials. Enable password authentication in the dashboard under the _Authentication_ tab and configure password strength requirements as needed. Stytch's magic link authentication can be replaced with [Magic Auth](/authkit/magic-auth). While Stytch sends clickable magic links via email, Magic Auth sends a six-digit one-time code that users enter manually. Magic Auth codes expire after 10 minutes and are automatically validated by AuthKit. Stytch's email OTP authentication is functionally identical to Magic Auth, so no application logic changes are needed. If your Stytch users sign in through OAuth providers like Google, Microsoft, or GitHub, they can continue using the same providers. After configuring OAuth providers in the dashboard, users can sign in with their social credentials and will be automatically linked to their user account based on email address matching. In the dashboard: 1. Navigate to Authentication > OAuth providers 2. Select the provider (Google, Microsoft, GitHub, etc.) 3. Add OAuth client credentials (Client ID and Secret) 4. Copy the redirect URI and add to your OAuth app configuration Users authenticate through AuthKit, which handles the OAuth flow. ```typescript title="Configure OAuth providers" const { user } = await workos.userManagement.authenticateWithCode({ code: authorizationCode, clientId: process.env.WORKOS_CLIENT_ID, }); ``` Check the [integrations page](/integrations) for the complete list of supported OAuth providers, including [Google OAuth](/integrations/google-oauth), [Microsoft OAuth](/integrations/microsoft-oauth), and [GitHub OAuth](/integrations/github-oauth). ### Multi-factor authentication Both Stytch and WorkOS support TOTP authenticators like Google Authenticator, Authy, and 1Password. WorkOS supports importing existing TOTP secrets during migration through the [developer-provided TOTP secrets](https://workos.com/changelog/developer-provided-totp-secrets) feature, which allows users to keep their existing authenticator app configurations without re-enrollment. However, [Stytch cannot export TOTP secrets](https://stytch.com/docs/guides/migrations/migrating-user-data-statically#adding-totp-or-biometrics-for-mfa). Users who have TOTP MFA enrolled in Stytch will need to re-enroll their authenticator apps with WorkOS during their next sign-in. Enable MFA in the dashboard under the _Authentication_ tab and configure whether MFA is optional or required. Communicate this change to your users before migration so they're prepared to scan a new QR code or enter a new secret key. While Stytch supports SMS-based MFA, WorkOS does not due to known security vulnerabilities with SMS (SIM swapping, interception, etc.). Users who currently have SMS-based MFA will need to switch to TOTP authenticators, email-based Magic Auth, or modern biometric [Passkeys](/authkit/passkeys). See the [MFA guide](/authkit/mfa) for enrollment flows and implementation details. ### Roles and sessions Stytch B2B provides RBAC with custom resources, roles, and actions. WorkOS offers similar capabilities through [roles and permissions](/authkit/roles-and-permissions). When migrating, identify your roles defined in Stytch, create equivalent roles in the dashboard, and assign roles during migration by specifying the `roleSlug` parameter when creating organization memberships. If your Stytch implementation uses complex RBAC policies with custom resources and actions, you may need to simplify to standard roles or implement custom authorization in your application logic. ```typescript title="Assign roles during migration" const roleMapping = { stytch_admin: 'admin', stytch_member: 'member', custom_role_123: 'manager', }; await workos.userManagement.createOrganizationMembership({ userId: workosUserId, organizationId: workosOrgId, roleSlug: roleMapping[stytchMember.roles[0].role_id] || 'member', }); ``` JWT-based session tokens are used for authentication state. Your application will need to handle these session tokens. Use [an SDK](/sdks) to verify, extract user context (user ID, organization ID, role), and implement token refresh logic if using long-lived sessions. ```typescript title="Handle WorkOS sessions" import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); const { user, organizationId, role } = await workos.userManagement.authenticateWithCode({ code: authorizationCode, clientId: process.env.WORKOS_CLIENT_ID, }); // Store session in your application req.session.userId = user.id; req.session.organizationId = organizationId; req.session.role = role; ``` See the [AuthKit guide](/authkit) for complete session management implementation. --- ## Next steps Be sure to understand how to [handle interim new users](/migrate/other-services/4-handling-interim-new-users) for managing users who sign up during your migration process. After completing your migration to WorkOS, you can take advantage of additional features: - **[Audit Logs](/audit-logs)**: Track security-relevant events across your application - **[Radar](/authkit/radar)**: Protect against bots, fraud, and abuse - **[Vault](/vault)**: Encrypt, store, and control access to sensitive data If you haven't already, check out the [AuthKit Quick Start guide](/authkit) to learn how to integrate WorkOS into your application. For questions or assistance with your migration, contact [support@workos.com](mailto:support@workos.com). ### Migrate from other services Learn how to export and import users from your own data store. ## Introduction The WorkOS AuthKit API allows you to migrate your existing user data from a variety of sources. In this guide, we'll walk through the steps to export, and then import users from your own data store. ## (1) Exporting data While moving authentication related metadata to WorkOS, most applications will continue to store certain user information in their data store. This common subset of data will usually be the following: | Field | Description | Status | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------- | | Email | The user's email address. Used for various authentication and verification purposes. | Required | | First Name | The user's first, or given name. | Optional | | Last Name | The user's last, or family name. | Optional | | Verification Status | The user's email verification status if they have gone through a verification flow. Assumed as "not verified" unless supplied. | Optional | | Password | The user's password hash, if they use password-based authentication. | Optional | While preparing the migration, you'll want to ensure this information is programmatically available for use in the import step, this can mean: - Exporting the relevant data to a file such as JSON or CSV. - Allowing the data to be queried from the data store directly. After the data is accessible, we can configure the import. --- ## (2) Importing Users into WorkOS Now that the User data is available, we can import it into WorkOS. > For migrations involving more than 200,000 users or organizations, contact [support@workos.com](mailto:support@workos.com) to coordinate a managed import. ### Before you begin: disable webhook delivery If you have [webhook endpoints](/reference/webhooks) configured, temporarily disable delivery for the duration of the bulk import to avoid overwhelming your webhook consumers with high volumes of `user.created`, `organization.created`, and `organization_membership.created` events. You can disable a webhook endpoint using the [Update Webhook Endpoint API](/reference/webhooks/update): ```bash curl -X PATCH https://api.workos.com/webhook_endpoints/{id} \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "status": "disabled" }' ``` Re-enable the endpoint after the import is complete by setting `status` back to `"enabled"`. ### Using the WorkOS migrations CLI The WorkOS CLI includes a migrations tool that can import users from a CSV file: ```bash npx workos migrations import --csv users.csv ``` For a guided, interactive experience: ```bash npx workos migrations wizard ``` The CLI handles batching and rate limiting automatically. ### Creating users For each of your users, you can call the WorkOS [Create User API](/reference/authkit/user/create). This will create a matching [User object](/reference/authkit/user) within WorkOS. A successful response will include a new WorkOS user ID, most apps will want to persist this WorkOS user ID alongside the application-local user object. ```json { "object": "user", /* highlight-start */ "id": "user_01E4ZCR3C56J083X43JQXF3JK5", /* highlight-end */ "email": "marcelina.davis@gmail.com", "firstName": "Marcelina", "lastName": "Davis", "emailVerified": true, "createdAt": "2021-06-25T19:07:33.155Z", "updatedAt": "2021-06-25T19:07:33.155Z" } ``` > **Email addresses are unique** to each WorkOS environment. If you have a subset of users already in WorkOS, you may need to handle constraint violation errors. There are now several options on how to proceed, depending on your application's needs: ### Importing passwords If your users currently use password-based authentication, you can import existing password hashes during the [users creation](/reference/authkit/user/create) process, or later using the WorkOS [Update User API](/reference/authkit/user/update). WorkOS currently supports the following password hashing algorithms: - `bcrypt` - `scrypt` - `firebase-scrypt` - `ssha` - `pbkdf2` - `argon2` For `scrypt` and `pbkdf2` passwords, use the PHC string format. The hash and salt should be B64 encoded: trim the `=` characters that represent Base64 padding. Using a PHC-formatting library, like Node's [`@phc/format`](https://www.npmjs.com/package/@phc/format), should handle this for you. The following table shows how to map the `scrypt` and `pbkdf2` parameters to the PHC parameters. #### scrypt | `Scrypt` value | | PHC hash parameter | | ----------------- | --- | ------------------ | | `key length` | → | `kl` | | `cost` | → | `n` | | `rounds` | → | `r` | | `parallelization` | → | `p` | A valid `scrypt` PHC formatted string looks like this: ```txt $scrypt$v=1$n=16384,r=8,p=1,kl=64$Swhqd4iUYTtWfbCYIPeuMw$q7pfdBQMJujd5FX/qX+ozM2O6aNqP+mo1ZnHGH15XM2vlhroQfPA037UpbdfpH4H66OrSPjsUhfkAMuNoBiQvw ``` #### pbkdf2 | `pbkdf2` value | | PHC hash parameter | | -------------- | --- | ------------------ | | `digest` | → | `d` | | `iterations` | → | `i` | For `pbkdf2` allowed values for digest are `sha256` or `sha512`. The value for iterations is dependent on digest. For `sha256` there is a minimum of 600,000 iterations and a max of 1,000,000. For `sha512` there is a minimum of 210,000 and a max of 1,000,000. A valid `pbkdf2` PHC formatted string looks like this: ```txt $pbkdf2$i=600000,d=sha256$T2ptRFh6MXhDQVh2SWZuUGdpQXBUTg$xXiyTisD7390NijyCv5ICMhFW4eDuMlzypRoLGLyIvA ``` #### argon2 | `argon2` value | | PHC hash parameter | | -------------- | --- | ------------------ | | `variant` | → | algorithm id | | `version` | → | `v` | | `memory` | → | `m` | | `time` | → | `t` | | `parallelism` | → | `p` | The variant should be `argon2id`, but older supported variants include `argon2d` and `argon2i`. The version must be `19`. The following memory, time (iterations), and parallelism settings are based on [OWASP recommendations](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id). Memory is specified in KiB with a minimum of 4,096 KiB (4 MiB) and maximum of 262,144 KiB (256 MiB). For time, there is a minimum of 1 iteration and a maximum of 5 iterations, except for `argon2i` which has a minimum of 3 iterations. Parallelism ranges from 1 to 8 threads. If your requirements fall outside of these guidelines, please [contact support](mailto:support@workos.com). A valid `argon2` PHC formatted string looks like this: ```txt $argon2id$v=19$m=65536,t=3,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG ``` For `firebase-scrypt` passwords, refer to the [Firebase Migration guide](/migrate/firebase) for an example of how to format the `password_hash`. For `ssha` passwords, use the following algorithm: 1. Generate a `salt`: random bytes 2. Hash the user's password and the `salt` using the SHA1 algorithm 3. Base64 encode the hash followed by the salt 4. Prepend the string with `{SSHA}` A high-level representation is: `{SSHA}base64(sha1(password + salt) + salt)`. Once imported, users can continue to sign-in with their existing password, **without** having to go through a password reset flow. ### Triggering password resets If you are unable to export passwords from your existing data store, whether for security reasons or other limitations, you can programmatically trigger a password reset flow using the WorkOS [Password Reset API](/reference/authkit/password-reset). This process can be initiated at any time, and doesn't need to happen during the user import process. Some applications may want to remove password-based authentication when switching to WorkOS, in favor of another method like Magic Auth. If this is the case for your application, you can skip dealing with passwords entirely. ### Migrating social auth users If you have users who previously signed in using social auth providers, such as [Google](/integrations/google-oauth) or [Microsoft](/integrations/microsoft-oauth), those users can continue to sign in with those providers after you've migrated to WorkOS. Check out our [integrations](/integrations) page for guidance on configuring the relevant provider's client credentials in WorkOS. After your provider is configured in WorkOS, users can sign in with their provider credentials and will be automatically linked to a WorkOS user. WorkOS uses the **email address** from the social auth provider to determine this match. > Some users may need to verify their email address through WorkOS if email verification is enabled in your WorkOS environment's authentication settings. Email verification behavior varies depending on whether the provider is known to verify email addresses. For example, users signing in using Google OAuth and a `gmail.com` email domain will not need to perform the extra verification step. --- ## (3) Enterprise Connections (SSO) If your application uses enterprise SAML or OIDC connections for SSO, you can migrate them to WorkOS. The best strategy depends on how many connections you have and whether you control the existing SSO infrastructure. ### Choosing a migration strategy ### (A) Fewer than 15 connections — Admin Portal approach For smaller deployments, the simplest path is to recreate each connection in WorkOS and coordinate with each customer's IT team to update their Identity Provider configuration. You can use the [Admin Portal](/admin-portal) to let customers self-service their SSO setup, reducing the coordination burden. For each connection: 1. Create or identify the WorkOS organization matching the existing organization 2. Share the [Admin Portal](/admin-portal) link with the customer's IT team so they can update their IdP configuration to point to WorkOS 3. Watch for the `connection.activated` webhook to roll out the customer to the WorkOS connection ### (B) 15 or more connections — Transparent migration For larger deployments, coordinating with every customer's IT team is impractical. Instead, you can perform a **transparent migration** so that IT admins do not need to reconfigure anything on their end. The approach depends on whether you are migrating from an external identity service or from a homegrown SSO implementation. #### Route 1: Migrating from an external service (proxy approach) If you are migrating from an external identity provider (such as Auth0, or another third-party service), you can place a proxy in front of the service's custom domain to route IdP callback traffic to WorkOS. This approach requires that you have a **custom domain** configured with your current provider (e.g., `auth.your-domain.com`) so that you control the domain routing. ##### Requirements - You have a custom domain configured with your current identity provider - Your SAML enterprise connections do not use SAML Request Signing with the provider's tenant global key pairs - Your SAML enterprise connections do not use SAML Response Encryption with the provider's tenant global key pairs ##### Configuring the callback proxy Once connections are imported into WorkOS, configure a proxy in front of your custom domain to route IdP callback traffic to WorkOS. The proxy intercepts callbacks at your custom domain's callback path and redirects them to your WorkOS custom domain. The proxy flow works as follows: 1. A user authenticates with their IdP, which posts the SAML response or OIDC callback to your custom domain 2. The proxy redirects the callback to WorkOS 3. WorkOS attempts to find a matching connection: - If found, it processes the response and redirects to your application's WorkOS callback - If not found, it redirects back with a `fallback` query parameter, and the proxy forwards the original callback to your existing provider This fallback mechanism ensures zero downtime — connections that haven't been migrated yet continue to work through your existing provider. The proxy can be implemented using Cloudflare redirect and transform rules, a Cloudflare Worker, or any reverse proxy you control. Contact [support@workos.com](mailto:support@workos.com) for a reference implementation and import assistance. > We recommend performing a proof-of-concept in a staging environment before production to de-risk breaking changes in your setup. #### Route 2: Migrating from a homegrown solution (callback modification) If your application has its own SSO implementation where you directly handle IdP callbacks, you already control the callback endpoints. Instead of a proxy, you can modify your existing callback handlers to forward IdP responses to WorkOS using a feature flag mechanism. ##### Preparing connection data The WorkOS migrations CLI can generate CSV templates for your connection data. There are separate templates for SAML and OIDC connections: ```bash npx workos migrations export-template saml_connections --output saml_connections.csv npx workos migrations export-template oidc_connections --output oidc_connections.csv ``` Or, using the interactive wizard: ```bash npx workos migrations wizard ``` Select **Custom CSV** → **Generate a blank CSV template** → **SAML Connections** or **OIDC Connections**. ###### SAML connections CSV | Column | Required | Description | | ------------------------ | -------- | ------------------------------------------------------------------- | | `organizationName` | Yes | Name of the organization | | `organizationId` | Yes | Your existing organization identifier | | `organizationExternalId` | No | External identifier for the organization | | `domains` | No | Semicolon-separated list of domains (e.g., `acme.com;app.acme.com`) | | `idpEntityId` | No | Identity Provider Entity ID | | `idpUrl` | No | Identity Provider SSO URL | | `x509Cert` | No | IdP X.509 signing certificate | | `idpMetadataUrl` | No | IdP metadata URL | | `customEntityId` | No | Custom SP Entity ID | | `customAcsUrl` | No | Custom Assertion Consumer Service URL | | `idpIdAttribute` | No | Attribute used for user identification (e.g., `email`) | | `emailAttribute` | No | SAML attribute for user email | | `firstNameAttribute` | No | SAML attribute for user first name | | `lastNameAttribute` | No | SAML attribute for user last name | | `nameAttribute` | No | SAML attribute for user full name | | `idpInitiatedEnabled` | No | Whether IdP-initiated SSO is enabled | | `requestSigningKey` | No | Key used for signing SAML requests | | `assertionEncryptionKey` | No | Key used for encrypting SAML assertions | | `nameIdEncryptionKey` | No | Key used for encrypting SAML NameID | | `importedId` | No | Original connection ID from your previous provider | ###### OIDC connections CSV | Column | Required | Description | | ------------------------ | -------- | ------------------------------------------------------------------- | | `organizationName` | Yes | Name of the organization | | `organizationId` | Yes | Your existing organization identifier | | `organizationExternalId` | No | External identifier for the organization | | `domains` | No | Semicolon-separated list of domains (e.g., `acme.com;app.acme.com`) | | `clientId` | No | OIDC client ID | | `clientSecret` | No | OIDC client secret | | `discoveryEndpoint` | No | OpenID Connect discovery URL | | `customRedirectUri` | No | Custom redirect URI | | `importedId` | No | Original connection ID from your previous provider | Fill in the appropriate template with your existing connection configurations and send it to [support@workos.com](mailto:support@workos.com) for import. ##### How it works 1. Export your connection configurations using the CSV template above and send to [support@workos.com](mailto:support@workos.com) for import into WorkOS 2. Modify your existing callback endpoint to check a [WorkOS Feature Flag](/feature-flags) before processing the IdP response 3. For organizations flagged for WorkOS, forward the IdP response (SAMLResponse or authorization code) to WorkOS for processing 4. For organizations not yet migrated, continue processing through your existing flow This gives you per-organization control over the migration without requiring IdP reconfiguration. ```typescript title="Callback modification with WorkOS Feature Flags" import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); const featureFlags = workos.featureFlags.createRuntimeClient(); await featureFlags.waitUntilReady({ timeoutMs: 5000 }); async function handleSSOCallback(req: Request): Promise { const organizationId = extractOrganizationFromCallback(req); const useWorkOS = featureFlags.isEnabled('workos-sso-enabled', { organizationId, }); if (useWorkOS) { // Forward the IdP response to WorkOS for processing const { user } = await workos.userManagement.authenticateWithCode({ code: req.query.code, clientId: process.env.WORKOS_CLIENT_ID!, }); return handleWorkOSUser(user); } // Continue with existing SSO flow for non-migrated organizations return handleExistingSSOCallback(req); } ``` ### Gradual rollout with Feature Flags Regardless of which route you use, the authorization URL piece works the same way. You can use [WorkOS Feature Flags](/feature-flags) to control which organizations use WorkOS SSO versus your existing provider during the migration. Create a feature flag (e.g., `workos-sso-enabled`) and target it to specific organizations as you migrate them. ```typescript title="Route SSO based on feature flag" import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); const featureFlags = workos.featureFlags.createRuntimeClient(); await featureFlags.waitUntilReady({ timeoutMs: 5000 }); function getSSOAuthorizationUrl(organizationId: string): string { const useWorkOS = featureFlags.isEnabled('workos-sso-enabled', { organizationId, }); if (useWorkOS) { return workos.userManagement.getAuthorizationUrl({ provider: 'authkit', organizationId, clientId: process.env.WORKOS_CLIENT_ID!, redirectUri: process.env.WORKOS_REDIRECT_URI!, }); } // Fall back to existing SSO provider for organizations not yet migrated return getExistingSSOAuthorizationUrl(organizationId); } ``` This lets you gradually migrate organizations to WorkOS SSO, verify each one works correctly, and roll back individual organizations if needed — all without code deployments. --- ## (4) Handling interim new users Many applications allow users to sign up at any time. If your app offers this feature, then you should consider the timing of your migration. If any users sign up after you've completed importing users into WorkOS, but before you've switched to WorkOS for authentication, then those users will have been omitted from the migration process. There are two main strategies to handle this: ### (A) Disable signups during migration The simplest solution is to schedule an appropriate time for the migration and disable signup while in progress. This may be done using temporary code added to your application and controlled by a feature flagging system. After the migration is complete, your application should be updated to perform authentication using WorkOS, and the signup flag block disabled. This helps to ensure the export/import process captures all active users. ### (B) Use a dual-write strategy For applications that want to avoid disabling signups, a "dual-write" strategy can be used. ![Diagram demonstrating the dual-write process.](https://images.workoscdn.com/images/656fbbac-adb1-4f99-b416-056d80e408ac.png?auto=format&fit=clip&q=80)\[border=false] When a new user signs-up, in addition to creating a user record in the existing user store, the application should also create a matching record in WorkOS using the [Create User API](/reference/authkit/user/create). As time passes, WorkOS will stay consistent with future new users, but a migration will still need to be performed for the historical set of users. You will need to perform the same export and import process into WorkOS, but keeping in mind that some users will already exist in WorkOS as a result from the "dual-write". While this minimizes forms of downtime for your application, there are other complications. For example, if a user updates their email or authentication method, you will need to perform the same update in WorkOS, at least until the migration process is complete. ### Which to choose? Your timeline for completing the migration, along with your user's tolerances for disruption, will affect which strategy makes more sense for your application. Disabling signups, or even sign-in entirely, and doing a "big-bang" migration by moving all users at the same time, could be reasonable for a smaller application. However, larger applications that are on the critical path for their customers may need a more careful path in order to provide consistent access. ## Wrapping-up User management migration complexity can vary, so it is important to consider how existing application constraints will transfer to WorkOS. If you have any questions, reach out to [support@workos.com](mailto:support@workos.com) or via your team's WorkOS Slack channel for more help planning your migration. ### Migrate from Firebase Learn how to migrate users to WorkOS from Firebase. ## Introduction The WorkOS AuthKit API allows you to migrate your existing user data from a variety of existing sources. In this guide, we'll walk through the steps to export your users from Firebase, and then import them into WorkOS. ## (1) Exporting Firebase user data Firebase customers can export their user data using either the [Firebase CLI](https://firebase.google.com/docs/cli/auth#auth-export) or the [Firebase API](https://firebase.google.com/docs/reference). In this guide we'll be using the Firebase CLI, use the following command to retrieve a dump of all users in JSON or CSV format. ```bash title="Exporting users with the Firebase CLI" firebase auth:export --project= --format=json users.json ``` ## (2) Importing users into WorkOS After obtaining your user data from Firebase, it's time to import it into WorkOS. ### Using the WorkOS migrations CLI The fastest way to import users is with the CLI. It transforms the Firebase JSON export into a migration package — including scrypt password hashes, using the hash parameters described in the next section — then imports it: ```bash npx workos migrations export firebase \ --from-file users.json \ --output-dir ./migration-firebase \ --signer-key \ --salt-separator \ --rounds 8 \ --memory-cost 14 npx workos migrations import-package ./migration-firebase ``` Or for a guided experience: `npx workos migrations wizard` Alternatively, use the WorkOS [Create User API](/reference/authkit/user/create) to create a corresponding record in WorkOS for each exported user. Use the following mapping from the Firebase format to parameters in your WorkOS Create User API calls: | Firebase | | WorkOS API | | --------------- | --- | ---------------- | | `email` | → | `email` | | `emailVerified` | → | `email_verified` | | `displayName` | → | `first_name` | | `displayName` | → | `last_name` | ### Importing passwords If your users sign in to your Firebase application using passwords, you can choose to also import those password hashes. Firebase uses a [forked version of `scrypt`](https://firebaseopensource.com/projects/firebase/scrypt/) which can be directly imported during the [user creation](/reference/authkit/user/create) process into WorkOS, or later using the [Update User API](/reference/authkit/user/update). First, retrieve your Firebase project's password hash parameters from the Firebase console following the [export documentation](https://firebase.google.com/docs/cli/auth#password_hash_parameters). These parameters are the `base64_signer_key`, `base64_salt_separator`, `rounds`, and `mem_cost`. Next, retrieve the password salts and hashes for each of your individual Firebase users by running the [Firebase CLI `auth:export` command](https://firebase.google.com/docs/cli/auth#auth-export). Your Firebase users that have a password set will have a `passwordHash` and `salt` field present which will be imported into WorkOS. Finally, you will need to format these parameters into a [PHC-compatible](https://github.com/P-H-C/phc-string-format/blob/5f1e4ec633845d43776849f503f8ce8314b5290c/phc-sf-spec.md) password hash following this Firebase to PHC hash parameter mapping: | Firebase value | | PHC hash parameter | | ----------------------- | --- | ------------------ | | `base64_signer_key` | → | `sk` | | `base64_salt_separator` | → | `ss` | | `rounds` | → | `r` | | `mem_cost` | → | `m` | The hash, salt, along with `sk` and `ss` parameters, should be [B64 encoded](https://github.com/P-H-C/phc-string-format/blob/5f1e4ec633845d43776849f503f8ce8314b5290c/phc-sf-spec.md#b64), which means trimming the `=` characters that represent base64 padding. Using a PHC-formatting library, like [`@phc/format`](https://www.npmjs.com/package/@phc/format) for Node, should handle this for you. ## Other authentication methods Firebase authentication methods vary depending on your specific usage, and corresponding connections can be easily configured in WorkOS. This allows users to continue signing in with the same authentication methods, matching the previous sign in experience. ### Social Auth Providers If your users "Sign in with Google" or similar, you can configure WorkOS to continue using those sign in methods. Migrating these connections involves providing the same client credentials (i.e. Client ID and Client Secret) to WorkOS as configured in Firebase. For more details on supported connections, see the provider-specific integration guides, such as for [Microsoft](/integrations/microsoft-oauth) and [Google](/integrations/google-oauth). Reach out to [support@workos.com](mailto:support@workos.com) if there are additional Social Auth providers you would like to see supported. ### Email Link If your users sign in using [Email Link](https://firebase.google.com/docs/auth/web/email-link-auth), sometimes called "passwordless", you can achieve the same experience by adding WorkOS [Magic Auth](/reference/authkit/magic-auth) to your application. ### OIDC and SAML Enterprise authentication often uses standard protocols such as [OpenID Connect (OIDC)](https://firebase.google.com/docs/auth/web/openid-connect) or [SAML](https://firebase.google.com/docs/auth/web/saml) between your service and identity provider. The same identity providers can be configured in WorkOS, preserving the sign in process familiar to your users. For specific instructions, see the guides on setting up [OIDC](/integrations/oidc) and [SAML](/integrations/saml) connections with WorkOS. ### Migrate from Descope Learn how to migrate users and organizations from Descope. ## Introduction The AuthKit API allows you to migrate your existing user data from a variety of existing sources. In this guide, we will walk through the steps to export, and then import your users from Descope. --- ## (1) Export Descope data Descope allows you to export user data through their [Management API](https://docs.descope.com/api/management/users) or directly from the Descope console. You can export user data programmatically using the [Search Users endpoint](https://docs.descope.com/management/user-management/user-exporting). The `searchAll()` function in the Descope Backend SDKs retrieves a comprehensive list of users. Submitting an empty request payload will return all users: ```bash curl -X POST https://api.descope.com/v1/mgmt/user/search \ -H 'Authorization: Bearer :' \ -H 'Content-Type: application/json' \ -d '{}' ``` Alternatively, you can export users directly from the [Descope console](https://docs.descope.com/management/user-management/user-exporting) by selecting users on the users page and clicking the "Export CSV" button. ### Exporting passwords If your Descope users currently sign in using password-based authentication, and you'd like to import those passwords, you'll need to [contact Descope support](https://docs.descope.com/management/user-management/user-exporting). Descope does not make hashed passwords available through their Backend APIs. After opening a support ticket, Descope can generate a CSV file containing your users' data including password hashes and facilitate a secure data transfer. Descope supports multiple password hashing algorithms including bcrypt, argon2, pbkdf2, and others. When you receive the password export from Descope support, make note of which hashing algorithm was used, as you'll need this information when importing. --- ## (2) Import users into WorkOS Once you've obtained the necessary export data from Descope, you can import your users into WorkOS. ### Using the WorkOS migrations CLI The fastest way to import users is with the CLI: ```bash npx workos migrations import --csv descope-users.csv ``` Or for a guided experience: `npx workos migrations wizard` ### Using WorkOS APIs With the data from Descope's user export, you can use the [Create User API](/reference/authkit/user/create) to import each user. The API is rate-limited, so for large migrations, you may want to implement batching with appropriate delays. You can view the [rate limits](/reference/rate-limits) documentation for more information. Using the fields from the Descope export, use the following mapping from Descope to parameters in your Create User API calls: | Descope | | WorkOS API | | --------------- | --- | ---------------- | | `email` | → | `email` | | `givenName` | → | `first_name` | | `familyName` | → | `last_name` | | `verifiedEmail` | → | `email_verified` | Here's an example migration script: ### Import passwords If you also exported passwords from Descope support, you can import them during the [user creation](/reference/authkit/user/create) process, or later using the [Update User API](/reference/authkit/user/update). WorkOS supports the following password hashing algorithms that Descope uses: - `bcrypt` - `argon2` - `pbkdf2` When importing passwords, pass the following parameters to the WorkOS API based on the hash format Descope provided: - The `password_hash_type` set to the appropriate algorithm (e.g., `'bcrypt'`, `'argon2'`, or `'pbkdf2'`) - The `password_hash` set to the password hash value from your Descope export For `argon2` and `pbkdf2` passwords, WorkOS expects the PHC string format. Refer to the [other services migration guide](/migrate/other-services/2-importing-users-into-workos/importing-passwords) for detailed formatting requirements for these hash types. - | Without passwords ```typescript import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); async function migrateUsers(descopeUsers) { for (const user of descopeUsers) { try { // In the JavaScript SDK, the property names are camelCase const workosUser = await workos.userManagement.createUser({ email: user.email, emailVerified: user.verifiedEmail, firstName: user.givenName, lastName: user.familyName, }); console.log(`Migrated user: ${user.email} -> ${workosUser.id}`); } catch (error) { console.error(`Failed to migrate user ${user.email}:`, error); } } } ``` - | With passwords ```typescript import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); async function migrateUsersWithPasswords(descopeUsers) { for (const user of descopeUsers) { try { const workosUser = await workos.userManagement.createUser({ email: user.email, emailVerified: user.verifiedEmail, firstName: user.givenName, lastName: user.familyName, // Include password hash if available from Descope export passwordHash: user.passwordHash, passwordHashType: user.passwordHashType, // 'bcrypt', 'argon2', or 'pbkdf2' }); console.log( `Migrated user with password: ${user.email} -> ${workosUser.id}`, ); } catch (error) { console.error(`Failed to migrate user ${user.email}:`, error); } } } ``` ### Migrate social auth users If you have users who previously signed in through Descope using social auth providers, such as [Google](/integrations/google-oauth) or [Microsoft](/integrations/microsoft-oauth), those users can continue to sign in with those providers after you've migrated. Check out the [integrations](/integrations) page for guidance on configuring the relevant provider's client credentials. After your provider is configured, users can sign in with their provider credentials and will be automatically linked to a WorkOS user. WorkOS uses the **email address** from the social auth provider to determine this match. > Some users may need to verify their email address through WorkOS if email verification is enabled in your environment's authentication settings. Email verification behavior varies depending on whether the provider is known to verify email addresses. For example, users signing in using Google OAuth and a `gmail.com` email domain will not need to perform the extra verification step. --- ## (3) Organizations Descope has a concept of ["Tenants"](https://docs.descope.com/b2b) which are analogous to [WorkOS Organizations](/reference/organization), in that both represent a B2B customer or organization within your application. ### Creating Organizations If you'd like to export your Descope tenants, you can use the [Descope Management API](https://docs.descope.com/management/tenant-management/sdks) to programmatically retrieve each tenant. You can then call the [Create Organization API](/reference/organization/create) to create matching Organizations in WorkOS. When creating Organizations in WorkOS, you can map the following fields from Descope tenants: | Descope Tenant | | WorkOS Organization | | -------------- | --- | ------------------- | | `name` | → | `name` | | `id` | → | `external_id` | Storing the Descope tenant ID as the `external_id` in WorkOS can help you maintain a reference between the two systems during migration. Here's an example migration script: ```typescript import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); async function migrateOrganizations(descopeTenants) { const orgIdMap = new Map(); for (const tenant of descopeTenants) { try { const workosOrg = await workos.organizations.createOrganization({ name: tenant.name, // Store the Descope tenant ID for reference externalId: tenant.id, }); console.log(`Migrated organization: ${tenant.name} -> ${workosOrg.id}`); // Store this mapping for migrating user memberships later orgIdMap.set(tenant.id, workosOrg.id); } catch (error) { console.error(`Failed to migrate organization ${tenant.name}:`, error); } } return orgIdMap; } ``` ### Adding user memberships Once you've created Organizations in WorkOS, you can add users to their respective organizations using the [Organization Membership API](/reference/authkit/organization-membership/create). In Descope, users can be associated with tenants, and this information is available when you export users via the Search Users API. Use this tenant association data to create the corresponding organization memberships in WorkOS. RBAC capabilities are available through [roles and permissions](/authkit/roles-and-permissions). When migrating, identify your roles defined in Descope, then create equivalent roles in [the dashboard](https://dashboard.workos.com/environment/authorization), and assign roles during migration by specifying the `roleSlug` parameter when creating organization memberships. ```typescript async function migrateMemberships(descopeUserTenants, orgIdMap, userIdMap) { for (const userTenant of descopeUserTenants) { const orgId = orgIdMap.get(userTenant.tenantId); const userId = userIdMap.get(userTenant.userId); if (!orgId || !userId) { console.error(`Missing mapping for user-tenant relationship`); continue; } try { await workos.userManagement.createOrganizationMembership({ userId: userId, organizationId: orgId, // Map Descope roles to WorkOS roles as needed roleSlug: userTenant.roleNames?.[0] || 'member', }); console.log(`Migrated membership: ${userId} -> ${orgId}`); } catch (error) { console.error(`Failed to migrate membership:`, error); } } } ``` --- ## (4) Special considerations There are some differences between the authentication strategies offered by Descope and WorkOS that you should be aware of when planning your migration. ### Multi-Factor Auth Descope supports SMS-based one-time passwords (OTP) for authentication and multi-factor auth. However, WorkOS does not support SMS-based second factors due to known security issues with SMS. Users who have SMS-based authentication or second factors will need to switch to using [email-based Magic Auth](/authkit/magic-auth), or re-enroll in MFA using a [TOTP-based authenticator](/authkit/mfa) instead. ### Passkeys and advanced authentication Descope supports [passkeys](https://docs.descope.com/auth-methods/passkeys) (WebAuthn) for passwordless authentication. [Passkey authentication](/authkit/passkeys) is also available through AuthKit's hosted UI, using the WebAuthn standard. Passkeys offer: - **Progressive enrollment**: Users with password-based accounts can be prompted to create passkeys - **MFA integration**: Passkeys serve as both first and second factors when MFA is enabled - **Secure authentication**: Using biometric or PIN verification on the user's device Note that passkey authentication is currently available through the hosted UI. You'll need to configure a custom domain for your AuthKit environment before enabling passkeys in production. Descope also offers other authentication methods like Magic Links and Enchanted Links. [Magic Auth](/authkit/magic-auth) delivers a similar passwordless email-based authentication experience. ### Enterprise SSO and SCIM Both Descope and WorkOS provide robust enterprise authentication features. If you're currently using Descope's [SSO](https://docs.descope.com/auth-methods/sso) or [SCIM provisioning](https://docs.descope.com/b2b/scim) features, WorkOS offers equivalent capabilities: - [Single Sign-On (SSO)](/sso) - Support for SAML and OIDC providers - [Directory Sync](/directory-sync) - SCIM-based user provisioning from identity providers When migrating enterprise customers who use SSO, you'll need to coordinate with them to reconfigure their Identity Provider (IdP) to point to WorkOS instead of Descope. WorkOS provides [comprehensive documentation](/sso) for setting up SSO connections with various providers. ### Account linking behavior Descope has account linking capabilities that automatically link social accounts with matching verified email addresses. WorkOS also supports automatic account linking based on email addresses. When migrating users who have multiple linked accounts in Descope (e.g., password + Google OAuth), you should: 1. Import the user once with their primary email 2. Configure the relevant social providers 3. When users sign in with their social provider, they will automatically be linked with the accounts based on email match ### Handling interim new users If your application allows users to sign up at any time, you should [consider the timing of your migration](/migrate/other-services/4-handling-interim-new-users). Users who sign up after you've exported data from Descope but before you've switched to WorkOS for authentication will be omitted from the migration. There are two main strategies to handle this: #### (A) Disable signups during migration Schedule an appropriate time for the migration and temporarily disable signup functionality. This can be controlled using a feature flag in your application. After the migration is complete and your application is using WorkOS for authentication, re-enable signups. #### (B) Use a dual-write strategy For applications that cannot disable signups, implement a "dual-write" strategy. When a new user signs up, create records in both your Descope project and WorkOS using the [Create User API](/reference/authkit/user/create). This keeps WorkOS synchronized with new users, though you'll still need to perform the historical user migration. Be aware that you'll need to keep user updates (email changes, password changes) synchronized between both systems until the migration is complete. --- ## Next steps With your users now imported, you can start using WorkOS to manage authentication for your application. If you haven't already, take a look at the [AuthKit Quick Start guide](/authkit) to learn how to integrate AuthKit into your application. ### Migrate from Clerk Learn how to migrate users and organizations from Clerk. ## Introduction The WorkOS AuthKit API allows you to migrate your existing user data from a variety of existing sources. In this guide, we will walk through the steps to export, and then import your users from Clerk. --- ## (1) Export Clerk user data Clerk allows for exporting user data [directly from their API](https://clerk.com/docs/deployments/exporting-users) using their Backend SDK. ### Export passwords If your Clerk users currently sign in using password-based authentication, and you'd like to import those passwords into WorkOS, then you'll need to use the [Clerk backend API](https://clerk.com/changelog/2024-10-23-export-users) to export them with your user data as a CSV file. > Clerk does not make the plaintext passwords available for export. --- ## (2) Import users into WorkOS Once you've obtained the necessary export files, you have two options for importing your user data into WorkOS. ### (A) Using the WorkOS migrations CLI The fastest way to import users into WorkOS is with the CLI. Clerk's export columns (like `primary_email_address` and `password_digest`) aren't in the WorkOS CSV format, so first transform the export into a migration package, then import it: ```bash npx workos migrations export clerk \ --from-file clerk-export.csv \ --output-dir ./migration-clerk npx workos migrations import-package ./migration-clerk ``` This maps Clerk's columns to the WorkOS format, carries bcrypt password digests through, and imports users, organizations, and memberships in the correct order. To also export Clerk enterprise SAML/OIDC connections for handoff, pass your Backend API key with `--secret-key`. For a guided, interactive experience: ```bash npx workos migrations wizard ``` If you'd rather write your own code, the same process can be completed using the public WorkOS APIs, as described below. ### (B) Using WorkOS APIs Using the data either from the Clerk API or from a JSON file received from their support team, you can use the WorkOS API to [create users](/reference/authkit/user/create) during the import. Keep in mind that user creation is rate-limited. You can view the docs on the [rate limits](/reference/rate-limits) for more information. Using the default fields from the [Clerk export](https://clerk.com/docs/deployments/exporting-users), use the following mapping from Clerk to parameters in your WorkOS Create User API calls: | Clerk | | WorkOS API | | ----------------- | --- | ------------ | | `email_addresses` | → | `email` | | `first_name` | → | `first_name` | | `last_name` | → | `last_name` | ### Handle users with multiple email addresses In the case of a user with multiple email addresses, Clerk separates them with a pipe symbol: ```json "email_addresses": "john@example.com|john.doe@example.com", ``` Unfortunately there's no way to know which email is the primary one from the export alone. Clerk does expose this information by retrieving the [User object from their API](https://clerk.com/docs/references/javascript/user/user#properties). ### Import passwords If you also exported passwords from Clerk, you can import them during the [user creation](/reference/authkit/user/create) process, or later using the WorkOS [Update User API](/reference/authkit/user/update). Clerk uses the `bcrypt` password hashing algorithm, which is supported by WorkOS. Make sure to pass the following parameters to the WorkOS API: - The `password_hash_type` set to `'bcrypt'` - The `password_hash` set to the `password_digest` field from your Clerk export ### Migrate social auth users If you have users who previously signed in through Clerk using social auth providers, such as [Google](/integrations/google-oauth) or [Microsoft](/integrations/microsoft-oauth), those users can continue to sign in with those providers after you've migrated to WorkOS. Check out our [integrations](/integrations) page for guidance on configuring the relevant provider's client credentials in WorkOS. After your provider is configured in WorkOS, users can sign in with their provider credentials and will be automatically linked to a WorkOS user. WorkOS uses the **email address** from the social auth provider to determine this match. --- ## (3) Create organizations Clerk's [organizations](https://clerk.com/docs/organizations/overview) are analogous to WorkOS [organizations](/reference/organization) – both represent a B2B customer. ### Creating Organizations If you'd like to export your Clerk organizations, you can use the [Clerk Backend SDK](https://clerk.com/docs/references/backend/organization/get-organization-list) to programmatically paginate through each organization. You can then use the WorkOS API to [create matching organizations](/reference/organization/create). ### Adding user memberships You can export Clerk organization memberships using Clerk's [Backend SDK](https://clerk.com/docs/references/backend/organization/get-organization-membership-list), and then use the WorkOS [Organization Membership API](/reference/authkit/organization-membership/create) to add each user to their respective organization. --- ## (4) Multi-Factor Auth There are some differences between the MFA strategies offered by Clerk and WorkOS. Clerk supports SMS-based second factors, however WorkOS does not due to known security issues with SMS. Users who have SMS-based second factors will need to switch to using email-based Magic Auth, or re-enroll in MFA using a TOTP-based authenticator instead. See the [MFA guide](/authkit/mfa) for more information on enrolling users. --- ## Next steps After the import, you can now start using WorkOS to manage your users. If you haven't, take a look at our [Quick Start guide](/authkit) to learn how to integrate WorkOS AuthKit into your application. ### Migrate from Better Auth Learn how to migrate users and organizations from Better Auth. ## Introduction You can migrate your existing user data from a variety of sources into WorkOS using the AuthKit API. This guide will walk you through the steps to export your data from Better Auth, and import into WorkOS. --- ## (1) Export Better Auth data Better Auth stores user data directly in your database, which means you have full control over exporting your data. Unlike hosted authentication services, Better Auth does not provide a built-in export tool, but you can access your data directly through your database. ### Accessing your database Better Auth uses [multiple database tables](https://www.better-auth.com/docs/concepts/database) to store authentication data. The main tables you'll need to export are: - **user**: Contains core user information (`id`, `name`, `email`, `emailVerified`, `image`, timestamps) - **account**: Stores provider-specific authentication data, including password hashes for credential-based accounts - **organization**: Available when using the [organization plugin](https://www.better-auth.com/docs/plugins/organization) - **member**: Mapping of users (and their roles) to organizations You can export this data using your database's native export tools, your ORM (for example, Prisma), or direct SQL queries. ### Exporting user data To export users, query the `user` table directly. ```sql SELECT * FROM user; ``` You can export this data to JSON, CSV, or any format that works for your migration script. ### Exporting passwords Better Auth stores password hashes in the `account` table with `providerId` set to `'credential'`. The passwords are hashed using [scrypt by default](https://www.better-auth.com/docs/authentication/email-password), though Better Auth supports custom hashing functions. To export password hashes, query the `account` table: ```sql SELECT userId, password FROM account WHERE providerId = 'credential'; ``` If you're using a custom password hashing algorithm in Better Auth, make note of the algorithm for the import step. The default is `scrypt`, which is supported by WorkOS. --- ## (2) Import users into WorkOS Once you've exported your user data from Better Auth, you can import it into WorkOS. ### Using the WorkOS migrations CLI The fastest way to import users is with the CLI: ```bash npx workos migrations import --csv better-auth-users.csv ``` Or for a guided experience: `npx workos migrations wizard` ### Using WorkOS APIs With the data from your Better Auth database, you can use the [Create User API](/reference/authkit/user/create) to import each user. The API is rate-limited, so for large migrations, you may want to implement batching with appropriate delays. You can view the [rate limits](/reference/rate-limits) documentation for more information. Using the Better Auth user table schema, use the following mapping to Create User API parameters: | Better Auth | | WorkOS | | --------------- | --- | ---------------- | | `email` | → | `email` | | `emailVerified` | → | `email_verified` | | `name` | → | `first_name` | | `name` | → | `last_name` | | `image` | → | (not supported) | > Better Auth stores a single `name` field, while WorkOS has separate `first_name` and `last_name` fields. You'll need to parse the name field or use it entirely for `first_name`. Here's an example migration script: ```typescript import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); async function migrateUsers(betterAuthUsers) { for (const user of betterAuthUsers) { // Parse name into first and last name if possible const [firstName, ...lastNameParts] = user.name.split(' '); const lastName = lastNameParts.join(' ') || undefined; try { // In the JavaScript SDK, the property names are camelCase const workosUser = await workos.userManagement.createUser({ email: user.email, emailVerified: user.emailVerified, firstName: firstName, lastName: lastName, }); console.log(`Migrated user: ${user.email} -> ${workosUser.id}`); } catch (error) { console.error(`Failed to migrate user ${user.email}:`, error); } } } ``` ### Importing passwords If you exported password hashes from Better Auth, you can import them during the [user creation](/reference/authkit/user/create) process, or later using the [Update User API](/reference/authkit/user/update). Better Auth uses `scrypt` as the default password hashing algorithm, which is supported by WorkOS. Make sure to pass the following parameters: - The `password_hash_type` set to `'scrypt'` - The `password_hash` set to the password hash value from your Better Auth `account` table The password hash should be in PHC string format. If Better Auth is storing raw scrypt hashes, you'll need to convert them to PHC format. See the [other services migration guide](/migrate/other-services/2-importing-users-into-workos/importing-passwords) for detailed information about PHC format parameters for scrypt. If you configured Better Auth to use a different password hashing algorithm, such as bcrypt, argon2, or pbkdf2, WorkOS supports these as well. Refer to the [password hash types](/migrate/other-services/2-importing-users-into-workos/importing-passwords) documentation for format requirements. ### Migrating social auth users If you have users who previously signed in through Better Auth using social auth providers, such as [Google](/integrations/google-oauth) or [Microsoft](/integrations/microsoft-oauth), those users can continue to sign in with those providers after you've migrated. Better Auth stores social auth accounts in the `account` table with different `providerId` values (e.g., `'google'`, `'github'`, `'microsoft'`). These accounts are linked to users via the `userId` field. Check out our [integrations](/integrations) page for guidance on configuring the relevant provider's client credentials. After your provider is configured, users can sign in with their provider credentials and will be automatically linked to a user. The **email address** from the social auth provider is used to determine this match. > Some users may need to verify their email address through WorkOS if email verification is enabled in your environment's authentication settings. Email verification behavior varies depending on whether the provider is known to verify email addresses. For example, users signing in using Google OAuth and a `gmail.com` email domain will not need to perform the extra verification step. --- ## (3) Organizations Better Auth has an [organization plugin](https://www.better-auth.com/docs/plugins/organization) that allows you to manage organization members and teams. If you're using this plugin, you can migrate your organizations to WorkOS, which has native support for [Organizations](/reference/organization) as a core B2B feature. ### Creating Organizations Better Auth stores organizations in an `organization` table with fields like `id`, `name`, `slug`, `logo`, and `metadata`. To migrate these, you'll need to: 1. Export organizations from your Better Auth database: ```sql SELECT * FROM organization; ``` 2. Create matching organizations using the [Create Organization API](/reference/organization/create): ```typescript import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); async function migrateOrganizations(betterAuthOrgs) { for (const org of betterAuthOrgs) { try { const workosOrg = await workos.organizations.createOrganization({ name: org.name, // You may want to store the Better Auth slug in organization metadata metadata: { betterAuthSlug: org.slug, }, }); console.log(`Migrated organization: ${org.name} -> ${workosOrg.id}`); // Store this mapping for migrating user memberships later orgIdMap.set(org.id, workosOrg.id); } catch (error) { console.error(`Failed to migrate organization ${org.name}:`, error); } } } ``` ### Adding organization memberships Better Auth stores organization memberships in a `member` table that links users (and their roles) to organizations. ```sql SELECT * FROM member; ``` Then use the [Organization Membership API](/reference/authkit/organization-membership/create) to add each user to their respective organization. WorkOS offers RBAC capabilities through [roles and permissions](/authkit/roles-and-permissions). When migrating, identify your roles defined in Better Auth, then create equivalent roles in the WorkOS Dashboard, and assign roles during migration by specifying the `roleSlug` parameter when creating organization memberships. If your Better Auth implementation uses complex RBAC policies with custom resources and actions, you may need to simplify to standard roles or implement custom authorization in your application logic. ```typescript async function migrateMemberships(betterAuthMemberships, orgIdMap, userIdMap) { for (const membership of betterAuthMemberships) { const orgId = orgIdMap.get(membership.organizationId); const userId = userIdMap.get(membership.userId); if (!orgId || !userId) { console.error(`Missing mapping for membership: ${membership.id}`); continue; } try { await workos.userManagement.createOrganizationMembership({ userId: userId, organizationId: orgId, // Better Auth uses custom role strings; map these to WorkOS roles as needed roleSlug: getRole(membership.role), }); console.log(`Migrated membership: ${membership.userId} -> ${orgId}`); } catch (error) { console.error(`Failed to migrate membership:`, error); } } } ``` ### Migrating teams If you're using the teams feature within Better Auth (an optional hierarchical level within organizations), note that there is not a directly corresponding "teams" concept. However, you have several options: 1. **Convert to organizations**: Create separate organizations for each Better Auth team 2. **Use organization metadata**: Store team information in organization metadata 3. **Use RBAC roles**: Represent team membership through custom roles in [role-based access control](/rbac/quick-start) For most B2B applications, flattening teams into separate organizations provides the cleanest migration path and takes full advantage of enterprise features like SSO and Directory Sync, which operate at the organization level. --- ## (4) Special considerations There are several differences between Better Auth and WorkOS that you should be aware of during migration. ### Multi-Factor Authentication Better Auth offers a [Two-Factor Authentication plugin](https://www.better-auth.com/docs/plugins/2fa) that supports TOTP-based authenticators. If your Better Auth users have enrolled in 2FA, they will need to re-enroll in MFA after migrating, as MFA secrets cannot be migrated for security reasons. See the [MFA guide](/authkit/mfa) for information on enrolling users in MFA. > WorkOS does not support SMS-based factors due to known security vulnerabilities with SMS. ### Account linking behavior Better Auth has sophisticated [account linking capabilities](https://www.better-auth.com/docs/concepts/users-accounts#account-linking) that automatically link social accounts with matching verified email addresses. WorkOS also supports automatic account linking based on email addresses. When migrating users who have multiple linked accounts in Better Auth (e.g., password + Google OAuth), you should: 1. Import the user once with their primary email 2. Configure the relevant social providers 3. When users sign in with their social provider, they will automatically be linked with the accounts based on email match ### Handling interim new users If your application allows users to sign up at any time, you should [consider the timing of your migration](/migrate/other-services/4-handling-interim-new-users). Users who sign up after you've exported data from Better Auth but before you've switched to WorkOS for authentication will be omitted from the migration. There are two main strategies to handle this: #### (A) Disable signups during migration Schedule an appropriate time for the migration and temporarily disable signup functionality. This can be controlled using a feature flag in your application. After the migration is complete and your application is using WorkOS for authentication, re-enable signups. #### (B) Use a dual-write strategy For applications that cannot disable signups, implement a "dual-write" strategy. When a new user signs up, create records in both your Better Auth database and WorkOS using the [Create User API](/reference/authkit/user/create). This keeps WorkOS synchronized with new users, though you'll still need to perform the historical user migration. Be aware that you'll need to keep user updates (email changes, password changes) synchronized between both systems until the migration is complete. ### Database-specific considerations Since Better Auth stores data in your own database, you have flexibility in how you structure the migration: - You can keep Better Auth tables in your database during a transition period - Consider implementing a gradual rollout where some users authenticate via WorkOS while others continue using Better Auth - Database schema is extensible, so custom fields will need to be handled separately (consider using [user metadata](/authkit/metadata) for custom data) --- ## Next steps With your users and organizations now imported, you can start using WorkOS to manage authentication for your application. If you haven't already, take a look at our [Quick Start guide](/authkit) to learn how to integrate AuthKit into your application. These enterprise-ready features go beyond basic authentication: - **[Single Sign-On](/sso)**: Enable SAML and OIDC SSO for enterprise customers - **[Directory Sync](/directory-sync)**: Automatically provision and deprovision users from identity providers - **[Admin Portal](/admin-portal)**: Allow your customers to self-serve SSO and Directory Sync configuration - **[Audit Logs](/audit-logs)**: Track security-relevant events in your application If you have questions about your migration or need assistance, reach out to [support@workos.com](mailto:support@workos.com). ### Migrate from AWS Cognito Learn how to migrate users to WorkOS from AWS Cognito. ## Introduction The WorkOS AuthKit API allows you to migrate your existing user data from a variety of existing sources. In this guide, we'll walk through the steps to export, and then import your users from AWS Cognito. > AWS Cognito does not offer exports of user password hashes or MFA keys. This means that your imported users will need to reset their passwords and reconfigure any required MFA. ## (1) Exporting Cognito user data User data in an AWS Cognito User Pool can be exported using the AWS CLI's [list-users command](https://docs.aws.amazon.com/cli/latest/reference/cognito-idp/list-users.html). To retrieve the first page of results, use the command: ```bash title="List users using the Cognito CLI" aws cognito-idp list-users --user-pool-id --region ``` Add the `--pagination-token ` argument to paginate subsequent requests: ```bash title="export-aws-cognito-users.sh" #!/bin/bash user_pool_id="" region="" output_dir="cognito_exports" file_index=1 mkdir -p "$output_dir" export_users() { aws cognito-idp list-users --user-pool-id "$user_pool_id" --region "$region" $1 | \ jq '.' > "$output_dir/users_$2.json" } next_token="" while true; do next_token=$(export_users "${next_token:+--pagination-token $next_token}" "$file_index" | jq -r '.PaginationToken // empty') [ -z "$next_token" ] && break ((file_index++)) done echo "Export complete." ``` ## (2) Importing users into WorkOS After obtaining your user data from Cognito, it's time to import them into WorkOS. ### Using the WorkOS migrations CLI The fastest way to migrate is with the CLI, which exports users directly from your user pools via the AWS API and writes a migration package ready for import: ```bash npx workos migrations export cognito \ --region \ --user-pool-ids \ --output-dir ./migration-cognito npx workos migrations import-package ./migration-cognito ``` Or for a guided experience: `npx workos migrations wizard` Alternatively, map attributes from the AWS Cognito User format to WorkOS API parameters. ```json title="Example AWS Cognito list-users response object" { "Users": [ { "Username": "22704aa3-fc10-479a-97eb-2af5806bd327", "Enabled": true, "UserStatus": "FORCE_CHANGE_PASSWORD", "UserCreateDate": 1548089817.683, "UserLastModifiedDate": 1548089817.683, "Attributes": [ { "Name": "sub", "Value": "22704aa3-fc10-479a-97eb-2af5806bd327" }, { "Name": "family_name", "Value": "Mouse" }, { "Name": "given_name", "Value": "Mickey" }, { "Name": "email_verified", "Value": "true" }, { "Name": "email", "Value": "mary@example.com" } ] } ] } ``` Using the WorkOS [Create User API](/reference/authkit/user/create), you can create a corresponding record in WorkOS for each exported user. Use the following mapping from the AWS Cognito object to parameters in your WorkOS Create User API calls: | AWS Cognito | | WorkOS API | | --------------- | --- | ---------------- | | `email` | → | `email` | | `emailVerified` | → | `email_verified` | | `given_name` | → | `first_name` | | `family_name` | → | `last_name` | > Migrated users **must reset their passwords** before they can sign in. ### Triggering password resets It's important to have a strategy for triggering password resets after importing your users into WorkOS. You may want to ask users to reset their password the next time they attempt to sign in, or proactively send them password reset emails. In either case, you can trigger the password reset flow by using the WorkOS [Send Password Reset Email API](/reference/authkit/password-reset/create). ## Other authentication methods In addition to migrating username and password users to WorkOS, you can migrate users who authenticate using third-party identity providers, such as Google, without re-obtaining access. Ensure you use the same credentials (i.e. Client ID and Client Secret) in WorkOS as those used for your connection in AWS Cognito. For OAuth providers, you will need to add WorkOS as an additional Redirect URI. See the [Google OAuth integration guide](/integrations/google-oauth/customize-google-oauth-domain-optional/3-add-new-redirect-uri-to-google) as an example of what this process looks like. ### Migrate from Auth0 Learn how to migrate users, organizations, and enterprise connections from Auth0. ## Introduction The WorkOS AuthKit API allows you to migrate your existing user data from a variety of existing sources. In this guide, we will walk through the steps to export, and then import your users, organizations, and enterprise SSO connections from Auth0. --- ## (1) Exporting Auth0 user data Auth0 allows their customers to export user data using several tools, which are outlined in [Auth0's export documentation](https://auth0.com/docs/troubleshoot/customer-support/manage-subscriptions/export-data). A combination of exports may be necessary to retrieve all of the desired user information, including passwords. ### Using the WorkOS migrations CLI The fastest way to export Auth0 data is with the WorkOS CLI migrations tool: ```bash npx workos migrations export auth0 \ --domain my-tenant.us.auth0.com \ --client-id \ --client-secret \ --output-dir ./migration-auth0 ``` This produces a migration package with users, organizations, memberships, roles, SSO handoff files, and warnings. You will need an Auth0 Machine-to-Machine application authorized for the Management API with the following scopes: - `read:users` - `read:user_idp_tokens` - `read:organizations` - `read:organization_members` - `read:organization_member_roles` - `read:roles` - `read:connections` - `read:connections_options` For an interactive, step-by-step experience, use the wizard: ```bash npx workos migrations wizard ``` ### Manual export The first tool is [Auth0's "Bulk User Export" jobs](https://auth0.com/docs/manage-users/user-migration/bulk-user-exports). These export jobs can be created programmatically using the [Auth0 Management API](https://auth0.com/docs/api/management/v2/jobs/post-users-exports), or through the official [Auth0 "User Import / Export Extension"](https://auth0.com/docs/customize/extensions/user-import-export-extension). In both cases, an Auth0 customer can request which fields they'd like exported for each user, with the final output of the process being a newline-delimited JSON file. ### Exporting passwords If your Auth0 users currently sign-in using password-based authentication, and you'd like to import those passwords into WorkOS, then you will need to [contact Auth0 support](https://auth0.com/docs/troubleshoot/customer-support). After opening a ticket with Auth0, it can take up to a week or more for your request to be processed. At the end you'll be given another newline-delimited JSON file, containing a subset of user data such as ID, but more importantly the password hash. > Auth0 does not make the plaintext passwords available for export. If you exported a migration package with the CLI, you can merge the password hashes into it: ```bash npx workos migrations merge-passwords \ --package ./migration-auth0 \ --passwords auth0-passwords.ndjson ``` --- ## (2) Importing users into WorkOS Once you've obtained the necessary export files, you can import your user data into WorkOS using the CLI or the API directly. > For migrations involving more than 200,000 users or organizations, contact [support@workos.com](mailto:support@workos.com) to coordinate a managed import. ### Before you begin: disable webhook delivery If you have [webhook endpoints](/reference/webhooks) configured, temporarily disable delivery for the duration of the bulk import to avoid overwhelming your webhook consumers with high volumes of `user.created`, `organization.created`, and `organization_membership.created` events. You can disable a webhook endpoint using the [Update Webhook Endpoint API](/reference/webhooks/update): ```bash curl -X PATCH https://api.workos.com/webhook_endpoints/{id} \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "status": "disabled" }' ``` Re-enable the endpoint after the import is complete by setting `status` back to `"enabled"`. ### (A) Using the WorkOS migrations CLI If you exported a migration package in the previous step, import it in one command: ```bash npx workos migrations import-package ./migration-auth0 ``` The orchestrator imports organizations, users, memberships, roles, and TOTP factors in the correct order. Preview what the import would do with `--plan` or `--dry-run` first. For a standalone CSV import: ```bash npx workos migrations import --csv users.csv ``` > User creation is rate-limited. See the [rate limits documentation](/reference/rate-limits) for details. The CLI handles batching and concurrency automatically. ### (B) Using WorkOS APIs With the data from Auth0's "Bulk User Export" job, you can use the WorkOS [Create User API](/reference/authkit/user/create) to import each of the users. Using the default fields from the [Auth0 export](https://auth0.com/docs/customize/extensions/user-import-export-extension#export-users), use the following mapping from Auth0 to parameters in your WorkOS Create User API calls: | Auth0 | | WorkOS API | | -------------- | --- | ---------------- | | Email | → | `email` | | Email Verified | → | `email_verified` | | Given Name | → | `first_name` | | Family Name | → | `last_name` | ### Importing passwords If you also exported passwords from Auth0, you can import them during the [user creation](/reference/authkit/user/create) process, or later using the WorkOS [Update User API](/reference/authkit/user/update). Auth0 uses the `bcrypt` password hashing algorithm, which is supported by WorkOS. Make sure to pass the following parameters to the WorkOS API: - The `password_hash_type` set to `'bcrypt'` - The `password_hash` set to the `passwordHash` field from your Auth0 export ### Migrating social auth users If you have users who previously signed in through Auth0 using social auth providers, such as [Google](/integrations/google-oauth) or [Microsoft](/integrations/microsoft-oauth), those users can continue to sign in with those providers after you've migrated to WorkOS. Check out our [integrations](/integrations) page for guidance on configuring the relevant provider's client credentials in WorkOS. After your provider is configured in WorkOS, users can sign in with their provider credentials and will be automatically linked to a WorkOS user. WorkOS uses the **email address** from the social auth provider to determine this match. > Some users may need to verify their email address through WorkOS if email verification is enabled in your WorkOS environment's authentication settings. Email verification behavior varies depending on whether the provider is known to verify email addresses. For example, users signing in using Google OAuth and a `gmail.com` email domain will not need to perform the extra verification step. --- ## (3) Organizations Auth0 has a concept of ["Organizations"](https://auth0.com/docs/manage-users/organizations) which are analogous to [WorkOS Organizations](/reference/organization), in that both represent a B2B customer. ### Creating Organizations If you exported a migration package with the CLI, organizations are imported automatically by `import-package`. Otherwise, you can use the [Auth0 Management API](https://auth0.com/docs/api/management/v2/organizations/get-organizations) to programmatically paginate through each Organization, then call the WorkOS [Create Organization API](/reference/organization/create) to create matching Organizations in WorkOS. ### Adding user memberships You can export Auth0 organization memberships using Auth0's "Bulk User Export" as described in the [Exporting Auth0 user data](/migrate/auth0/1-exporting-auth0-user-data) step, and then use the WorkOS [Organization Membership API](/reference/authkit/organization-membership/create) to add each user to their respective organization. > If you plan to import Enterprise Connections (SSO), see the next section first — importing a bulk set of connections will automatically create the corresponding organizations in WorkOS. --- ## (4) Enterprise Connections (SSO) If your Auth0 tenant has enterprise SAML or OIDC connections, you can migrate them to WorkOS. The best strategy depends on how many connections you have. ### Choosing a migration strategy ### (A) Fewer than 15 connections — Admin Portal approach For smaller deployments, the simplest path is to recreate each connection in WorkOS and coordinate with each customer's IT team to update their Identity Provider configuration. You can use the [Admin Portal](/admin-portal) to let customers self-service their SSO setup, reducing the coordination burden. For each connection: 1. Create or identify the WorkOS organization matching the Auth0 organization 2. Share the [Admin Portal](/admin-portal) link with the customer's IT team so they can update their IdP configuration to point to WorkOS 3. Watch for the `connection.activated` webhook to roll out the customer to the WorkOS connection ### (B) 15 or more connections — Transparent proxy migration For larger deployments, coordinating with every customer's IT team is impractical. Instead, you can perform a **transparent migration** where customer IdPs continue posting to the same Auth0 callback URL while a proxy routes the traffic to WorkOS. IT admins do not need to reconfigure anything on their end. This approach requires that you have a **custom domain configured in Auth0** (e.g., `auth0.your-domain.com`) so that you control the domain routing. > For a detailed walkthrough of the transparent proxy migration, see the [Auth0 to WorkOS Enterprise Connections Migration Guide](https://workos.com/guide/auth0-to-workos-enterprise-connections-migration-guide). ### Requirements for transparent proxy migration To migrate enterprise SSO connections with zero friction, the following must be true: - You have configured a [custom domain](https://auth0.com/docs/customize/custom-domains) with Auth0 so that you control the domain routing - Your SAML enterprise connections do not use SAML Request Signing with Auth0 tenant global key pairs - Your SAML enterprise connections do not use SAML Response Encryption with Auth0 tenant global key pairs ### Exporting enterprise connections The WorkOS migrations CLI can export your Auth0 enterprise connections: ```bash npx workos migrations export auth0 \ --domain my-tenant.us.auth0.com \ --client-id \ --client-secret \ --entities sso \ --output-dir ./migration-auth0-sso ``` This produces files with SAML and OIDC connection details, custom attribute mappings, and proxy routes. Contact [support@workos.com](mailto:support@workos.com) with the export files, and the WorkOS team will import the connections for you. After the import, WorkOS provides a mapping between Auth0 and WorkOS connection IDs that you can use during the gradual rollout. ### Configuring the callback proxy ![Configuring the callback proxy](https://images.workoscdn.com/images/d7655dfe-1d49-4fa6-9deb-24f98359a6b2.png) Once connections are imported into WorkOS, configure a proxy in front of your Auth0 custom domain to route IdP callback traffic to WorkOS. The proxy intercepts callbacks at your Auth0 custom domain's `/login/callback` path and redirects them to your WorkOS custom domain. The proxy flow works as follows: 1. A user authenticates with their IdP, which posts the SAML response or OIDC callback to your Auth0 custom domain 2. The proxy redirects the callback to WorkOS 3. WorkOS attempts to find a matching connection: - If found, it processes the response and redirects to your application's WorkOS callback - If not found, it redirects back with a `fallback=auth0` query parameter, and the proxy forwards the original callback to Auth0 This fallback mechanism ensures zero downtime — connections that haven't been migrated yet continue to work through Auth0. The proxy can be implemented using Cloudflare redirect and transform rules, a Cloudflare Worker, or any reverse proxy you control. The [workos-migrations repository](https://github.com/workos/workos-migrations/tree/main/proxy-sample-auth0) includes a reference implementation. For Cloudflare rules configuration, see the [detailed migration guide](https://workos.com/guide/auth0-to-workos-enterprise-connections-migration-guide). > We recommend performing a proof-of-concept in a staging environment before production to de-risk breaking changes in your setup. ### Gradual rollout with Feature Flags Once the proxy is in place, you can opt-in connections to WorkOS one at a time. [WorkOS Feature Flags](/feature-flags) can control which organizations use WorkOS SSO versus Auth0 during the migration. Create a feature flag (e.g., `workos-sso-enabled`) and target it to specific organizations as you migrate them. ```typescript title="Route SSO based on feature flag" import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); const featureFlags = workos.featureFlags.createRuntimeClient(); await featureFlags.waitUntilReady({ timeoutMs: 5000 }); function getSSOAuthorizationUrl(organizationId: string): string { const useWorkOS = featureFlags.isEnabled('workos-sso-enabled', { organizationId, }); if (useWorkOS) { return workos.userManagement.getAuthorizationUrl({ provider: 'authkit', organizationId, clientId: process.env.WORKOS_CLIENT_ID!, redirectUri: process.env.WORKOS_REDIRECT_URI!, }); } // Fall back to Auth0 for organizations not yet migrated return ( `https://${process.env.AUTH0_DOMAIN}/authorize?` + `client_id=${encodeURIComponent(process.env.AUTH0_CLIENT_ID!)}` + `&redirect_uri=${encodeURIComponent(process.env.AUTH0_REDIRECT_URI!)}` + `&response_type=code` + `&organization=${encodeURIComponent(organizationId)}` ); } ``` This lets you gradually migrate organizations to WorkOS SSO, verify each one works correctly, and roll back individual organizations if needed — all without code deployments. After the migration is complete, you can turn off your Auth0 tenant entirely. You will need to maintain the custom domain in your DNS provider so that the proxy continues to route any remaining traffic. > For a simpler integration path that doesn't require changes to your Auth0 application code, see the [Auth0 Enterprise Connection](/integrations/auth0-enterprise-connection) integration guide. --- ## (5) Multi-Factor Auth There are some differences between the Multi-Factor Auth (MFA) strategies offered by Auth0 and WorkOS. Auth0 supports SMS-based second factors, however WorkOS does not due to known security issues with SMS. Users who have SMS-based second factors will need to switch to using email-based Magic Auth, or re-enroll in MFA using a TOTP-based authenticator instead. If your Auth0 users have TOTP factors, the CLI can enroll them in WorkOS after import: ```bash npx workos migrations enroll-totp \ --input totp-secrets.csv \ --totp-issuer "YourApp" ``` --- ## (6) Handling interim new users If your application allows users to sign up at any time, you should [consider the timing of your migration](/migrate/other-services/4-handling-interim-new-users). Users who sign up after you've exported data from Auth0 but before you've switched to WorkOS for authentication will be omitted from the migration. There are two main strategies to handle this: ### (A) Disable signups during migration Schedule an appropriate time for the migration and temporarily disable signup functionality. This can be controlled using a feature flag in your application. After the migration is complete and your application is using WorkOS for authentication, re-enable signups. ### (B) Use a dual-write strategy For applications that cannot disable signups, implement a "dual-write" strategy. When a new user signs up, create records in both Auth0 and WorkOS using the [Create User API](/reference/authkit/user/create). This keeps WorkOS synchronized with new users, though you'll still need to perform the historical user migration. Be aware that you'll need to keep user updates (email changes, password changes) synchronized between both systems until the migration is complete. --- ## Next steps After completing your migration to WorkOS, you can take advantage of additional features: - **[Audit Logs](/audit-logs)**: Track security-relevant events across your application - **[Radar](/authkit/radar)**: Protect against bots, fraud, and abuse - **[Feature Flags](/feature-flags)**: Control feature rollout for specific users and organizations If you haven't already, check out the [AuthKit Quick Start guide](/authkit) to learn how to integrate WorkOS into your application. For questions or assistance with your migration, contact [support@workos.com](mailto:support@workos.com). ## Multi-Factor Auth {#mfa} ### Multi-Factor Authentication A composable API for implementing multi-factor authentication. ## Introduction The Multi-Factor Authentication (MFA) API is intended to be a composable, unopinionated set of endpoints that can be integrated into existing application/session management strategies. The available types of authentication factors are: - `totp` – Time-based one-time password - `sms` – One-time password via SMS message (US only) > The MFA API is not intended to be used with the WorkOS SSO feature. It's recommended to leverage the MFA features of the Identity Provider that is powering your SSO implementation. ## What you'll build In this guide, we'll walk you through the process of enrolling new authentication factors for a user, and the challenge/verification process for existing authentication factors. This guide will show you how to: 1. Create an Authentication Factor 2. Challenge the Authentication Factor 3. Verify the Challenge ## Before getting started To get the most out of this guide, you'll need: - A [WorkOS account](https://dashboard.workos.com/) ## API object definitions [Authentication Factor](/reference/mfa/factor) : A factor of authentication that can be used in conjunction with a primary factor to provide multiple factors of authentication. [Authentication Challenge](/reference/mfa/challenge) : A request for an Authentication Factor to be verified. ## (1) Create an Authentication Factor We'll first need to enroll a new Authentication Factor. ### Install the WorkOS SDK WorkOS offers native SDKs in several popular programming languages. Choose a language below to see instructions in your application's language. ### Set secrets To make calls to WorkOS, provide the API key and, in some cases, the client ID. Store these values as managed secrets, such as `WORKOS_API_KEY` and `WORKOS_CLIENT_ID`, and pass them to the SDKs either as environment variables or directly in your app's configuration based on your preferences. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' ``` ### Enroll the Authentication Factor - | Using TOTP Use the TOTP type when the user is using a third-party authenticator app such as Google Authenticator or Authy. The response returns a `qr_code` and a secret. The `qr_code` value is a base64 encoded data URI that is used to [display the QR code](https://css-tricks.com/data-uris/) in your application for enrollment with an authenticator application. The `secret` can be entered into some authenticator applications in place of scanning a QR code. - | Using SMS Use the SMS type when the user wants to receive one time passwords as SMS messages to their mobile device. Phone number must be a valid US number. An error will be returned for malformed or invalid phone numbers. Now that we've successfully created an authentication factor, we'll need to save the ID for later use. It's recommended that you persist the factor ID in your own user model according to your application's needs. ## (2) Challenge the Authentication Factor Next we'll initiate the authentication process for the newly created factor which we'll refer to as a challenge. - | Create Authentication Challenge - | Sending Custom SMS Message When challenging an SMS authentication factor, you can pass an optional SMS template to customize the SMS message that is sent to the end user. Use the `{{code}}` token to inject the one time password into the message. Now that we've successfully challenged the authentication factor, we'll need to save the challenge ID for the last step, challenge verification. ## (3) Verify the Challenge The last step in the authentication process is to verify the one time password provided by the end-user. ### Verification Response If the challenge is successfully verified `valid` will return `true`. Otherwise it will return `false` and another verification attempt must be made. ### Already Verified Error If a challenge was already successfully verified, it cannot be used a second time. If further verification is needed in your application, create a new challenge. ### Expired Error For SMS authentication factors, challenges are only available for verification for 10 minutes. After that they are expired and cannot be verified. We've now successfully verified an end-user's authentication factor. This authentication factor can now be used as a second factor of authentication in your application's existing authentication strategy. The ID of the authentication factor should be persisted in your application for future authentication challenges. ### Example Apps View sample Multi-Factor Auth apps for each SDK. You can view minimal example apps that demonstrate how to use the WorkOS SDKs to authenticate users via MFA: ### Sign-In UX User experience considerations for MFA sign-in. ## Introduction Once a user has setup two-factor authentication, their sign-in process will be different from the standard sign-in flow. This guide will walk you through the adjustments you need to make to support this in your application. ## Prompt user to verify the extra factor At the very least, assuming the user has enrolled in one method (e.g. SMS/Text message) you should present the user with a new screen for the extra verification step after they have entered their username and password. ## When the user has enrolled in multiple methods If the user has enrolled in multiple methods, consider including both methods in the verification step after they have entered their username and password. Following what we discussed in the [enrollment guide](/mfa/ux/enrollment/let-users-choose-their-primary-method), consider presenting the user with their primary method first as well as letting them switch. --- ## Full interactive UI example The following interactive example shows a full UI for signing-in using MFA encompassing all the considerations mentioned above. ### Enrollment UX User experience considerations for MFA enrollment. ## Introduction Now that we've seen how the MFA APIs work, you may want to consider how you want to present the MFA enrollment experience to your users. This guide will cover some of the considerations you should take into account when designing your enrollment experience. ## Provide multiple methods The MFA APIs support multiple methods of authentication. Consider providing your users with multiple options for enrolling in MFA. Adding flexibility will reduce friction in users adoption. ## Let users choose their primary method If a user has enrolled in multiple methods, consider letting them select a primary. This will allow you to challenge them with the method they are most comfortable, whilst still benefiting from the security of a backup in case they lose access. ## Setup a `totp` factor accessibly As we have previously seen, [when enrolling a `totp` factor using the MFA API](/mfa/1-create-an-authentication-factor/enroll-the-authentication-factor), the response returns a `qr_code` and a `secret`. The `qr_code` value can be passed directly to the source on an image tag as follows: However, some users may not be able to scan the QR code. Consider providing the `secret` value in the UI as an alternate way to set up their authenticator app. Additionally, consider describing the QR code for assistive technologies: ## Interoperable one-time-passcode input In order to make the experience as smooth as possible for your users, there are a few things to consider regarding the input they will use to fill in their one-time-passcode. ### Provide the right affordance You may be tempted to use [a number input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number) as it will show the mobile keyboard for numbers only. This is not recommended because a browser expects a number input to be countable, rather than a sequence of multiple numbers, which can cause unexpected behavior. Instead, we recommend using a text input (`type="text"`) with the `inputmode="numeric"` attribute to provide mobile devices with the expected numerical keyboard prompt. ### Autofill Setting `autocomplete="one-time-code"` will enable autofill with in any user-agent that supports it. This will for example ensure Safari on iOS/macOS can suggest/auto-fill the one-time-code received via SMS. Consider also submitting the form automatically as soon as the passcode length has been met. This should help reduce the friction of using two-factor authentication for your users. ### Validation Consider using client-side validation to ensure the user enters a valid one-time-passcode. This will reduce the number of requests to the server and improve the user experience. `pattern="^\d{6}$"` can be used to validate the length of the one-time-passcode. Here is a code example implementing the above considerations: --- ## Full UI interactive example The following interactive example shows a full UI for enrolling in MFA, and encompasses all of the considerations mentioned above. ## Magic Link {#magic-link} ### Magic Link The fastest way to securely enable authentication – passwordless sign-in via email in a couple lines of code. > **Deprecated:** Magic Link is not recommended due to issues with email clients or other security software visiting the links and invalidating them. Instead, use [Magic Auth](/authkit/magic-auth), which provides a more secure passwordless authentication method. ## Introduction Managing password authentication entails significant overhead for engineering teams and opens up many risks for breaches. Magic Link from WorkOS gives you the ability to build a secure passwordless authentication flow utilizing email. Send users a one-time-use link and let them sign in with a single click. > Magic Link sets you up to handle Single Sign-On via the [WorkOS SSO API](/sso). The redirect URI / profile retrieval process is identical between Magic Link and SSO. ![Diagram showing Magic Link flow which emphasizes that WorkOS does not manage the session.](https://images.workoscdn.com/docs/guides/magic-link/v1/magic-link-diagram.png?auto=format&fit=clip&q=50)\[border=false] Magic Link is not a session management solution – instead it is an authentication solution. You as the developer have the ability to manage user sessions as you see fit. This means you determine how long a session is valid for, as well as how to store and invalidate a session. Magic Links are single use, meaning that they will immediately expire after they are first clicked. If end users have security checks included with their email provider that test all embedded URLs, it can cause the Magic Links to expire before they reach the user's inbox. To work around this, we recommend that end users add these Magic Link emails to an allowlist in order to bypass these security checks. ## What you'll build In this guide, we'll take you from learning about passwordless authentication all the way through to building production-ready passwordless authentication flows with the WorkOS Magic Link API. This guide will show you how to: 1. Add Magic Link to your app 2. Configure a redirect URI 3. Create a new Magic Link Connection ## Before getting started To get the most out of this guide, you'll need: - A [WorkOS account](https://dashboard.workos.com/) ## API object definitions [Passwordless Session](/reference/magic-link/passwordless-session) : Represents a passwordless authentication session. [Profile](/reference/sso/profile) : Represents an authenticated user. The Profile object contains information relevant to a user in the form of normalized and raw attributes. ## (1) Add Magic Link to your app ### Install the WorkOS SDK WorkOS offers native SDKs in several popular programming languages. Choose a language below to see instructions in your application's language. ### Set secrets To make calls to WorkOS, provide the API key and, in some cases, the client ID. Store these values as managed secrets, such as `WORKOS_API_KEY` and `WORKOS_CLIENT_ID`, and pass them to the SDKs either as environment variables or directly in your app's configuration based on your preferences. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' ``` ### Add a callback endpoint Let's first add the redirect endpoint which will handle the callback from WorkOS after a user has authenticated via a magic link. This endpoint should exchange the authorization code (valid for 10 minutes) returned by WorkOS with the authenticated user's Profile. ### Create a Passwordless Session and email the user Create a Passwordless Session to generate an authentication link for a user. An authentication link is valid for 15 minutes and can be sent via the WorkOS API or using your own email service. You can use the optional `state` parameter to encode arbitrary information to help restore application state between redirects. You can use the optional `redirect_uri` parameter to override the default [Redirect URI](/glossary/redirect-uri) set in the dashboard. > A Magic Link Connection will be automatically created if there isn't already one for the domain specified when creating a new Passwordless Session. - | WorkOS email Use the WorkOS API to send the authentication link to the user. The email sent will be WorkOS branded. - | Custom email Use your own email service and custom branded email template to send the authentication link to the user. --- ## (2) Configure a redirect URI You should set a redirect URI (i.e. the callback endpoint from [Add a callback endpoint](/magic-link/1-add-magic-link-to-your-app/add-a-callback-endpoint)) in the [Applications](https://dashboard.workos.com/environment/applications) section of the WorkOS Dashboard. Open your application and go to the **Redirects** tab – be sure not to include wildcard subdomains or query parameters. ![A screenshot showing where to add a callback in the WorkOS Dashboard.](https://images.workoscdn.com/images/43ffd916-890b-4f1f-8767-0b70113288d9.png?auto=format&fit=clip&q=50) ### Launch Checklist Make sure you're ready to take your app to production. ## Create an IP Allowlist WorkOS makes use of Cloudflare to ensure security and reliability of all operations. If you are looking to create a list of allowed IP addresses for redirect requests, you can use the IP Ranges listed in the [Cloudflare documentation](https://www.cloudflare.com/ips/). ## Go-live checklist - \[ ] Unlock your Production environment by adding your billing information > Only enterprise connections in your Production environment will be charged. Any Google OAuth or Magic Link connections in Production will be free. - \[ ] Configure a production redirect URI for your application - \[ ] Secure your Production project's API key - \[ ] Ensure that your application can receive redirects from WorkOS Depending on your network architecture, you may need to allowlist incoming redirect traffic from `api.workos.com`. ## Frequently asked questions ### Can I customize the email sent via Magic Link? Yes, you can use your own email service and custom branded email template to send the authentication link to the user. See the custom email code snippet in the [create passwordless session section](/magic-link/1-add-magic-link-to-your-app/create-a-passwordless-session-and-email-the-user) for an example. ### Example Apps View sample Magic Link apps for each SDK. You can view minimal example apps that demonstrate how to use the WorkOS SDKs to authenticate users via Magic Link: ## Integrations {#integrations} ### Xero OAuth Learn how to set up OAuth with Xero ## Introduction The Xero OAuth integration allows your users to authenticate using their Xero credentials through the "Sign in with Xero" flow. The configuration process involves creating an OAuth application in Xero and configuring the client credentials in your WorkOS Dashboard. --- ## What WorkOS provides When setting up Xero OAuth, WorkOS provides one key piece of information that needs to be configured in your Xero OAuth application: - [Redirect URI](/glossary/redirect-uri): The endpoint where Xero will send authentication responses after successful login The Redirect URI is available in the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select the **Authentication** tab and the **OAuth providers** sub-tab. Locate the **Xero** section. ![The Xero OAuth section in the WorkOS Dashboard.](https://images.workoscdn.com/images/ea385495-75f6-4357-b16a-97c1383bbc9b.png?auto=format&fit=clip&q=50) Click **Enable**. The **Xero OAuth** configuration dialog will open. Locate the **Redirect URI**. ![Xero OAuth Redirect URI in the WorkOS Dashboard.](https://images.workoscdn.com/images/75e4e68e-cf07-4277-8979-7cd81f82f68f.png?auto=format&fit=clip&q=50) The **Redirect URI** serves as the destination for authentication responses and must be configured in your Xero application's OAuth settings. --- ## What you'll need You will need to obtain two pieces of information from a Xero Developer application: - **Xero Client ID**: Application identifier from Xero - **Xero Client Secret**: Authentication secret for the application The following sections will guide you through creating an OAuth application in your Xero Developer account and generating these credentials. --- ## (1) Create the Xero OAuth application Log in to your [Xero developer account](https://developer.xero.com) and create a new application. ![The Xero developer homepage.](https://images.workoscdn.com/images/58e9b3af-7442-45e7-8be2-cb1fa9ab39a2.png?auto=format&fit=clip&q=80) In the top right corner, select **New app**. Fill out the form starting with the application name. ![The Xero form to create a new OAuth application.](https://images.workoscdn.com/images/f78a99b4-f004-4437-9612-6d97ef49bf3d.png?auto=format&fit=clip&q=50) For the **Integration type**, select **Web app**. For **Company or application URI**, use your application's homepage URI. For **Redirect URI**, use the **Redirect URI** from the Xero OAuth configuration in the WorkOS Dashboard. ![OAuth client credentials in the Xero application settings.](https://images.workoscdn.com/images/9a0c3175-3af3-4613-a9f9-c9e6851507fe.png?auto=format&fit=clip&q=50) Agree to Xero's Developer Platform Terms & Conditions and click **Create app**. --- ## (2) Generate client credentials On the next page, you will see the Xero **App details** for your new OAuth application. From the left navigation menu, navigate to the **Configuration** page. ![OAuth client credentials in the Xero application settings before creating a client secret.](https://images.workoscdn.com/images/5ec780c3-c325-4455-992e-20727c39f8f9.png?auto=format&fit=clip&q=50) Select **Generate a secret** to create a client secret. ![OAuth client credentials in the Xero application settings after creating a client secret.](https://images.workoscdn.com/images/58158b26-0854-496f-9ccc-660955735463.png?auto=format&fit=clip&q=50) Copy the **Client ID** and **Client secret 1** as you'll need them for the WorkOS configuration. --- ## (3) Configure Xero credentials in WorkOS Now that you have the **Xero Client ID** and **Xero Client Secret** from the previous steps, return to the [WorkOS Dashboard](https://dashboard.workos.com). In the **Xero OAuth** configuration dialog, enable the integration. Paste the credentials from Xero into their respective fields in the WorkOS Dashboard. ![OAuth client credentials in the WorkOS Xero setup modal filled with client id and client secret.](https://images.workoscdn.com/images/9bb1cd53-a5cc-4a04-b7d4-2fd9791ad499.png?auto=format&fit=clip&q=50) Click **Save** to complete the configuration. You are now ready to start authenticating with Xero OAuth. You will use the `provider` query parameter in the Get Authorization URL API endpoint to support global Xero OAuth for any domain. The `provider` query parameter should be set to `XeroOAuth`. --- ## Configure Additional OAuth Scopes (Optional) WorkOS will request the OAuth scopes that are required for authentication by default. You can optionally configure your integration to request additional OAuth scopes as needed. When the **Return Xero OAuth tokens** option is selected, the access token and refresh token from Xero will be included in the response from the [Authenticate with code API](/reference/authkit/authentication/code). ![A screenshot showing Xero OAuth scopes configuration in the WorkOS Dashboard](https://images.workoscdn.com/images/a39beaaf-faf4-4fcf-98b7-eeb54f0135fb.png?auto=format&fit=clip&q=50) Any scopes configured here will be included on every Xero OAuth request. To specify additional scopes dynamically, use the `provider_scopes` query parameter on the [Get Authorization URL API endpoint](/reference/authkit/authentication/get-authorization-url). For more information, see Xero's OAuth scopes [documentation](https://developer.xero.com/documentation/oauth2/scopes). --- ## Frequently asked questions ### How is the WorkOS Xero OAuth integration different from implementing regular Xero OAuth flow? It's the same Xero OAuth flow as you could build yourself, but it's encapsulated within WorkOS SSO. This means you don't need to build it yourself. In addition to Xero OAuth, you can use WorkOS SSO to support other identity providers, all with a single integration. ### What is the provider query parameter and how is it used in the Xero OAuth integration? You can use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/sso/get-authorization-url) to support global Xero OAuth for any domain. The `provider` query parameter should be set to `XeroOAuth`. ### What type of Xero integration should I select? You should select **Web app** as the integration type when creating your Xero OAuth application. This is the correct type for OAuth integrations that will work with WorkOS. ### Where can I find my Xero application after creation? After creating your Xero application, you can find it in your [Xero Developer Portal](https://developer.xero.com) under your apps list. From there, you can access the **Configuration** page to manage your OAuth settings and regenerate credentials if needed. ### Workday Learn about syncing your user list with Workday. ## Introduction This guide outlines how to synchronize your application's Workday directories. To synchronize an organization's users and groups provisioned for your application, you'll need the following information from the organization: - The Workday Custom Report JSON endpoint - The Workday Custom Group Report JSON endpoint - Username for accessing the Custom Report endpoint - Password for accessing the Custom Report endpoint > Note: The Workday integration isn't enabled by default in the WorkOS Dashboard or Admin Portal. Please reach out to [support@workos.com](mailto:support@workos.com) or via your team's WorkOS Slack channel if you would like Workday enabled. --- ## (1) Create an Integration System User It's recommended that the organization creates an Integration System User within Workday. The Integration System User will be used to access Custom Reports. ![A screenshot of the "Create Integration System User" form in the Workday Dashboard.](https://images.workoscdn.com/images/24b0561d-cd74-46a1-939e-3c76ead90c89.png?auto=format&fit=clip&q=50) > If you've finished the setup, and everything works as expected but fields are missing from the Report, ensure that the user created has access to access to the fields. ![A screenshot showing user access to a report in the Workday Dashboard.](https://images.workoscdn.com/images/7e3e33f1-3724-4ff9-a4b6-ad2ac475ccb3.png?auto=format&fit=clip&q=50) --- ## (2) Create a Security Group Create a new security group in Workday. Set the Type of Tenanted Security Group to Integration System Security Group (Unconstrained). Then add a name for the Security Group and select OK. ![A screenshot showing the "Create Security Group" form in the Workday Dashboard.](https://images.workoscdn.com/images/5e24e9d0-fba3-4e1d-8782-67c6491b3652.png?auto=format&fit=clip&q=50) Next, for Integration System Users, add the integration system user you created in the previous step, and select OK. ![A screenshot showing where to add the Integration System User in the Workday Dashboard.](https://images.workoscdn.com/images/5483b3eb-3995-48b6-8718-a4eb07ccf681.png?auto=format&fit=clip&q=50) --- ## (3) Add domain security policies to the Security Group Next, you'll need to add domain security policies to the newly created security group. You can access this on the Security Group Settings → Maintain Domain Permissions for Security Group page. ![A screenshot showing where to find the "Maintain Domain Permissions for Security Group" option in the Workday Dashboard.](https://images.workoscdn.com/images/592f1450-d6d4-4a47-adef-6d1ce9007f4a.png?auto=format&fit=clip&q=50&w=2048) You'll need to permit the following domain security policies to have "Get" access under Integration Permissions: - Person Data: Work Contact Information - Workday Accounts - Worker Data: Active and Terminated Workers - Worker Data: All Positions - Worker Data: Business Title on Worker Profile - Worker Data: Current Staffing Information - Worker Data: Public Worker Reports - Worker Data: Workers ![A screenshot showing Integration Permissions in the Workday Dashboard.](https://images.workoscdn.com/images/32f4bae2-9ef0-4a7b-a27e-6c28268298d6.png?auto=format&fit=clip&q=50) To activate these new security settings, you need to go to the Activate Pending Security Policy Changes page and click OK. ![A screenshot showing the Activate Pending Security Policy Changes page in the Workday Dashboard.](https://images.workoscdn.com/images/2c708837-b39d-454f-90b0-acfe377d4ad5.png?auto=format&fit=clip&q=50) Then, select the Confirm checkbox to finish activating. ![A screenshot showing where to confirm the Active Pending Security Policy Changes in the Workday Dashboard.](https://images.workoscdn.com/images/664f3905-d9e6-4390-b210-1e7eaffa25c2.png?auto=format&fit=clip&q=50) --- ## (4) Create and Populate Custom Reports You will need to create two Custom Reports. The first Custom Report will be used for syncing User information. The second report will be used for syncing Group information. When creating the report, make sure to select the Advanced report type and to have the Enable as Web Service box checked. ![A screenshot showing the "Create Custom Report" page in the Workday Dashboard.](https://images.workoscdn.com/images/8fa8ffb7-e377-4289-a130-3719646dea8a.png?auto=format&fit=clip&q=50) You need to add information for certain fields to the report. You can do this by directly adding columns to the report for the attributes in Workday with column heading names specified as follows: ![A screenshot showing an example of Custom User Report in the Workday Dashboard.](https://images.workoscdn.com/images/d3d4bb22-b4c8-467a-a3b4-bd0e6b4d2aea.png?auto=format&fit=clip&q=50) Along the same lines as the User Report, WorkOS looks for the following information in the Group Report: --- ## (5) Add an authorized user If an Integration System User was created, the organization will want to have that user added as an authorized user. This can be found under the **Share** tab from within a Report. ![A screenshot showing the "Share" tab in the Workday Dashboard.](https://images.workoscdn.com/images/8794da9c-89ca-4b84-842b-3f3fe6648d39.png?auto=format&fit=clip&q=50) --- ## (6) Get the RaaS endpoint Now that the Report itself is setup and access to it had been configured, the organization will need to get the RaaS endpoint. The page with the endpoints can be found under **Actions → Web Service → View URLs**. ![A screenshot showing where to find the view URLs option in the Workday Dashboard.](https://images.workoscdn.com/images/d212438c-951b-464f-aa42-2bebd0e2bdf2.png?auto=format&fit=clip&q=50) Once on the URLs page, the one that WorkOS will need is listed under the **JSON** section. ![A screenshot showing the View URLs Web Service page in the Workday Dashboard.](https://images.workoscdn.com/images/8698f25c-22bc-48ee-82c7-5fa885b20215.png?auto=format&fit=clip&q=50) --- ## (7) Create your Directory Sync Connection Login to your WorkOS Dashboard and select "Organizations" from the left hand navigation bar. Select the organization you'll be configuring a new Directory Sync Connection with. Click "Add Directory". ![A screenshot showing where to find the "Add Directory" button in the WorkOS Dashboard.](https://images.workoscdn.com/images/6244ae58-85a4-4c14-b6c0-c12bca04408e.png?auto=format&fit=clip&q=50) Select "Workday" as the directory type, and then input the Company Name. Click the "Create Directory" button. ![A screenshot showing the "Create Directory" button in the WorkOS Dashboard.](https://images.workoscdn.com/images/27e9b01f-52e6-433b-af33-38eb3961dc70.png?auto=format&fit=clip&q=50) --- ## (8) Setup your Directory Sync Connection Click "Update Directory" to input the organization's Custom Report JSON endpoints, username and password. ![A screenshot showing where to find the "Update Directory" button in the WorkOS Dashboard.](https://images.workoscdn.com/images/0c51f74e-8705-4193-93db-126a61bb367c.png?auto=format&fit=clip&q=50) Then, click "Save Directory Details". --- ## (9) View users and groups in your dashboard Now, whenever the organization assigns users or groups to your application, you'll receive Dashboard updates based on changes in their directory. A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) ## Frequently asked questions ### How often does the Workday directory perform a sync? The Workday directory polls in every 30 minutes starting from the time of the initial sync. ### VMware Learn how to configure a connection to VMware via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. --- ## What WorkOS provides WorkOS provides the [SP Metadata](/glossary/sp-metadata) link. It's readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot showing where to find the SP Metadata in the WorkOS dashboard.](https://images.workoscdn.com/images/e253ad08-a85b-4586-bf8c-970059eb286c.png?auto=format&fit=clip&q=50) --- ## What you'll need Next, you will provide the Metadata URL from VMware. Normally, this information will come from the organization's IT Management team when they set up your application's SAML 2.0 configuration in their VMware admin dashboard. But, should that not be the case during your setup, here's how to obtain it. --- ## (1) Create a new SaaS Application In your Workspace ONE Catalog, click "New". Give your application a descriptive name. ![A screenshot showing how to create new application in VMware.](https://images.workoscdn.com/images/576ed672-e030-4f1e-936e-c04d33ff7dfd.png?auto=format&fit=clip&q=50) --- ## (2) Basic SAML Configuration Click the "Configuration" tab from the left sidebar. Copy the SP Metadata Link from your VMware connection in the WorkOS dashboard and paste it in the URL/XML field under Configuration in Workspace One. ![A screenshot showing where to input WorkOS SP metadata when configuring VMware application.](https://images.workoscdn.com/images/6d7bace5-a513-4782-ac18-8327b5e364a3.png?auto=format&fit=clip&q=50) --- ## (3) Advanced SAML Configuration Continue scrolling and expand "Advanced Properties". ![A screenshot showing where to find "Advanced Properties" dropdown in VMware application.](https://images.workoscdn.com/images/dc6d711a-104c-4cd6-bca7-dff852dbb2c9.png?auto=format&fit=clip&q=50) Enable "Sign Assertion" and "Include Assertion Signature". ![A screenshot showing where to enable "Sign Assertion" and "Include Assertion Signature" in VMware application.](https://images.workoscdn.com/images/98b0a17a-51a4-41c4-87be-1ffadfce96aa.png?auto=format&fit=clip&q=50) --- ## (4) Configure Attribute Map Continue scrolling until "Custom Attribute Mapping". ![A screenshot showing where to find "Custom Attribute Mapping" in VMware application.](https://images.workoscdn.com/images/d35112ac-5d76-47c4-aa6c-436321d30b06.png?auto=format&fit=clip&q=50) Fill in the following attribute mappings and select "Next" until you are prompted to "Save". - `id` → `${user.objectGUID}` - `firstName` → `${user.firstName}` - `lastName` → `${user.lastName}` - `email` → `${user.email}` ![A screenshot showing how to configure attribute mappings in VMware application.](https://images.workoscdn.com/images/2ef20a4a-9095-4c35-85b8-cf4e16c79da9.png?auto=format&fit=clip&q=50) Some VMware configurations use `user.ExternalId` instead of `user.objectGUID`. In this case, you would map the id attribute to `user.ExternalId`. ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, map the groups in your identity provider to a SAML attribute named `groups`. > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (5) Upload Metadata URL After saving your SaaS Application, click "Settings" then "SAML Metadata". Click on "Copy URL" next to "Identity Provider (IdP) metadata". ![A screenshot showing where to find metadata URL in VMware application.](https://images.workoscdn.com/images/f99932ab-8828-4b78-a044-0c19c35859dd.png?auto=format&fit=clip&q=50) Back in the WorkOS Dashboard, click on "Edit Metadata Configuration" in the "Metadata Configuration" section of the Connection. ![A screenshot showing where to edit the IdP metadata URL in the WorkOS dashboard.](https://images.workoscdn.com/images/d743c922-1517-4dd2-80ab-cab5e4a9c53f.png?auto=format&fit=clip&q=50) Finally, input the Metadata URL and click "Save Metadata Configuration". Your Connection will then be linked and good to go! ![A screenshot showing how to configure IdP metadata URL in the WorkOS dashboard.](https://images.workoscdn.com/images/30130529-4132-45f6-aa33-70d8760612fd.png?auto=format&fit=clip&q=50) ### Vercel OAuth Learn how to set up OAuth with Vercel ## Introduction The Vercel OAuth integration allows your users to authenticate using their Vercel credentials. The configuration process involves creating an OAuth application in Vercel and configuring the client credentials in your WorkOS Dashboard. --- ## What WorkOS provides When setting up Vercel OAuth, WorkOS provides one key piece of information that needs to be configured in your Vercel OAuth application: - [Redirect URI](/glossary/redirect-uri): The endpoint where Vercel will send authentication responses after successful login The Redirect URI is available in the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select the **Authentication** tab and the **Providers** sub-tab. Locate the **Vercel** section. ![The Vercel OAuth section in the WorkOS Dashboard](https://images.workoscdn.com/images/fbd35719-bb0d-4ccc-a613-a63dc3ba97b5.png?auto=format&fit=clip&q=50) Click **Enable**. The **Vercel OAuth** configuration dialog will open. Locate the **Redirect URI**. ![The Vercel OAuth configuration modal in the WorkOS Dashboard](https://images.workoscdn.com/images/648eb886-837f-4eb2-a366-6d6094187a5d.png?auto=format&fit=clip&q=50) The **Redirect URI** serves as the destination for authentication responses and must be configured in your Vercel OAuth application as the Authorization Callback URL. --- ## What you'll need You will need to obtain two pieces of information from a Vercel OAuth application: - **Vercel Client ID**: Application identifier from Vercel - **Vercel Client Secret**: Authentication secret for the application The following sections will guide you through creating an OAuth application in your Vercel account and generating these credentials. --- ## (1) Create the Vercel OAuth application Log in to your [Vercel account](https://vercel.com/login) and navigate to your team Settings tab. In the left navigation menu, scroll down to select **Apps**. Click **Create** to create a new application. ![Vercel Apps page with Create button](https://images.workoscdn.com/images/1c5a34a7-64c1-42d1-b2e8-363b3e14a1be.png?auto=format&fit=clip&q=50) Choose a name for your app, optionally add a logo, and click Save. --- ## (2) Configure the Vercel OAuth application In the left navigation menu, ensure that the **General** tab is selected. Scroll down to the **Authorization Callback URLs** section, and enter the **Redirect URI** from the Vercel OAuth configuration in the WorkOS Dashboard. Click **Save**. ![Configuring Redirect URI in Vercel](https://images.workoscdn.com/images/b9e526f1-099b-472b-9a46-e9504ae2c106.png?auto=format&fit=clip&q=50) In the left navigation menu, select the **Authentication** tab. In the **Client Authentication Methods** section, make sure that **client\_secret\_post** is selected. ![Configuring Client Authentication Methods in Vercel](https://images.workoscdn.com/images/65baf589-746b-4b33-b648-36f1d8b57c5d.png?auto=format&fit=clip&q=50) In the left navigation menu, select the **Permissions** tab. In the **Scopes** section, enable the **openid**, **email**, and **profile** scopes to allow the application to read basic user profile information. Click **Save**. ![Configuring Scopes in Vercel](https://images.workoscdn.com/images/7240cd69-de9b-4a20-9f1a-13ed6beaf825.png?auto=format&fit=clip&q=50) --- ## (3) Generate client credentials In the left navigation menu, select the **General** tab and view your Client ID in the **Details** section. ![View Client ID in Vercel](https://images.workoscdn.com/images/fef2735e-9a66-47f0-a0d5-e6d402a3ae7d.png?auto=format&fit=clip&q=50) In the left navigation menu, select the **Authentication** tab. Scroll down to the **Client Secrets** section and click **Generate** to generate a new Client Secret. ![Generate Client Secret in Vercel](https://images.workoscdn.com/images/72e4b918-80ec-4aa8-b54a-349ca6d3bff2.png?auto=format&fit=clip&q=50) Note the **Client ID** and **Client Secret** values as you'll need them for the WorkOS configuration. > **Important**: The Client Secret is only shown once. Make sure to copy and store it securely. --- ## (4) Configure Vercel credentials in WorkOS Now that you have the **Vercel Client ID** and **Vercel Client Secret** from the previous step, return to the [WorkOS Dashboard](https://dashboard.workos.com). In the **Vercel OAuth** configuration dialog, enable the integration. Paste the credentials from Vercel into their respective fields in the WorkOS Dashboard. ![Entering Vercel Credentials in WorkOS Dashboard](https://images.workoscdn.com/images/ff653223-0ace-4f91-85f5-48e238e48666.png?auto=format&fit=clip&q=50) Click **Save changes** to complete the configuration. You are now ready to start authenticating with Vercel OAuth. If you are using AuthKit's [Hosted UI](/authkit/hosted-ui), a Continue with Vercel button will be added to your login page. If you are building your own authentication flows outside of AuthKit's hosted UI, you will use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/authkit/authentication/get-authorization-url) to support global Vercel OAuth for any domain. The `provider` query parameter should be set to `VercelOAuth`. --- ## Frequently asked questions ### How is the WorkOS Vercel OAuth integration different from implementing regular Vercel OAuth flow? It's the same Vercel OAuth flow as you could build yourself, but it's encapsulated within WorkOS SSO. This means you don't need to build it yourself. In addition to Vercel OAuth, you can use WorkOS SSO to support other identity providers, all with a single integration. ### What is the provider query parameter and how is it used in the Vercel OAuth integration? If you are building your own authentication flows outside of AuthKit's hosted UI, you can use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/authkit/authentication/get-authorization-url) to support global Vercel OAuth for any domain. The `provider` query parameter should be set to `VercelOAuth`. ### What scopes are required for Vercel OAuth? The **openid**, **profile**, and **email** scopes are required to allow the application to read user profile information necessary for authentication. These scopes provide access to the user's basic profile data and email address. ### Supabase + WorkOS SSO Learn how to use WorkOS for SSO with your Supabase application. ## Introduction This guide outlines the steps to make WorkOS SSO connections available to your application using Supabase Auth. It will require a few changes to your existing Supabase application code. If you are wanting to instead use AuthKit with your Supabase application, check out our [Supabase + AuthKit guide](/integrations/supabase-authkit). --- ## (1) Copy WorkOS Client ID and API Key Supabase uses the WorkOS Client ID and API Key to initiate the authentication flow and to return the SSO user profile. The first step is finding the Client ID and the API Key in the WorkOS dashboard. In the WorkOS dashboard, go to **Configuration** and under the "Settings" tab and copy the Client ID. ![A screenshot showing where to find the Client ID in the WorkOS dashboard configurations page.](https://images.workoscdn.com/images/5cdbbd7e-2141-470c-8b86-b0876974e58a.png?auto=format&fit=clip&q=50) Select **API Keys** on the left-side navigation bar and either copy an existing API Key or create a new API Key and copy it. ![A screenshot showing where the WorkOS API Key is in the dashboard.](https://images.workoscdn.com/images/fe6c9ad1-f04a-4335-9752-4ef149fa3147.png?auto=format&fit=clip&q=50) --- ## (2) Add your WorkOS credentials into your Supabase Project and configure the Redirect URL Sign in to Supabase and then go to your Supabase Project Dashboard. Navigate to **Authentication** → **Explore Auth**. ![A screenshot showing when to the Authentication section is in the Supabase project dashboard.](https://images.workoscdn.com/images/f773aeb8-5bee-4eba-89a0-62441a79be11.png?auto=format&fit=clip&q=50) Select the Providers tab and scroll down to WorkOS and enter the WorkOS URL as **https://api.workos.com**. Then enter the Client ID and API Key copied from the WorkOS Dashboard, toggle to enable WorkOS as a provider and click **Save**. ![A screenshot showing how to enable WorkOS as a provider in Supabase and input the WorkOS URL, Client ID and Secret Key.](https://images.workoscdn.com/images/c275b3f4-807c-4961-916b-c0ed2d6717dd.png?auto=format&fit=clip&q=50) Copy the Redirect URL from the WorkOS provider section. In the [Applications](https://dashboard.workos.com/environment/applications) section of the WorkOS Dashboard, open your application and go to the **Redirects** tab to add the copied Redirect URL. ![A screenshot showing where to add the WorkOS Redirect URL.](https://images.workoscdn.com/images/27ad127c-3631-45d0-aedc-39ab90f03ed6.png?auto=format&fit=clip&q=50) --- ## (3) Add login code to your client app When a user signs in, call `signInWithOAuth` with `workos` as the provider. Pass in a Connection ID, Organization ID, or provider type (for OAuth) under `queryParams`. --- ## Summary With a few lines of code, you can add WorkOS as an SSO provider and enable features like the admin portal and dozens of integrations within your Supabase application. ### Supabase + AuthKit Learn how to use AuthKit with your Supabase application. ## Introduction This guide outlines the steps to use WorkOS as a Supabase [third-party auth provider](https://supabase.com/docs/guides/auth/third-party/overview). This will allow you to authenticate users with AuthKit and use AuthKit access tokens to access Supabase's REST and GraphQL APIs in your app. ## (1) Add a WorkOS third-party auth integration Configure a WorkOS integration in the [Supabase dashboard](https://supabase.com/dashboard/project/_/auth/third-party). ![Supabase 3rd party auth dashboard](https://images.workoscdn.com/images/6494746d-f6d2-46a1-bf26-f4fe7370e12b.png?auto=format&fit=clip&q=50) Your issuer URL is: ```txt title="WorkOS Issuer" https://api_workos_com/user_management/client_123456789 ``` ![Supabase WorkOS Connection dialog](https://images.workoscdn.com/images/e4d5c238-a217-4c9c-a955-a882074919bb.png?auto=format&fit=clip&q=50) ## (2) Set up a JWT Template Supabase RLS policies expect a `role` claim in the access token that corresponds to a database role. WorkOS already adds a `role` claim corresponding to the user's role in an organization. To configure the role claim for Supabase, set up a JWT template in the Authentication page of the [WorkOS Dashboard](https://dashboard.workos.com/environment/authentication/features). Under Features, choose JWT Template: We add a `user_role` claim so that your application can still determine the role assigned to that user. ## (3) Pass the access token to Supabase APIs Pass in your WorkOS client ID and auth domain when initializing the [Supabase client library](https://supabase.com/docs/guides/auth/third-party/workos#setup-the-supabase-client-library). That's it! Supabase will now accept the access tokens returned by AuthKit. ### Slack OAuth Learn how to set up OAuth with Slack ## Introduction The Slack OAuth integration allows your users to authenticate using their Slack credentials through the "Sign in with Slack" flow. The configuration process involves creating or configuring a Slack App and setting up OAuth permissions with the client credentials in your WorkOS Dashboard. --- ## What WorkOS provides When setting up Slack OAuth, WorkOS provides one key piece of information that needs to be configured in your Slack App: - [Redirect URI](/glossary/redirect-uri): The endpoint where Slack will send authentication responses after successful login The Redirect URI is available in the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select the **Authentication** tab and the **OAuth providers** sub-tab. Locate the **Slack** section. ![The Slack OAuth section in the WorkOS Dashboard.](https://images.workoscdn.com/images/9c70cdb3-0b02-4529-919a-3d91235e78cf.png?auto=format&fit=clip&q=50) Click **Enable**. The **Slack OAuth** configuration dialog will open. Locate the **Redirect URI**. ![Slack OAuth Redirect URI in the WorkOS Dashboard.](https://images.workoscdn.com/images/c7800ed9-c9b9-4893-8821-e3af465362c5.png?auto=format&fit=clip&q=50) The **Redirect URI** serves as the destination for authentication responses and must be configured in your Slack App's OAuth & Permissions settings. --- ## What you'll need You will need to obtain two pieces of information from a Slack App: - **Slack Client ID**: Application identifier from Slack - **Slack Client Secret**: Authentication secret for the application The following sections will guide you through creating or configuring a Slack App and generating these credentials. --- ## (1) Create or open your Slack App Navigate to the [Slack App management page](https://api.slack.com/apps). If you don't already have a Slack App, click **Create an App**, provide a name, and choose the development workspace where you'll test. ![The Slack API portal showing the create new app button.](https://images.workoscdn.com/images/127f704d-ce13-49e0-9d82-2ba123547e3e.png?auto=format&fit=clip&q=80) Once created, open your new Slack App to configure it. --- ## (2) Configure OAuth & Permissions In your Slack App's settings, go to **OAuth & Permissions** in the left-hand navigation menu. Under **Redirect URLs**, add the **Redirect URI** from the WorkOS Dashboard. ![The Slack API portal showing where to configure your redirect URI.](https://images.workoscdn.com/images/f0e7d586-a8e1-4a67-8c06-085dc4009b32.png?auto=format&fit=clip&q=80) Click **Save URLs** to confirm. Under **Scopes**, ensure you request the standard OpenID scopes (e.g., `openid`, `profile`, `email`), which Slack requires for Sign in with Slack using OIDC. --- ## (3) Retrieve Slack credentials Still in your Slack App's settings, find your **Client ID** and **Client Secret**. Copy both values as you'll need them for the WorkOS configuration. --- ## (4) Configure Slack credentials in WorkOS Now that you have the **Slack Client ID** and **Slack Client Secret** from the previous steps, return to the [WorkOS Dashboard](https://dashboard.workos.com). In the **Slack OAuth** configuration dialog, enable the integration. Paste the credentials from Slack into their respective fields in the WorkOS Dashboard. ![The WorkOS dashboard with the Slack OAuth connection enabled.](https://images.workoscdn.com/images/c9c7c0de-c1f1-4d73-8f68-1b415d3dc5cb.png?auto=format&fit=clip&q=50) Click **Save** to complete the configuration. --- ## Frequently asked questions ### How is the WorkOS Slack OAuth integration different from implementing regular Slack OAuth flow? It's the same Slack OAuth flow as you could build yourself, but it's encapsulated within WorkOS SSO. This means you don't need to build it yourself. In addition to Slack OAuth, you can use WorkOS SSO to support other identity providers, all with a single integration. ### What is the provider query parameter and how is it used in the Slack OAuth integration? You can use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/sso/get-authorization-url) to support Slack OAuth for any domain. The `provider` query parameter should be set to `SlackOAuth`. ### What scopes are required for Slack OAuth? The standard OpenID scopes (`openid`, `profile`, `email`) are required for Sign in with Slack using OIDC. These scopes provide access to the user's basic profile information necessary for authentication. ### SimpleSAMLphp Learn how to configure a SimpleSAMLphp connection. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a SimpleSAMLphp SAML Connection, you'll need the Identity Provider Metadata URL that is available from the organization's SimpleSAMLphp instance. --- ## What WorkOS provides WorkOS provides the [ACS URL](/glossary/acs-url), the [SP Metadata](/glossary/sp-metadata) Link and the [SP Entity ID](/glossary/sp-entity-id). They are readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot showing where to find the ACS URL, SP Metadata and SP Entity ID in the WorkOS dashboard.](https://images.workoscdn.com/images/e2c962f1-2fe9-470f-af1f-684fe651fcbc.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. The SP Metadata link contains a metadata file that the organization can use to set up the SAML integration. The SP Entity ID is a URI used to identify the issuer of a SAML request, response, or assertion. --- ## What you'll need In order to integrate, you'll need the [IdP Metadata URL](/glossary/idp-metadata). Normally, this will come from the organization's IT Management team when they set up your application's SAML configuration in their SimpleSAMLphp instance. But, should that not be the case during your setup, here's how to obtain it. --- ## (1) Configure SAML Application with Service Provider Details Follow the [SimpleSAMLphp documentation](https://simplesamlphp.org/docs/stable/simplesamlphp-idp.html) to set up SimpleSAMLphp as an Identity Provider and add a new SP. Copy and paste the ACS URL and SP Entity ID into the corresponding fields for Service Provider configuration. You can find more on how to structure this under "Adding SPs to the IdP" in the SimpleSAMLphp documentation linked above. The necessary SP metadata can also be found in the SP metadata URL provided in the WorkOS Dashboard. --- ## (2) Configure SAML Attributes You will need to send the following 4 required attributes in the SAML Response: `firstName`, `lastName`, `email`, and `id`. Ensure the following attribute mapping is set: - A user's first name → `firstName` - A user's last name → `lastName` - A user's email address → `email` - A unique identifier representing a user → `id` ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, map the groups in your identity provider to a SAML attribute named `groups`. > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (3) Obtain Identity Provider Metadata Obtain the IdP Metadata URL. As noted in the ["Adding this IdP to other SPs" section of the SimpleSAMLphp documentation](https://simplesamlphp.org/docs/stable/simplesamlphp-idp.html), the IdP metadata URL should be available from `/saml2/idp/metadata.php`. ![A screenshot showing where to edit the IdP metadata URL in the WorkOS dashboard.](https://images.workoscdn.com/images/07f6f9a0-4331-4124-b90e-dc8d24f7e2ea.png?auto=format&fit=clip&q=50) Alternatively, you can manually configure the connection by providing the IdP URI (Entity ID), [IdP SSO URL](/glossary/idp-sso-url) and X.509 Certificate. ![A screenshot showing how to switch to manual IdP metadata configuration in the WorkOS dashboard.](https://images.workoscdn.com/images/07c47c03-354d-4df4-bdb9-bc25573aeb25.png?auto=format&fit=clip&q=50) ![A screenshot showing how to manually configure the IdP metadata in the WorkOS dashboard.](https://images.workoscdn.com/images/d838649f-ee75-429e-94b2-c1693294b81c.png?auto=format&fit=clip&q=50) Your Connection will then be Active and good to go! ### Shibboleth Unsolicited SAML Learn how to configure a Shibboleth Unsolicited connection via SAML. ## Introduction These instructions are for connecting to Shibboleth using the [UnsolicitedSSOConfiguration](https://shibboleth.atlassian.net/wiki/spaces/IDP4/pages/1265631696/UnsolicitedSSOConfiguration). If the organization requires the [generic SAML 2.0 configuration](https://shibboleth.atlassian.net/wiki/spaces/IDP4/pages/1265631694/SAML2SSOConfiguration) instead, please use the [Shibboleth Generic SAML provider documentation](/integrations/shibboleth-generic-saml). Each SSO Identity Provider requires specific information to create and configure a new [connection](/glossary/connection). Often, the information required to create a connection will differ by Identity Provider. To create a Shibboleth Unsolicited SAML connection, you'll need the Identity Provider metadata that is available from the organization's Shibboleth instance. Start by logging in to your WorkOS dashboard and browse to the "Organizations" tab on the left hand navigation bar. Select the organization you wish to configure a Shibboleth Unsolicited SAML connection for, and select "Manually Configure Connection" under "Identity Provider". ![Create New Connection in WorkOS Dashboard](https://images.workoscdn.com/images/c4cf0500-9155-42dd-aa2d-fd40fbbc79bc.png?auto=format&fit=clip&q=50) Select "Shibboleth Unsolicited SAML" from the Identity Provider dropdown, enter a descriptive name for the connection, and then select the "Create Connection" button. ![Select Shibboleth Unsolicited SAML Provider](https://images.workoscdn.com/images/8a32ce47-1087-420d-87b3-49e031308ae7.png?auto=format&fit=clip&q=50) --- ## What WorkOS provides Once you've created your connection, WorkOS provides the [ACS URL](/glossary/acs-url), [SP Metadata](/glossary/sp-metadata) link, and [SP Entity ID](/glossary/sp-entity-id). It's readily available in your connection settings in the [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot showing where to find the ACS URL, SP Metadata and SP Entity ID in the WorkOS dashboard.](https://images.workoscdn.com/images/a19338a8-f7a4-432a-8e7f-0f1b27a5422e.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. The SP Metadata link contains a metadata file that the organization can use to set up the Shibboleth Unsolicited SAML integration. The SP Entity ID is a URI used to identify the issuer of a SAML request and the audience of a SAML response. In this case, the SP Entity ID is used to communicate that WorkOS will be the party performing SAML requests to the organization's Shibboleth instance, and that WorkOS is the intended audience of the SAML responses from the Shibboleth instance. --- ## What you'll need In order to integrate you'll need the Shibboleth IdP metadata. Normally, this information will come from the organization's IT Management team when they set up your application's Shibboleth configuration. But, should that not be the case during your setup, here's how to obtain them. --- ## (1) Enter Service Provider Details Copy and Paste the "ACS URL" and "SP Entity ID" into the corresponding fields for Service Provider details and configuration. For some Shibboleth setups, you can use the metadata found at the SP Metadata link to configure the Shibboleth connection. --- ## (2) Obtain Identity Provider Metadata Download the IdP metadata from the Shibboleth instance. Refer to the [Shibboleth documentation](https://shibboleth.atlassian.net/wiki/spaces/CONCEPT/pages/928645275/MetadataForIdP) for more information on this metadata file. Keep in mind where the file was saved, as we'll be uploading it later to configure the connection. --- ## (3) Configure Attribute Mapping At a minimum, the Attribute Statement in the SAML Response should include `id`, `email`, `firstName`, and `lastName` attributes. Refer to the [Shibboleth documentation](https://shibboleth.atlassian.net/wiki/spaces/CONCEPT/pages/928645122/SAMLAttributeNaming) for more information on adding and mapping attributes. ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, map the groups in your identity provider to a SAML attribute named `groups`. > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (4) Upload Metadata File In the connection settings in the WorkOS dashboard, click "Edit Metadata Configuration". ![A screenshot showing where to edit the IdP metadata URL in the WorkOS dashboard.](https://images.workoscdn.com/images/eaf5a624-5a5a-4702-a4f8-1cb3d55ed6e9.png?auto=format&fit=clip&q=50) Upload the XML metadata file from Shibboleth into the "Metadata File" field and select "Save Metadata Configuration". Your connection will then be linked and good to go! ![A screenshot showing where to upload and how to save the IdP metadata URL in the WorkOS dashboard.](https://images.workoscdn.com/images/ad7fc5c3-f3cf-4860-a219-00838ee5e766.png?auto=format&fit=clip&q=50) ### Shibboleth Generic SAML Learn how to configure a Shibboleth Generic connection via SAML. ## Introduction These instructions are for connecting to Shibboleth using the [generic SAML 2.0 configuration](https://shibboleth.atlassian.net/wiki/spaces/IDP4/pages/1265631694/SAML2SSOConfiguration). If the organization requires the [UnsolicitedSSOConfiguration](https://shibboleth.atlassian.net/wiki/spaces/IDP4/pages/1265631696/UnsolicitedSSOConfiguration) instead, please use the [Shibboleth Unsolicited SAML provider documentation](/integrations/shibboleth-unsolicited-saml). Each SSO Identity Provider requires specific information to create and configure a new [connection](/glossary/connection). Often, the information required to create a connection will differ by Identity Provider. To create a Shibboleth Generic SAML connection, you'll need the Identity Provider metadata that is available from the organization's Shibboleth instance. Start by logging in to your WorkOS dashboard and browse to the "Organizations" tab on the left hand navigation bar. Select the organization you wish to configure a Shibboleth Generic SAML connection for, and select "Manually Configure Connection" under "Identity Provider". ![A screenshot showing where to find "Manually Configure Connection" in the WorkOS Dashboard.](https://images.workoscdn.com/images/f07dc8e4-e97c-4bd0-9dbd-14915cd46e40.png?auto=format&fit=clip&q=50) Select "Shibboleth Generic SAML" from the Identity Provider dropdown, enter a descriptive name for the connection, and then select the "Create Connection" button. ![A screenshot showing "Create Connection" details in the WorkOS Dashboard.](https://images.workoscdn.com/images/640b70d1-60ce-48c7-865f-2441325a078c.png?auto=format&fit=clip&q=50) --- ## What WorkOS provides Once you've created your connection, WorkOS provides the [ACS URL](/glossary/acs-url), [SP Metadata](/glossary/sp-metadata) link, and [SP Entity ID](/glossary/sp-entity-id). It's readily available in your connection settings in the [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot showing where to find the ACS URL, SP Metadata and SP Entity ID in the WorkOS Dashboard.](https://images.workoscdn.com/images/efd8ea95-9dbd-4a18-b961-7d9d1b4bc3ce.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. The SP Metadata link contains a metadata file that the organization can use to set up the Shibboleth Generic SAML integration. The SP Entity ID is a URI used to identify the issuer of a SAML request and the audience of a SAML response. In this case, the SP Entity ID is used to communicate that WorkOS will be the party performing SAML requests to the organization's Shibboleth instance, and that WorkOS is the intended audience of the SAML responses from the Shibboleth instance. --- ## What you'll need In order to integrate you'll need the Shibboleth IdP metadata. Normally, this information will come from the organization's IT Management team when they set up your application's Shibboleth configuration. But, should that not be the case during your setup, here's how to obtain them. --- ## (1) Enter Service Provider Details Copy and Paste the "ACS URL" and "SP Entity ID" into the corresponding fields for Service Provider details and configuration. For some Shibboleth setups, you can use the metadata found at the SP Metadata link to configure the Shibboleth connection. --- ## (2) Obtain Identity Provider Metadata Download the IdP metadata from the Shibboleth instance. Refer to the [Shibboleth documentation](https://shibboleth.atlassian.net/wiki/spaces/CONCEPT/pages/928645275/MetadataForIdP) for more information on this metadata file. Keep in mind where the file was saved, as we'll be uploading it later to configure the Connection. --- ## (3) Configure Attribute Mapping At a minimum, the Attribute Statement in the SAML Response should include `id`, `email`, `firstName`, and `lastName` attributes. Refer to the [Shibboleth documentation](https://shibboleth.atlassian.net/wiki/spaces/CONCEPT/pages/928645122/SAMLAttributeNaming) for more information on adding and mapping attributes. ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, map the groups in your identity provider to a SAML attribute named `groups`. Once your SAML app is configured to return groups, navigate to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (4) Upload Metadata File In the connection settings in the WorkOS Dashboard, click "Edit Metadata Configuration". ![A screenshot showing where to edit the IdP metadata URL in the WorkOS Dashboard.](https://images.workoscdn.com/images/8fb3610f-15a3-4e10-8441-50121bd32609.png?auto=format&fit=clip&q=50) Upload the XML metadata file from Shibboleth into the "Metadata File" field and select "Save Metadata Configuration". Your connection will then be linked and good to go! ![A screenshot showing where to upload and how to save the IdP metadata URL in the WorkOS Dashboard.](https://images.workoscdn.com/images/d9745f3c-4b3f-4e43-aea2-1b21e7160909.png?auto=format&fit=clip&q=50) ### SFTP Learn about syncing users with an SFTP connection ## Introduction To set up an SFTP (Secure File Transfer Protocol) directory sync connection, you'll need to provide the organization's IT team with specific configuration details from WorkOS. This allows them to upload CSV files containing user and group information via SFTP. WorkOS maintains a receiving SFTP server that the organization's HRIS provider or SFTP client can connect to. If the organization's HRIS has a built-in SFTP client, SFTP will allow them to automatically sync their data and ensure their data is always up to date. An SFTP integration allows for provider-agnostic ingestion of employee data into your product ecosystem. Once the integration is set up, WorkOS automatically creates and hosts an SFTP folder for the organization's HRIS provider to upload files at a regular cadence. An SFTP integration has the following advantages: - Works with any system that has the ability to export CSVs - Has an easy integration path for an organization comfortable working with CSVs and SFTP - Allows a custom cadence of updates for your customer Your application interfaces with an SFTP directory the same as with other directories; receiving [events](/events) when the directory is created or updated: --- ## What WorkOS provides When setting up an SFTP directory sync connection, WorkOS provides two key pieces of information that you'll need to share with the organization: - **SFTP Server URL**: The location where the organization will upload user and group CSV files - **Username**: Authentication credentials for SFTP access These are available in your directory's settings in the [WorkOS Dashboard](https://dashboard.workos.com/) once the connection is configured. ![SFTP directory details in the WorkOS Dashboard.](https://images.workoscdn.com/images/46c63f08-579e-4e60-8cb6-b20d6f95ff8b.png?auto=format&fit=clip&q=50) The SFTP server uses public key authentication, providing secure file transfer capabilities for user and group data synchronization. --- ## What you will need The organization will need to provide a public key for authentication and prepare their user and group data in the required CSV format. You will need to obtain from the organization: - **Public Key**: For SFTP authentication (maximum key length is 2048 bytes; supported keys are: `ED25519`, `RSA`, and `ECDSA`) The organization will need to export their users and groups as CSV files with the structure below. ### `users.csv` This file is required. ### `user_groups.csv` This file is _optional_. ### `groups.csv` This file is _optional_. Additional metadata may be also included in this file. --- ## (1) Set up your directory sync endpoint Login to the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select the **Organizations** tab. Select the appropriate organization for which you will enable a SFTP directory sync connection. On the organization's page, scroll down to the **Directory Sync** section. Click **Configure manually**. ![WorkOS Dashboard showing directory sync card with configure manually button highlighted](https://images.workoscdn.com/images/ebf08eb3-a698-4498-adde-1b551ab0f519.png?auto=format&fit=clip&q=50) Select **SFTP** as the directory type. Input an appropriate name for the connection. Click **Create Directory**. ![The WorkOS Dashboard with a create directory dialog](https://images.workoscdn.com/images/e1010105-9c22-4d20-88d0-8b316df97ad2.png?auto=format&fit=clip&q=50) --- ## (2) Configure SFTP authentication Obtain the public key from the organization's admin that will be used for SFTP authentication. From the directory page in the WorkOS Dashboard, in the **Directory details** section click the **Update Directory** button. ![A screenshot showing where to find "Update directory" for an Organization in the WorkOS Dashboard.](https://images.workoscdn.com/images/d0847fd0-b9c9-4ec2-aa1e-b69c6aac1fa5.png?auto=format&fit=clip&q=50) Paste the organization's public key into the input field. The SSH public key format should include the key type (e.g. `ssh-rsa`, `ssh-ed25519`), base64 encoded body, and an optional comment, with spaces between each element. For example, `ssh-rsa AAAABB1 keycomment`. RSA, ECDSA, and ED25519 keys are accepted: - For RSA keys, the key type is `ssh-rsa`. - For ED25519 keys, the key type is `ssh-ed25519`. - For ECDSA keys, the key type is either `ecdsa-sha2-nistp256`, `ecdsa-sha2-nistp384`, or `ecdsa-sha2-nistp521`, depending on the size of the key generated. ![A screenshot showing how to update SFTP directory details in the WorkOS Dashboard.](https://images.workoscdn.com/images/77a535f1-87d4-410f-bd7c-09a4535e53c2.png?auto=format&fit=clip&q=50) --- ## (3) Provide SFTP configuration to the organization After adding the public key, WorkOS generates a username. You will see the green **Linked** icon appear. Copy the **Username** and SFTP server URL from the WorkOS Dashboard. Share these values with the organization so they can configure their SFTP client: - **SFTP Server**: `sftp.workos.com` - **Username**: The generated username from the WorkOS Dashboard - **Authentication**: Their private key (corresponding to the public key you uploaded) Instruct the organization to upload their CSV files using these credentials. --- ## (4) Confirm users and groups are synced Now, whenever your customer uploads updated CSV files via SFTP, you'll receive updates based on the changes in their directory data. The **Users** tab within the SFTP connection displays synced users. A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) ## SFTP Security ### How is my organization's data protected in transit? SFTP uses SSH (Secure Shell protocol) to symmetrically encrypt traffic after an asymmetric key negotiation for authentication. Our solution leverages the [AWS Transfer Family](https://docs.aws.amazon.com/transfer/latest/userguide/how-aws-transfer-works.html), so that we can support a common, secure protocol (SSH) with modern, isolated data storage (AWS S3). We leverage the default security policy ([security-policy-transfer-2020-06](https://docs.aws.amazon.com/transfer/latest/userguide/security-policies.html#security-policy-transfer-2020-06)) for the choice of SSH cipher-suites, which determines the strength of cryptographic protection for data in transit. ### How is my organization's data protected at rest? As the data is stored in an AWS S3 bucket the default (since January 2023) is that it is encrypted at rest ([SSE-S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-encryption.html)). The symmetric encryption used is AES-256, more information is available in [the FAQ](https://docs.aws.amazon.com/AmazonS3/latest/userguide/default-encryption-faq.html). ### How does WorkOS isolate one of my organization's data from the other? Each of the organizations you onboard will [create an SSH key pair](/integrations/sftp/what-you-will-need), this consists of a public key, and a private key. They will retain the private key, ensuring that only they can authenticate. The public key uploaded to WorkOS will be used to authenticate the organization's connection via SFTP. Each of your organizations is mapped to a distinct S3 bucket based on an internal (cryptographically random) identifier for the SSH key pair. ### When does WorkOS dispose of the data and how is this done? In either of the following events your organization's data, and the S3 bucket will be deleted: 1. You off-board the organization from your product/service. 2. You no longer use the WorkOS Directory Sync service. --- ## Frequently asked questions ### How often do SFTP directories perform a sync? SFTP directories will sync automatically whenever file changes are detected and every 30 minutes following the initial synchronization. ### SCIM Learn about syncing users with a custom SCIM provider ## Introduction To set up a SCIM v2.0 directory sync connection, you'll need to provide the organization's IT team with specific configuration details from WorkOS. This allows their SCIM server to synchronize users and groups with your application. --- ## What WorkOS provides When setting up a SCIM directory sync connection, WorkOS provides two key pieces of information that you'll need to share with the organization: - [Endpoint](/glossary/endpoint): The URL where the SCIM server will send requests - [Bearer Token](/glossary/bearer-token): Authentication credentials for the endpoint requests Both of these are available in the **Directory details** section of the directory sync connection in the [WorkOS Dashboard](https://dashboard.workos.com/). The endpoint is shown as soon as the directory is created, and bearer tokens are generated on demand from the **Bearer tokens** card on the same page. ![The WorkOS Dashboard showing the directory details card with the endpoint and the Bearer tokens card below it](https://images.workoscdn.com/images/1ae8c088-07d6-4512-9abf-1adec38f6b0b.png?auto=format&fit=clip&q=50) These settings enable the organization's SCIM server to securely send user and group data to your application through WorkOS. > IT contacts can also generate, rotate, and revoke bearer tokens themselves from the [Admin Portal](/admin-portal). See [Bearer token rotation](/admin-portal/token-rotation) for details. --- ## What you will need The organization's IT team will handle the SCIM server configuration on their end. You simply need to provide them with the endpoint URL and bearer token from the WorkOS Dashboard. Typically, the organization's IT team will use these values to configure your application within their SCIM server or identity provider admin dashboard. --- ## (1) Set up your directory sync endpoint Login to the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select the **Organizations** tab. Select the appropriate organization for which you will enable a SCIM directory sync connection. On the organization's page, scroll down to the **Directory Sync** section. Click **Configure manually**. ![WorkOS Dashboard showing directory sync card with configure manually button highlighted](https://images.workoscdn.com/images/ebf08eb3-a698-4498-adde-1b551ab0f519.png?auto=format&fit=clip&q=50) Select **Custom SCIM v2.0** as the directory type. Input an appropriate name for the connection. Click **Create Directory**. ![The WorkOS Dashboard with a create directory dialog showing directory type and name inputs](https://images.workoscdn.com/images/aa5a17d9-0990-4af6-a61f-1640658650e1.png?auto=format&fit=clip&q=50) The directory sync connection will now display the endpoint for the SCIM server. To create a bearer token, click **Generate token** on the **Bearer tokens** card. The token is shown once at creation time — copy it before closing the dialog. > We have support for custom labeled URLs for directory sync endpoints. [Contact us](mailto:support@workos.com) for more info! --- ## (2) Provide SCIM configuration to the organization Copy the **Endpoint** from the **Directory details** section and the bearer token you generated in the previous step. Provide these values to the organization's IT team so they can configure the application within their SCIM server or identity provider admin dashboard: - **Endpoint URL**: The destination where their SCIM server will send user and group data - **Bearer Token**: Authentication credentials for secure communication Once the organization has configured these values in their SCIM server, your application will be ready to receive real-time user and group synchronization. > Need to rotate or revoke a token later? See [Bearer token rotation](/admin-portal/token-rotation) for the full self-serve flow, including how IT contacts can manage tokens directly from the Admin Portal. --- ## (3) Assign users and groups to your application Now, whenever the organization assigns users or groups to your application in their directory, you'll receive real-time dashboard updates based on changes in their system. A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) ### SAML Learn how to configure a new custom SAML connection ## Introduction To set up a SAML connection on behalf of an organization, you'll need the identity provider metadata or manual configuration details from the organization's IT team. --- ## What WorkOS provides When setting up a SAML connection, WorkOS provides three key pieces of information in the **Service Provider Details** section for an SSO connection within the [WorkOS Dashboard](https://dashboard.workos.com/): - [SP Entity ID](/glossary/sp-entity-id): A unique identifier that represents your application in SAML communications - [ACS URL](/glossary/acs-url): The endpoint where identity providers send authentication responses - [SP Metadata](/glossary/sp-metadata): A configuration file containing all necessary SAML settings ![WorkOS Settings](https://images.workoscdn.com/images/bc0ebb05-e918-4217-8435-bfd1c73dd1f6.png?auto=format&fit=clip&q=80) These settings are required to configure a SAML integration. The **ACS URL** serves as the destination for authentication responses, while the **SP Entity ID** uniquely identifies your application in SAML requests and responses. The **SP Metadata** URL provides a complete configuration file that simplifies the setup process for the organization. --- ## What you will need You will need to obtain one of the following from the organization: - [Identity Provider Metadata URL](/glossary/idp-metadata): Configuration URL containing SAML metadata (preferred) - Manual configuration details: SSO URL, Entity ID, and X.509 Certificate (if metadata URL is not available) Typically, the organization's IT team will provide these values when they configure your application in their identity provider admin dashboard. However, if you need to guide them through the process, the following sections will help. --- ## (1) Configure Service Provider Details For SSO to properly function, the organization needs to create and configure a SAML application in their identity provider. Copy the **ACS URL** and **SP Entity ID** from the **Service Provider Details** section in the WorkOS Dashboard. Instruct IT contacts to paste these values into the corresponding fields in their identity provider's admin dashboard. Alternatively, they can use the service provider metadata URL to automatically configure the SAML connection if their identity provider supports metadata-based configuration. --- ## (2) Obtain identity provider metadata After the organization creates a SAML application, their identity provider will provide either a metadata URL or manual configuration details. If they have a metadata URL, in the WorkOS Dashboard, navigate to the **Identity Provider Configuration** section. Click **Edit Configuration**. ![Open Identity Provider Configuration in WorkOS Dashboard](https://images.workoscdn.com/images/a33cc226-7167-4450-8879-9f123fc8ffeb.png?auto=format&fit=clip&q=80) Paste the metadata URL from the organization's IT team into the input field. Your connection will be automatically configured once the metadata is processed. ![Upload identity provider metadata URL to WorkOS Dashboard](https://images.workoscdn.com/images/4d25d1a1-57a0-464d-95d7-a33eb85d2e0f.png?auto=format&fit=clip&q=80) If the organization's identity provider doesn't provide a metadata URL, you'll need to manually configure the connection by clicking the **Switch to Manual Configuration** option and entering the SSO URL, Entity ID, and X.509 Certificate provided by their IT team. ![Switch to Manual Configuration](https://images.workoscdn.com/images/7384d9b7-b918-4778-ac1f-2b389cf73241.png?auto=format&fit=clip&q=80) ![Manually configure connection in WorkOS Dashboard](https://images.workoscdn.com/images/37eaf62e-dd9f-41b0-9e91-221256318298.png?auto=format&fit=clip&q=80) --- ## (3) Configure attribute mapping The organization's SAML provider needs to include specific attributes in the SAML response. Instruct them to configure their SAML application to include the following attributes in the Attribute Statement: - `id`: Maps to the `idp_id` attribute in WorkOS user profiles - `email`: Maps to the `email` attribute in WorkOS user profiles - `firstName`: Maps to the `first_name` attribute in WorkOS user profiles - `lastName`: Maps to the `last_name` attribute in WorkOS user profiles ### Role assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To enable this functionality, instruct the organization to add a `groups` attribute to the SAML response that maps to a list of the user's group memberships. > Finish role assignment set-up by navigating to the SSO connection page in the **Organizations** section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. ### Salesforce SAML Learn how to configure a connection to Salesforce via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [connection](/glossary/connection). And often, the information required to create a connection will differ by Identity Provider. To create an Salesforce SAML connection, you'll need three pieces of information: an [ACS URL](/glossary/acs-url), an [SP Entity ID](/glossary/sp-entity-id), and a [Metadata URL](/glossary/idp-metadata). --- ## What WorkOS provides WorkOS provides the ACS URL and SP Entity ID. It's readily available in your Connection Settings in the [WorkOS dashboard](https://dashboard.workos.com/). ![A screenshot showing where to find the ACS URL and SP Entity ID in the WorkOS dashboard.](https://images.workoscdn.com/images/134a9a2e-3409-4969-9048-01be960c7d93.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. In Salesforce's case, it needs to be set by the organization when configuring Salesforce as an Identity Provider. The Entity ID is a URI used to identify the issuer of a SAML request, response, or assertion. In this case, the entity ID is used to communicate that WorkOS will be the party performing SAML requests to the organization's Salesforce instance. Specifically, the ACS URL and SP Entity ID will need to be set in the Connected Apps setup in Salesforce. ![A screenshot showing where to place the WorkOS ACS URL and SP Entity ID in the Salesforce dashboard.](https://images.workoscdn.com/images/98390601-4c8a-42f4-9965-52ddcd28ff45.png?auto=format&fit=clip&q=50) --- ## What you'll need In order to integrate you'll need the Salesforce Metadata URL. Normally, the this will come from the organization's IT Management team when they set up your application's SAML client in their Salesforce instance. But, should that not be the case during your setup, here's how to obtain it. --- ## (1) Generate Certificate Log in to your Salesforce Account, click the Settings cog icon on the top right, and select "Setup". Once in setup mode you can use the search bar to easily navigate around between settings pages. The first page to navigate to is the "Certificate and Key Management" page. ![A screenshot showing how to navigate to the "Certificate and Key Management" page in the Salesforce dashboard.](https://images.workoscdn.com/images/769b9580-ffc1-46d6-b382-4b5a83222dd8.png?auto=format&fit=clip&q=50) Once in setup mode you can use the search bar to easily navigate around between settings pages. The first page to navigate to is the "Certificate and Key Management" page. If a key does not exist that you would like to use, click "Create Self-Signed Certificate" to generate a new one. ![A screenshot showing how to generate a Self-Signed Certificate in the Salesforce dashboard.](https://images.workoscdn.com/images/fc278a8b-3398-46ff-9a58-143dc127d0e6.png?auto=format&fit=clip&q=50) Give the Certificate a meaningful label and unique name and select the Key Size you'd like to use. It's not necessary to have an Exportable Private Key, but if you are using a key-certificate store you can choose this option. ![A screenshot showing how to configure the Self-Signed Certificate details in the Salesforce dashboard.](https://images.workoscdn.com/images/936558fc-d9c3-4075-a139-3cea3d3854dc.png?auto=format&fit=clip&q=50) --- ## (2) Enable Salesforce as an IdP From the setup search bar browse to the "Identity Provider" portal in Salesforce. If it has not already been done, select "Enable Identity Provider". ![A screenshot showing how to enable Salesforce as an Identity Provider in the Salesforce dashboard.](https://images.workoscdn.com/images/f890533c-dd88-4b05-9cbe-e47b3a416906.png?auto=format&fit=clip&q=50) You will need to select the correct certificate from the previous step. ![A screenshot showing how to select the SAML certificate for the Identity Provider setup in the Salesforce dashboard.](https://images.workoscdn.com/images/f332f289-dad3-491d-a1c3-67e14e381cfc.png?auto=format&fit=clip&q=50) Additionally this page will display the Metadata URL. You will need to copy this URL and in a later step it will be uploaded into WorkOS. ![A screenshot showing where to copy the IdP Metadata URL from in the Salesforce dashboard.](https://images.workoscdn.com/images/e5088944-d7b5-4e3f-8072-d672bbd88f26.png?auto=format&fit=clip&q=50) --- ## (3) Configure SAML Application Next from the setup search bar browse to the "App Manager" portal. Once here you will want to select the option for "New Connected App". ![A screenshot showing how to create a new Connected App in the Salesforce dashboard.](https://images.workoscdn.com/images/af73f2b9-6c91-4b45-87aa-b0e15a2d9a0d.png?auto=format&fit=clip&q=50) Give the App and API a meaningful name and set a contact email that corresponds to who you'd reach out to for support should there be an issue. You can always opt to use `support@workos.com`. ![A screenshot showing how to configure the name and contact email for the new Connected App in the Salesforce dashboard.](https://images.workoscdn.com/images/03a48352-2825-4c6d-aa8d-bfb57f03159f.png?auto=format&fit=clip&q=50) Scroll down further to the "Web App Settings" and check the box for "Enable SAML". Enter the Entity ID and ACS URL into their respective places within the Settings. The "Subject Type" should be set to "User ID" and the "Name ID Format" should be set to `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`. The "Issuer" should populate correctly with your Salesforce subdomain. For the IdP Certificate, select the certificate that matches the one previously used when enabling the Identity Provider, and for the "Signing Algorithm for SAML Messages" choose "SHA256". ![A screenshot showing how to configure the Connected App's Web App Settings in the Salesforce Dashboard.](https://images.workoscdn.com/images/98390601-4c8a-42f4-9965-52ddcd28ff45.png?auto=format&fit=clip&q=50) Save the configurations and you should now see the new Connected App listed under "App Manager". --- ## (4) Configure User Attributes and Claims In the Setup search bar browse to the "Manage Connected Apps" portal. Click on your application and this will open the view where you can configure the attribute mapping, and later on the user profile access permissions. ![A screenshot showing how to open the configurations for the new Connected App in the Salesforce dashboard.](https://images.workoscdn.com/images/6d1dc5a0-d7a5-4e68-a596-5e69f0cb1d52.png?auto=format&fit=clip&q=50) Viewing the app, scroll down to the "Custom Attributes" section and select "New". ![A screenshot showing how to create new Custom Attribute mapping in the Salesforce dashboard.](https://images.workoscdn.com/images/716f679d-907f-42b9-8024-ff74ecff82cc.png?auto=format&fit=clip&q=50) Salesforce automatically includes email as an Attribute so we will need to add three fields: - `id` - `firstName` - `lastName` Configure the fields so the mapping matches the following: ![A screenshot showing how to configure SAML attribute mapping in the Salesforce dashboard.](https://images.workoscdn.com/images/0dfb70bf-744f-4021-ae20-c06ade8f792d.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, create a new custom attribute with a key of `groups`. Map this attribute to a value that contains a user's group membership or role information, such as `$UserRole.Name` in the example below. ![A screenshot showing where to add the groups attribute in the Salesforce dashboard.](https://images.workoscdn.com/images/0f2abfab-25c9-4ce4-aeb4-7f0f3fae8038.png?auto=format&fit=clip&q=50) > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (5) Manage Profiles With Application Access Similarly, viewing the app, there is a "Manage Profiles" section for granting access to control who can log into the application. Select "Manage Profiles" and grant access to the appropriate profiles that should have access to the application in the "Application Profile Assignment" wizard. Select "Save" when complete. ![A screenshot showing how to configure the "Application Profile Assignments" in the Salesforce dashboard.](https://images.workoscdn.com/images/26cdf036-5428-4ccf-b320-f9d1e41250e2.png?auto=format&fit=clip&q=50) Here is an example of a successfully configured "Connected Application" allowing access to anyone with an "End User" Profile. ![A screenshot showing the completed "Application Profile Assignments" in the Salesforce dashboard.](https://images.workoscdn.com/images/fdc0584a-1350-42d7-8816-c8255e307db6.png?auto=format&fit=clip&q=50) --- ## (6) Obtain Identity Provider Details Finally, return to the WorkOS dashboard. Within your connection settings, select "Edit Metadata Configuration" under "Identity Provider Configuration" and provide the Metadata URL you obtained from Salesforce. Your connection will then be verified and good to go! ![A screenshot showing where to add the IdP Metadata URL in the WorkOS dashboard.](https://images.workoscdn.com/images/ff29bcdd-a7df-47d3-88fc-f001a3dae23d.png?auto=format&fit=clip&q=50) ### Salesforce OAuth Learn how to set up OAuth with Salesforce. ## Introduction The Salesforce OAuth integration allows your users to authenticate using their Salesforce credentials. The configuration process involves creating an External Client App in Salesforce and configuring the client credentials in the WorkOS Dashboard. --- ## What WorkOS provides When setting up Salesforce OAuth, WorkOS provides one key piece of information that needs to be configured in your Salesforce External Client App: - [Redirect URI](/glossary/redirect-uri): The endpoint where Salesforce will send authentication responses after successful login The Redirect URI is available in the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select the **Authentication** tab and the **OAuth providers** sub-tab. Locate the **Salesforce** section. ![Open the Salesforce configuration dialog](https://images.workoscdn.com/images/27840df3-434d-4fc0-bae3-aa3dee021f2a.png?auto=format&fit=clip&q=50) Click **Manage**. The **Salesforce OAuth** configuration dialog will open. Locate the **Redirect URI**. ![Salesforce OAuth Redirect URI in the WorkOS Dashboard](https://images.workoscdn.com/images/387b564f-7c4c-4b94-aece-7dc3eb862058.png?auto=format&fit=clip&q=50) The **Redirect URI** serves as the destination for authentication responses and must be configured in your Salesforce External Client App as the authorization callback URL. --- ## What you'll need You will need to obtain two pieces of information from a Salesforce External Client App: - **Salesforce Consumer Key**: Application identifier from Salesforce - **Salesforce Consumer Secret**: Authentication secret for the application The following sections will guide you through creating an External Client App in your Salesforce instance and generating these credentials. --- ## (1) Create the Salesforce External Client App Sign in to Salesforce and navigate to Setup. On the sidebar, select **Apps**, then **External Client Apps**, then **External Client App Manager**. Create a new External Client App. ![The New External Client App button in Salesforce](https://images.workoscdn.com/images/e17fec69-13b5-4281-8311-5854ac1007af.png?auto=format&fit=clip&q=50) --- ## (2) Configure External Client App Fill out the External Client App form. Expand the **API (Enable OAuth Settings)** section, and check the **Enable OAuth** checkbox. For the **Callback URL** input, enter the **Redirect URI** from the WorkOS Dashboard. It is also required to add the "Access the identity URL service" and "Access unique user identifiers" scopes to your app. ![The Salesforce form to create a new External Client App](https://images.workoscdn.com/images/f1ce3367-fc4f-4be6-9529-49835431c38e.png?auto=format&fit=clip&q=50) Under **Security** deselect the **Require Proof Key for Code Exchange (PKCE) extension for Supported Authorization Flows** option, as WorkOS does not currently support PKCE for Salesforce OAuth. Click **Create**. ![The option to disable the PKCE requirement for a Salesforce External Client App](https://images.workoscdn.com/images/7e9a2bda-0ba4-4d33-a5f4-3ae07909a67e.png?auto=format&fit=clip&q=50) After creating your External Client App, click the **Settings** tab, and then expand **OAuth Settings**. Click on **Consumer Key and Secret**. You'll be given the Consumer Key and Secret for your External Client App. Note these values as you'll need them for the WorkOS configuration. --- ## (3) Configure Salesforce credentials in WorkOS Now that you have the **Salesforce Consumer Key** and **Salesforce Consumer Secret** from the previous step return to the [WorkOS Dashboard](https://dashboard.workos.com/). In the **Salesforce OAuth** configuration dialog, paste the credentials from Salesforce into the Client ID and Client Secret fields. ![Where to enter the Salesforce Consumer Key and Salesforce Consumer Secret in the WorkOS Dashboard](https://images.workoscdn.com/images/f65f7819-f9c9-4321-9ba5-9365fa51f4e8.png?auto=format&fit=clip&q=50) Click **Save changes** to complete the configuration. You're now able to authenticate users with Salesforce OAuth. If you are using AuthKit's [Hosted UI](/authkit/hosted-ui), the Login with Salesforce button will be added to your login page. If you are building your own authentication flows outside of AuthKit's hosted UI, you will use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/authkit/authentication/get-authorization-url) to support global Salesforce OAuth for any domain. The `provider` query parameter should be set to `SalesforceOAuth`. --- ## Configure Additional OAuth Scopes (Optional) WorkOS will request the OAuth scopes that are required for authentication by default. You can optionally configure your integration to request additional OAuth scopes as needed. When the **Return Salesforce OAuth tokens** option is selected, the access token from Salesforce will be included in the response from the [Authenticate with code API](/reference/authkit/authentication/code). ![A screenshot showing Salesforce OAuth scopes configuration in the WorkOS Dashboard](https://images.workoscdn.com/images/f1a87bc5-71b3-48fb-b2cf-3052ee39d4b4.png?auto=format&fit=clip&q=50) Any scopes configured here will be included on every Salesforce OAuth request. To specify additional scopes dynamically, use the `provider_scopes` query parameter on the [Get Authorization URL API endpoint](/reference/authkit/authentication/get-authorization-url). You will also have to update your External Client App's configured scopes to include these additional scopes. For more information, see Salesforce's OAuth scopes [documentation](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_tokens_scopes.htm). ## Frequently asked questions ### How is the WorkOS Salesforce OAuth integration different from implementing regular Salesforce OAuth flow? It's the same Salesforce OAuth flow as you could build yourself, but it's encapsulated within WorkOS SSO. This means you don't need to build it yourself. In addition to Salesforce OAuth, you can use WorkOS SSO to support other identity providers, all with a single integration. ### What is the provider query parameter and how is it used in the Salesforce OAuth integration? You can use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/authkit/authentication/get-authorization-url) to support global Salesforce OAuth for any domain. The `provider` query parameter should be set to `SalesforceOAuth`. ### What scopes are required for Salesforce OAuth? The **openid**, **profile**, and **email** scopes are required to allow the application to read user profile information necessary for authentication. These scopes provide access to the user's basic profile data. ### SailPoint SCIM Learn about syncing users with SailPoint SCIM ## Introduction To set up a SailPoint SCIM v2.0 directory sync connection, you'll need to provide the organization's IT team with specific configuration details from WorkOS. This allows their SailPoint SCIM server to synchronize users and groups with your application. --- ## What WorkOS provides When setting up a SailPoint SCIM directory sync connection, WorkOS provides two key pieces of information that you'll need to share with the organization: - [Endpoint](/glossary/endpoint): The URL where the SailPoint SCIM server will send requests - [Bearer Token](/glossary/bearer-token): Authentication credentials for the endpoint requests Both of these are available in the **Directory details** section of the directory sync connection in the [WorkOS Dashboard](https://dashboard.workos.com/). ![The WorkOS dashboard, highlights the directory details card with filled endpoint and bearer token inputs](https://images.workoscdn.com/images/1ae8c088-07d6-4512-9abf-1adec38f6b0b.png?auto=format&fit=clip&q=50) These settings enable the organization's SailPoint SCIM server to securely send user and group data to your application through WorkOS. --- ## What you will need The organization's IT team will handle the SailPoint SCIM server configuration on their end. You simply need to provide them with the endpoint URL and bearer token from the WorkOS Dashboard. Typically, the organization's IT team will use these values to configure your application within their SailPoint SCIM server or identity provider admin dashboard. --- ## (1) Set up your directory sync endpoint Login to the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select the **Organizations** tab. Select the appropriate organization for which you will enable a SailPoint SCIM directory sync connection. On the organization's page, scroll down to the **Directory Sync** section. Click **Configure manually**. ![WorkOS Dashboard showing directory sync card with configure manually button highlighted](https://images.workoscdn.com/images/ebf08eb3-a698-4498-adde-1b551ab0f519.png?auto=format&fit=clip&q=50) Select **SailPoint** as the directory type. Input an appropriate name for the connection. Click **Create Directory**. ![The WorkOS Dashboard with a create directory dialog showing directory type and name inputs](https://images.workoscdn.com/images/aa5a17d9-0990-4af6-a61f-1640658650e1.png?auto=format&fit=clip&q=50) The directory sync connection will now display the endpoint for the SailPoint SCIM server and the bearer token. > We have support for custom labeled URLs for directory sync endpoints. [Contact us](mailto:support@workos.com) for more info! --- ## (2) Provide SailPoint SCIM configuration to the organization Copy the **Endpoint** and **Bearer Token** from the **Directory details** section on the directory page of the WorkOS Dashboard. Provide these values to the organization's IT team so they can configure the application within their SailPoint SCIM server or identity provider admin dashboard: - **Endpoint URL**: The destination where their SailPoint SCIM server will send user and group data - **Bearer Token**: Authentication credentials for secure communication Once the organization has configured these values in their SailPoint SCIM server, your application will be ready to receive real-time user and group synchronization. --- ## (3) Assign users and groups to your application Now, whenever the organization assigns users or groups to your application in their directory, you'll receive real-time dashboard updates based on changes in their system. A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync). ### Rippling SCIM Learn about syncing your user list with Rippling SCIM v2.0. ## Introduction This guide outlines how to synchronize your application's Rippling directories using SCIM. To synchronize an organization's users and groups provisioned for your application, you'll need to provide the organization with two pieces of information: - An [Endpoint](/glossary/endpoint) that Rippling will make requests to. - A [Bearer Token](/glossary/bearer-token) for Rippling to authenticate its endpoint requests. Both of these are available in your Endpoint's Settings in the [WorkOS Dashboard](https://dashboard.workos.com). > Steps 2, 3, and 4 below will need to be carried out by the organization when configuring your application in their Rippling instance. --- ## (1) Set up your Directory Sync endpoint Login to your WorkOS Dashboard and select "Organizations" from the left hand navigation bar. Select the organization you'll be configuring a new Directory Sync for. Under "Actions" click "Add Directory". ![A screenshot showing where to click "Add Directory" in the WorkOS dashboard.](https://images.workoscdn.com/images/0f13d97a-b2a8-4263-ad11-e8e7633f3ae5.png?auto=format&fit=clip&q=50) Select "Rippling" from the dropdown, and enter the organization name. Then, click "Create Directory." ![A screenshot showing where to name and create a Rippling Directory in the WorkOS dashboard.](https://images.workoscdn.com/images/83cd8619-6ccd-4d49-9a69-5c0cd04dd8d6.png?auto=format&fit=clip&q=50) Your Rippling directory sync has now been created successfully with an Endpoint and Bearer Token. ![A screenshot showing where to locate the Rippling directory details in the WorkOS dashboard.](https://images.workoscdn.com/images/98b1e1f1-b601-4df0-97bc-cfa824a7559e.png?auto=format&fit=clip&q=50) > We have support for custom URLs for Directory Sync endpoints. [Contact us](mailto:support@workos.com) for more info! --- ## (2) Create your Rippling application Log in to the Rippling admin dashboard and select the "Custom App" option in the menu under the "Identity Management" category. ![A screenshot showing where to select the "Custom App" option in the "Identity Management" menu in Rippling.](https://images.workoscdn.com/images/2851bbb9-a486-4e51-90c1-6265959cb336.png?auto=format&fit=clip&q=50) Select "Create New App" in the Custom App page. ![A screenshot showing where to select "Create New App" in Rippling.](https://images.workoscdn.com/images/bd2b1fba-2433-4fc2-b20b-7a0ca712dd20.png?auto=format&fit=clip&q=50) Fill out the application's name, select categories, upload an image for the logo, and check the "User Management via SCIM" box. Click "Continue" and the next page will populate more option fields regarding SCIM setup. ![A screenshot showing where to fill in the name, categories, logo, and type of custom app in Rippling.](https://images.workoscdn.com/images/74bf5e11-239e-4cf4-b3ce-af819d3c7b95.png?auto=format&fit=clip&q=50) ## (3) Configure your integration Set the SCIM version to 2.0. Fill in the endpoint into the "SCIM Base URL" field. ![A screenshot showing where to set the SCIM version and "SCIM Base URL" in Rippling.](https://images.workoscdn.com/images/a4fce113-4383-42b4-9d46-eac1e2ec6941.png?auto=format&fit=clip&q=50) Set the SCIM authorization method to "Bearer Token" in the "SCIM Authorization Method" dropdown list. Check off features for groups, pagination, delete groups and PATCH groups. ![A screenshot showing the SCIM authorization method and configuration options in Rippling.](https://images.workoscdn.com/images/9c9c19cc-0836-4aa9-90e0-fb42d751594b.png?auto=format&fit=clip&q=50) Add SCIM attributes `externalId`, `emails.primary`, `name.givenName`, `name.familyName` to the "Supported SCIM Attributes" input box. If you have additional custom attributes, add the appropriate corresponding Rippling values of the custom attributes. Click "Continue" to move to the next step. ![A screenshot showing the "Supported SCIM Attributes" field in Rippling.](https://images.workoscdn.com/images/566a60cf-044e-423e-b1ee-d1cbee96440b.png?auto=format&fit=clip&q=50) Rippling will then prompt you to install the app. Click "Install now" and proceed through the next step. Then, copy and paste the Bearer Token into the "Bearer Token" field and click "Continue". ![A screenshot showing where to enter the Bearer Token in Rippling.](https://images.workoscdn.com/images/bb2ce893-3c9e-4d97-a7f8-4e0bb7128843.png?auto=format&fit=clip&q=50) ## (4) Assign users and groups to your application After entering the Bearer Token, the following two pages "App Access Rules" and "Provision Time", can be filled out by your own preference. You should then arrive at the "Account Matching" page. In order for your users and groups to be synced, you will need to assign them to your Rippling Application. Match the Rippling users to the account, or create a new application account for the user(s). ![A screenshot showing where to match Rippling users to an account in Rippling.](https://images.workoscdn.com/images/c95d76d4-721a-4626-9ee7-6e33c124bf91.png?auto=format&fit=clip&q=50) Create groups for the application as needed. ![A screenshot showing where to create a group in Rippling.](https://images.workoscdn.com/images/49677af7-9dce-48cb-b32b-94df728644f0.png?auto=format&fit=clip&q=50) Name the group. ![A screenshot showing where to name a group in Rippling.](https://images.workoscdn.com/images/073ca80c-42c2-4f65-abd2-50e8af89dd2b.png?auto=format&fit=clip&q=50) Assign Rippling users/groups to the newly created application group. ![A screenshot showing where to assign users and groups to a newly created application in Rippling.](https://images.workoscdn.com/images/aa94731f-f5c3-4517-818f-383a64924dc3.png?auto=format&fit=clip&q=50) Make sure all attributes previously added are enabled, and that their cadence is set to "On user creation and updates". Then, click "Save" and "Continue" to finish setup. ![A screenshot showing where to ensure that all attributes are enabled in Rippling.](https://images.workoscdn.com/images/aa067d8d-b62f-459d-b640-e577a2050b67.png?auto=format&fit=clip&q=50) In your WorkOS dashboard, you should now see the users and groups synced over. ![A screenshot showing a successfully synced user from Rippling in the WorkOS dashboard.](https://images.workoscdn.com/images/c38e1ba8-90e3-4cf0-a008-443f8c77f6a2.png?auto=format&fit=clip&q=50) A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) ## Frequently asked questions ### Can I add additional custom fields to this SCIM integration? Yes, however Rippling allows only a limited set of custom fields in SCIM applications. ### Rippling SAML Learn how to configure a connection to Rippling via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a Rippling SAML Connection, you'll need the Identity Provider metadata that is available from creating an app within the Rippling instance. Start by logging in to your WorkOS dashboard and browse to the "Organizations" tab on the left hand navigation bar. Select the organization you wish to configure a Rippling SAML Connection for, and select "Manually Configure Connection" under "Identity Provider". ![A screenshot showing where to select "Manually Configure Connection" in the WorkOS dashboard.](https://images.workoscdn.com/images/8fb3c79a-f154-4e74-ac23-0330f36dbb62.png?auto=format&fit=clip&q=80) Select "Rippling SAML" from the Identity Provider dropdown, enter a descriptive name for the connection, and then select the "Create Connection" button. ![A screenshot showing the "Create Connection" modal with options configured in the WorkOS dashboard.](https://images.workoscdn.com/images/75e3d01e-a653-4ab5-a460-caced555226f.png?auto=format&fit=clip&q=80) --- ## Introduction WorkOS provides the [ACS URL](/glossary/acs-url) and [SP Entity ID](/glossary/sp-entity-id). They're readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/) ![A screenshot showing the "ACS URL" and "SP Entity ID" in the WorkOS dashboard.](https://images.workoscdn.com/images/b1d10058-5f92-441f-8f3d-615983e93489.png?auto=format&fit=clip&q=80) The ACS URL is the location an Identity Provider redirects its authentication response to. The Entity ID is a URI used to identify the issuer of a SAML request, response, or assertion. In this case, the Entity ID is used to communicate that WorkOS will be the party performing SAML requests to the organization's Rippling instance. --- ## What you'll need In order to integrate you'll need the Rippling IdP metadata. Normally, this information will come from the organization's IT Management team when they set up your application's Rippling configuration. But, should that not be the case during your setup, here's how to obtain them. --- ## (1) Create A New SAML Application In Rippling Log in to Rippling as an administrator and select "IT Management" then "Custom App" from the left-side navigation bar. !["A screenshot showing where to select "Custom App" in the Rippling dashboard.](https://images.workoscdn.com/images/a56252d2-4e9a-4839-b540-0239b0360756.png?auto=format&fit=clip&q=80) Select "Create New App" to begin creating a new SAML application. ![A screenshot showing where to select "Create New App" in the Rippling dashboard.](https://images.workoscdn.com/images/49a2345a-bacc-4332-ad2d-a43f4884279f.png?auto=format&fit=clip&q=80) Give the app a descriptive name, select a category, and upload a logo file. Make sure to check the box for "Single Sign-On (SAML)", then click "Continue". ![A screenshot showing where to configure the new app's "Name", "Categories", and app type in the Rippling dashboard.](https://images.workoscdn.com/images/f2d7947a-81eb-459d-b823-a84fc2e031ed.png?auto=format&fit=clip&q=80) Select the option confirming that you are the Application Admin. Rippling will display a new page with "SSO Setup Instructions" we will use in the next step. ![A screenshot showing the configuration of the "Who should install the SAML App?" setting in the Rippling dashboard.](https://images.workoscdn.com/images/2a71a48e-3765-4d85-8cb2-a0111ff2c28a.png?auto=format&fit=clip&q=80) ## (2) Download IdP Metadata From Rippling Rippling will present the SSO Setup instructions which will include the [IdP Metadata](/glossary/idp-metadata) XML file. Click to download the file from Rippling. ![A screenshot showing where to download the IdP Metadata in the Rippling dashboard.](https://images.workoscdn.com/images/b58647d3-283c-4151-b714-9b0c5c8c33b3.png?auto=format&fit=clip&q=80) Save this file in a memorable place, as we will upload it to the WorkOS dashboard in a later step. --- ## (3) Enter Service Provider Details and Configure App Settings Scrolling down on the SSO Setup Instructions, Rippling will request the ACS URL and Service Provider Entity ID. Input the ACS URL and SP Entity ID from the WorkOS dashboard into the respective fields. Once complete, click the "Move to Next Step Button". ![A screenshot showing where to input the WorkOS ACS URL and SP Entity ID in the Rippling dashboard.](https://images.workoscdn.com/images/482b6b5e-8c29-4675-8de9-a3bbe1240c3c.png?auto=format&fit=clip&q=80) Select your desired Access Rules. ![A screenshot showing where to select SSO Access Rules in the Rippling dashboard.](https://images.workoscdn.com/images/f0833317-cb61-4b92-894d-c2c66a0d1af3.png?auto=format&fit=clip&q=80) Select your desired Provision Time. ![A screenshot showing where to select Provision Time in the Rippling dashboard.](https://images.workoscdn.com/images/98f45313-64ab-4bc5-b1c9-aabfa4ef3478.png?auto=format&fit=clip&q=80) Configure SSO for Admins if necessary. ![A screenshot showing where to configure Admin SSO in the Rippling dashboard.](https://images.workoscdn.com/images/9b5ac438-7bc6-4e76-92b5-db21ce8e79ba.png?auto=format&fit=clip&q=80) Configure Group Attributes if necessary. ![A screenshot showing where to configure Group Attributes in the Rippling dashboard.](https://images.workoscdn.com/images/8c0b2600-a5b7-46df-80d1-347daff1840c.png?auto=format&fit=clip&q=80) Verify your SSO integration if you want to test the connection. ![A screenshot showing where to verify an SSO connection in the Rippling dashboard.](https://images.workoscdn.com/images/0d1c0474-ae85-46a9-982b-0eec7f8ab4e0.png?auto=format&fit=clip&q=80) Click "Visit the app". The application settings will be presented, here we will configure the SAML attribute mapping in the next step. ![A screenshot showing where to select "Visit the app" in the Rippling dashboard.](https://images.workoscdn.com/images/f67e94c8-99db-462c-943a-98e58c086fd6.png?auto=format&fit=clip&q=80) --- ## (4) Configure Attribute Mapping Select the "Settings" tab then on the left navigation select "SAML Attributes" and use the "Create new" button. Add attributes as "Global attributes". ![A screenshot showing where to select "Create New" in the "SAML Attributes" in the Rippling dashboard.](https://images.workoscdn.com/images/8b900811-0089-4e56-a770-06bae8d097b6.png?auto=format&fit=clip&q=80) Input the attributes as follows: - `id` → `User's ID` - `email` → `User's email address` - `firstName` → `User's Legal first name` - `lastName` → `User's Legal last name` Here is a screenshot showing the proper final configuration: ![A screenshot showing the proper configuration of the "SAML Attributes" in the Rippling dashboard.](https://images.workoscdn.com/images/73bc17dc-fc0f-43f6-901f-a6bcd92caf17.png?auto=format&fit=clip&q=80) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, follow the guidance below. Create a new SAML attribute and select the "Group attribute" type. Click "Continue". ![A screenshot showing how to add a group attribute in the Rippling dashboard.](https://images.workoscdn.com/images/1d904a73-9e49-4e44-b0fe-e8a2bdb9203d.png?auto=format&fit=clip&q=80) Enter `groups` for the "Group attribute name". ![A screenshot showing what to name a group attribute in the Rippling dashboard.](https://images.workoscdn.com/images/3bbab635-f5e1-48b0-b39f-11ec75669d68.png?auto=format&fit=clip&q=80) Select the attribute values to map to the group attribute. The example below shows two values, "Admins" and "Engineers", that map to the "All Admins" user group and the "Engineering Department" user group, respectively. ![A screenshot showing how to map the group attribute for Admins in the Rippling dashboard.](https://images.workoscdn.com/images/5a113ba9-0874-4574-95ab-a7e462dd856a.png?auto=format&fit=clip&q=80) > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (5) Disable the 'InResponseTo' Field In the "Settings" tab, on the left navigation select "Advanced SAML Settings" and use the "Edit" button to set "Disable 'InResponseTo' field in assertions for IdP initiated SSO" to true by checking the box to enable the setting. ![A screenshot showing where to enable the "Disable 'InResponseTo' field in assertions for IdP initiated SSO" setting in the Rippling dashboard.](https://images.workoscdn.com/images/46ec2824-7e3d-4b9f-93c1-56042e268477.png?auto=format&fit=clip&q=80) The 'InResponseTo' field is primarily used for IdP-initiated SSO and enabling this setting allows WorkOS to accept both SP and IdP initiated SSO from Rippling. Click the "Save" button to save this setting. In the next step, we will complete the integration by uploading the Metadata XML file to the WorkOS Dashboard. --- ## (6) Update Metadata File Return to the Rippling connection in the WorkOS dashboard and select "Edit Metadata Configuration". ![A screenshot showing where to select "Edit Metadata Configuration" in the WorkOS dashboard.](https://images.workoscdn.com/images/418a58ed-1370-4243-8c93-400c5c19d0b0.png?auto=format&fit=clip&q=80) Upload the XML metadata file from Rippling into the "Metadata File" field and select "Save Metadata Configuration". ![A screenshot showing where to select "Save Metadata Configuration" in the "XML File Metadata Configuration" modal in the WorkOS dashboard.](https://images.workoscdn.com/images/234fcc8b-e96a-4c66-8f7f-d2750ba337da.png?auto=format&fit=clip&q=80) Your Connection will then be linked and good to go! ### React Native Expo Learn how to integrate WorkOS SSO into a React Native Expo app. ## Introduction When it comes to combining the WorkOS SSO solution with mobile applications, our advice on the general flow tends to go like this: 1. Make an API call to generate an Authorization URL. 2. Send the end user to the generated URL within their mobile browser. 3. Deep-link the end user back into your native application upon successful authentication. With Expo, you're able to integrate the WorkOS API with the Expo AuthSession and WebBrowser libraries, which adds web browser based authentication to your app. --- ## (1) Add AuthSession Package To get started, you'll want to add the `AuthSession` package to your React Native Expo project using the following: ```bash title="Install Expo's AuthSession Package" expo install expo-auth-session expo-random ``` We'll be using the `AuthSession.makeRedirectUri()` method to generate a RedirectUri for us to use. ## (2) Add WebBrowser Package You'll also want to add the `WebBrowser` package to your React Native Expo project using the following: ```bash title="Install Expo's WebBrowser Package" expo install expo-web-browser ``` For our purposes, we'll specifically be using the `WebBrowser.openAuthSessionAsync()` method, which you can read more about [here](https://docs.expo.dev/versions/latest/sdk/webbrowser/#webbrowseropenauthsessionasyncurl-redirecturl-options). We will be using two arguments: - `url`: This will be the Authorization URL we generate using the WorkOS API - `redirect`: This will be the link back into your native Expo application once authentication is complete ## (3) Get Authorization URL The first step in the authentication process will be to Get the Authorization URL and use it as the `url` argument in the `openAuthSessionAsync()` method. In the code, it would look something like this: ```js title="Get Authorization URL Call" // Generate the RedirectUri and save it to a redirect variable // You will also need to add this redirect URI on your application's Redirects tab in the WorkOS Dashboard const redirect = AuthSession.makeRedirectUri().toString(); // Pull Connection ID from environment variables const connection_id = process.env.WORKOS_CONNECTION_ID; // Pull Client ID from evnironment variables const client_id = process.env.WORKOS_CLIENT_ID; // Format the URL for the Get Authorization URL call and pass in the Client ID, Redirect URI, and Connection ID const url = `https://api.workos.com/sso/authorize?response_type=code&client_id=${client_id}&redirect_uri=${redirect}&state=&connection=${connection_id}`; // Call openAuthSessionAsync with the url and redirect from above, and save the returned object to a variable const result = await WebBrowser.openAuthSessionAsync(url, redirect); // Pull the code returned in the result stored as a param in the url field. In this case, we are using a regular expression pattern to pull it from the url. const codeRegex = /code=([^&]+)/; const matches = result.url.match(codeRegex); const code = matches ? matches[1] : null; ``` ## (4) Exchange OAuth Code for User Profile and Token Once the above is in place, you will ultimately have a code which you can then exchange in one more API call for the user profile of the authenticating user. You'll be making a POST request to Get a Profile and Token with the token, as shown here using Axios: ```js title="Exchange OAuth Code for Profile and Token" // Use the profile returned in response.data as you need! axios({ method: 'post', url: `https://api.workos.com/sso/token?client_id=${client_id}&client_secret=${apiKey}&grant_type=authorization_code&code=${code}`, }).then((response) => {}); ``` From the end user's side, they will be sent to the native UI of their Identity Provider in their mobile browser. After they authenticate with their credentials, they will be dropped back into the native application, ready to go. --- ## Conclusion That's all there is to it! By combining WorkOS SSO with React Native Expo AuthSession, adding Single Sign-On to your Expo app is a total breeze with minimal code needed. To test the React Native Expo flow for yourself, head over to the GitHub repository of [our example React Native Expo application](https://github.com/workos/expo-authkit-example) and give it a whirl for yourself! ### PingOne SAML Learn how to configure a connection to PingOne via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a PingOne SAML Connection, you'll need two pieces of information: an [SP Metadata URL](/glossary/sp-metadata) from WorkOS, and an [IdP Metadata URL](/glossary/idp-metadata) from PingOne. --- ## What WorkOS provides WorkOS provides the SP Metadata URL. It is readily available in your Connection settings in the [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot showing where to find the SP Metadata URL in the WorkOS Dashboard.](https://images.workoscdn.com/images/30a33416-afd5-4c8a-b629-392fb4666ef3.png?auto=format&fit=clip&q=50) The SP Metadata link contains a metadata file the organization can use to set up the SAML integration. In PingOne's case, the SP Metadata URL needs to be set by the organization when configuring your application in their PingOne instance. Specifically, the SP Metadata URL will need to be set on the SAML Configuration page: ![A screenshot showing where the SP Metadata URL needs to be set in the PingOne settings.](https://images.workoscdn.com/images/01d0b62a-de8b-426e-a89e-f94a4f4fc721.png?auto=format&fit=clip&q=50) --- ## What you'll need Next, provide the PingOne IdP Metadata URL. Normally, this information will come from the organization's IT Management team when they set up your application's SAML 2.0 configuration in their PingOne admin dashboard. However, should that not be the case during your setup, here's how to obtain them: --- ## (1) Log In and Select Your Application In the PingOne Admin Console, select "Applications" (under "Connections") in the side menu. Then, select your application. ![A screenshot showing where to select a SAML app in PingOne.](https://images.workoscdn.com/images/5eecf339-0475-441c-af8b-4f7bab95d8f4.png?auto=format&fit=clip&q=50) --- ## (2) Configure Attribute Mapping In the "Attribute Mapping" section of the PingOne SAML app, add the following field-value parameter pairs: - `email` → `Email Address` - `firstName` → `Given Name` - `id` → `User ID` - `lastName` → `Family Name` ![A screenshot showing where to configure SAML attributes in PingOne.](https://images.workoscdn.com/images/1ad40d3f-dea4-4ebc-af6f-85bfc81cce30.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, follow the guidance below. Select the `+ Add` button once. To return the names of all groups a user is a member of, add "groups" in the "Attributes" column mapped to the "Group Names" PingOne attribute. Click "Save". ## ![A screenshot showing where to configure SAML groups attribute in PingOne.](https://images.workoscdn.com/images/750a99c5-ac7b-40b2-86fe-bb579c151606.png?auto=format&fit=clip&q=50) Add a new `groups` attribute mapped to the "Group Names" PingOne attribute. > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (3) Obtain Identity Provider Metadata In the "Configuration" tab, copy the "IdP Metadata URL". You'll need this in the next step. Enable the SAML app to allow users to authenticate. ![A screenshot showing where to copy the IdP Metadata URL from in PingOne.](https://images.workoscdn.com/images/e6e6f666-d67e-4a96-b1be-d9bf015e8d62.png?auto=format&fit=clip&q=50) --- ## (4) Upload IdP Metadata URL Finally, upload the IdP Metadata URL you saved earlier in your WorkOS Connection settings. Your Connection will then be linked and good to go! ![A screenshot showing where to upload the IdP Metadata URL in the WorkOS Dashboard.](https://images.workoscdn.com/images/0eccd480-bbb3-4ee3-8c9a-d0c65934fd15.png?auto=format&fit=clip&q=50) ### PingFederate SCIM Learn about syncing your user list with PingFederate SCIM. ## Introduction The PingFederate SCIM Connector can be used to enable a directory sync connection with WorkOS. Follow the steps below to set up this integration. To synchronize an organization's users and groups provisioned for your application, you'll need two pieces of information: - An [Endpoint](/glossary/endpoint) that PingFederate will make requests to - A [Bearer Token](/glossary/bearer-token) for PingFederate to authenticate it's endpoint requests After completing step 1 below, both of these are available in your Endpoint's Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). > The rest of the steps after the first will need to be carried out by the organization when configuring your application in their PingFederate instance. --- ## (1) Set up your directory in the WorkOS Dashboard Login to your WorkOS Dashboard and select "Organizations" from the left hand navigation bar. Select the organization you'll be configuring a new Directory Sync with. Click "Add Directory". ![A screenshot showing where to add a directory in the WorkOS dashboard.](https://images.workoscdn.com/images/1bb63451-a696-4f69-9707-fa46e0b17f36.png?auto=format&fit=clip&q=50) Select "PingFederate" from the dropdown, and give the connection a descriptive name. Click "Create Directory". ![A screenshot showing where to select PingFederate SCIM v2.0 as the Directory Provider in the WorkOS dashboard.](https://images.workoscdn.com/images/8809c25e-da19-4cca-8947-b92a4105e67c.png?auto=format&fit=clip&q=50) Save the Endpoint and Bearer Token, you'll need those in the next section when you configure the SCIM Connector application in PingFederate. ![A screenshot showing where to locate the Endpoint and Bearer Token in the WorkOS dashboard.](https://images.workoscdn.com/images/5de04f00-938d-4b1e-bced-fa342cdb1f6c.png?auto=format&fit=clip&q=50) > We have support for custom labeled URLs for Directory Sync endpoints. [Contact us](mailto:support@workos.com) for more info! --- ## (2) Install the SCIM Connector in PingFederate This step will take place in PingFederate. First, download and install the SCIM Connector [following the setup guide from PingFederate](https://docs.pingidentity.com/bundle/pingfederate-scim-connector/page/ulk1563995050657.html). Next, deploy the SCIM Connector files to your PingFederate directory following [the provider's documentation](https://docs.pingidentity.com/bundle/pingfederate-scim-connector/page/dcn1563995073633.html). Finally, enable provisioning in PingFederate using [the documentation from PingFederate](https://docs.pingidentity.com/r/en-us/pingfederate-112/help_spconnectionconfigtasklet_saasprovisioningstate). Once that setup has been completed, continue on to step 3. --- ## (3) Select or create your PingFederate SCIM Connector Application Log in as an admin to your PingFederate instance, and select "Applications" → "SP Connections". ![A screenshot showing where to locate the SP Connections area in PingFederate.](https://images.workoscdn.com/images/a3c7e38f-7184-460e-8405-9d9f7c7883df.png?auto=format&fit=clip&q=50) Select "Create Connection". ![A screenshot showing where to create a connection in PingFederate.](https://images.workoscdn.com/images/a5f103e4-f3b5-4808-ac9f-22ad33b3dc35.png?auto=format&fit=clip&q=50) On the Connection Template page, select "Use a Template for this Connection" and then select "SCIM Connector" from the dropdown list. If you don't see the SCIM Connector option, go back to the [Install SCIM Connector in PingFederate step](/integrations/pingfederate-scim/2-install-the-scim-connector-in-pingfederate). Click "Next". ![A screenshot showing how to select the SCIM Connector template in PingFederate.](https://images.workoscdn.com/images/f3f55f2e-6a1c-4727-9c15-5e76abe9dfe7.png?auto=format&fit=clip&q=50) On the Connection Type page, make sure Outbound Provisioning is checked with the SCIM Connector Type. Click "Next". ![A screenshot showing where to configure outbound provisioning in PingFederate.](https://images.workoscdn.com/images/68968637-291d-472b-84fa-eb095ddcf13f.png?auto=format&fit=clip&q=50) On the General Info page, give this connection a descriptive name, and click "Next". ![A screenshot showing where to give the connection a name in PingFederate.](https://images.workoscdn.com/images/08096d8a-ad68-4682-bbb8-9449b9e57780.png?auto=format&fit=clip&q=50) --- ## (4) Configure Outbound Provisioning for your PingFederate application On the Outbound Provisioning page, select the "Configure Provisioning" button. ![A screenshot showing where to click "Configure Provisioning" in PingFederate.](https://images.workoscdn.com/images/c390a6e3-bf41-4507-8b31-7d0798cfbbb1.png?auto=format&fit=clip&q=50) On the Target page, paste in the Endpoint from your WorkOS Directory Sync Connection in the SCIM URL field. Make sure SCIM Version is set as `2.0` and the Authentication Method is set as `OAuth 2 Bearer Token`. Paste in the Bearer Token from your WorkOS Directory Sync Connection in the Access Token field. Select "Next". ![A screenshot showing where to input provisioning settings in PingFederate.](https://images.workoscdn.com/images/8c8fdbb5-5ebe-4a40-90b8-8c5820ba2eac.png?auto=format&fit=clip&q=50) On the Manage Channels page, select "Create". ![A screenshot showing where to create a channel in PingFederate.](https://images.workoscdn.com/images/a38da71d-4d75-4a43-a1a8-859988ad5cac.png?auto=format&fit=clip&q=50) On the Channel Info page, add a descriptive name and click "Next". ![A screenshot showing where to configure the channel name in PingFederate.](https://images.workoscdn.com/images/18896d5c-4499-4f1b-a989-be530b0a3dda.png?auto=format&fit=clip&q=50) Select an "Active Data Store" from the dropdown menu. In this example, This example uses a PingDirectory LDAP instance, but this may be different depending on the type of data store used in each case. Please refer to the [PingFederate documentation](https://docs.pingidentity.com/bundle/pingfederate-103/page/vbe1564003005413.html) for specific settings on your type of data store. Click "Next". ![A screenshot showing where to configure the channel source in PingFederate.](https://images.workoscdn.com/images/b7c8af75-69e0-49dd-a094-1ef29c005043.png?auto=format&fit=clip&q=50) On the Source Settings page, make any modifications needed for your data store. In this example, the default values for the LDAP data store did not need to be modified, so the default settings were used. After configuring the source settings specific to your use case, click "Next" to go to the Source Location page. ![A screenshot showing where to configure the source settings in PingFederate.](https://images.workoscdn.com/images/dc7af973-ceae-449a-831e-f9dd9065a719.png?auto=format&fit=clip&q=50) On the Source Location page, input a Base DN and either a Group DB or Filter for the Users. This tells your application where to look for the users to sync from your active data store. The setup used in each case may be different depending on the type of data store being used and which users and groups are to be provisioned. Please reference [PingFederate documentation](https://docs.pingidentity.com/bundle/pingfederate-103/page/jqa1564003005539.html) for specific steps. When this is complete, click "Next". ![A screenshot showing where to configure the source location in PingFederate.](https://images.workoscdn.com/images/fa42db05-c78f-459c-ba6b-49ca4df104bd.png?auto=format&fit=clip&q=50) --- ## (5) Configure attribute mapping in PingFederate On the Attribute Mapping page, configure the mapping of attributes in the data store to the SCIM attributes. The exact configuration will depend on the specific setup in each unique situation. For this PingDirectory LDAP example, the default settings are used. When finished, Click "Next". ![A screenshot showing where to configure attribute mapping in PingFederate.](https://images.workoscdn.com/images/081f7d7c-b0fa-4595-adbf-ca6d0270bf8e.png?auto=format&fit=clip&q=50) On the Activation & Summary page, check that the settings are complete, then toggle the "Channel Status" to "Active" and select "Done". ![A screenshot showing where to check the settings and set the channel status to active in PingFederate.](https://images.workoscdn.com/images/36d37973-301d-4b36-b408-8e5dd16cc6ec.png?auto=format&fit=clip&q=50) You are directed back to the Manage Channels page, where you can select "Done". ![A screenshot showing where to finish the channel setup in PingFederate.](https://images.workoscdn.com/images/67eabbed-36f4-4e95-8312-210f2cb24b65.png?auto=format&fit=clip&q=50) You're then directed to the Outbound Provisioning page, where you can select "Next". ![A screenshot showing where to finish the outbound provisioning setup in PingFederate.](https://images.workoscdn.com/images/8a60ece6-4ac2-4db9-993e-4aa70ac912c8.png?auto=format&fit=clip&q=50) --- ## (6) Activate the SP Connection in PingFederate On the Activation & Summary page, turn on provisioning with the toggle at the top, and then select "Save". ![A screenshot showing where to activate the PingFederate app.](https://images.workoscdn.com/images/cc0c979a-1444-4e8b-bd7e-925d3a834333.png?auto=format&fit=clip&q=50) You'll now see your SCIM application listed in the SP Connections page. ![A screenshot showing where to view the completed app in PingFederate.](https://images.workoscdn.com/images/88f2b484-d308-45ac-8e5f-64239a40e2be.png?auto=format&fit=clip&q=50) The provisioning will automatically begin when the connection is activated through outbound requests from Ping Federate. It may take a few minutes for this process to start. Once it is synced, you'll see a Linked status in the Directory settings in the WorkOS Dashboard. ![A screenshot showing a linked PingFederate SCIM connection in the WorkOS dashboard.](https://images.workoscdn.com/images/70241625-42f1-4a02-ba0e-5fe9f4e843eb.png?auto=format&fit=clip&q=50) A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) ### PingFederate SAML Learn how to configure a connection to PingFederate via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a PingFederate SAML Connection, you'll need the Identity Provider metadata that is available from your PingFederate instance. --- ## What WorkOS provides WorkOS provides the [ACS URL](/glossary/acs-url) and [SP Entity ID](/glossary/sp-entity-id). It's readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/get-started). ![A screenshot showing where to find the ACS URL and SP Entity ID in the WorkOS Dashboard.](https://images.workoscdn.com/images/f0528e51-bb50-438c-b837-f355af202b60.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. In PingFederate's case, the ACS URL needs to be set by the organization when configuring your application in their PingFederate instance. Specifically, the ACS URL needs to be set as the "Endpoint URL" when defining the Protocol Settings in the SP Connection for WorkOS. ![A screenshot showing where the ACS URL needs to be set in the PingFederate settings.](https://images.workoscdn.com/images/7c626b2d-59be-489f-9890-4758e287dfbb.png?auto=format&fit=clip&q=50) The SP Entity ID is a URI used to identify the issuer of a SAML request, response, or assertion. In this case, the entity ID is used to communicate to that WorkOS will be the party performing SAML requests to the organization's PingFederate instance. Specifically, the SP Entity ID needs to be set as the "Partner's Entity ID (Connection ID)" when defining the General Info Settings in the SP Connection for WorkOS. ![A screenshot showing where to set the SP Entity ID in the PingFederate settings.](https://images.workoscdn.com/images/09d9fda5-5f4f-4920-ab96-951e0a44d158.png?auto=format&fit=clip&q=50) --- ## What you'll need In order to integrate you'll need the PingFederate IdP metadata. Normally, this information will come from the organization's IT Management team when they set up your application's SAML 2.0 configuration in their PingFederate admin dashboard. However, that should not be the case during your setup. Here's how to obtain them: --- ## (1) Log In and Select Your Application Log in to your PingFederate instance, go to the admin dashboard, select "Applications" at the top, and select the "SP Connections" menu option. ![A screenshot showing where to find the SP Connections section in the PingFederate admin dashboard.](https://images.workoscdn.com/images/6b0049f8-faf1-45d5-b352-58215cfc3f4a.png?auto=format&fit=clip&q=50) --- ## (2) Obtain Identity Provider Metadata On the SP Connection list, find your WorkOS SAML 2.0 connection. Click on the "Select Action" menu and then select "Export Metadata" to download the IdP metadata. ![A screenshot showing where to download the IdP metadata file in PingFederate.](https://images.workoscdn.com/images/6fece896-4310-40fc-9b40-be471f5ea85b.png?auto=format&fit=clip&q=50) Keep in mind where the file was saved, as we'll be later uploading it to configure the Connection. --- ## (3) Configure Attribute Mapping In the SP Connections dashboard, click into your desired connection. From there, click into the "Activation & Summary" tab, then click "Attribute Contract". You will need to add `id`, `email`, `firstName`, and `lastName` as attributes. Once configured, click "Next". ![A screenshot showing where to configure attribute mapping in PingFederate.](https://images.workoscdn.com/images/c6568ddb-76f4-4da1-80c4-d0964ae469dc.png?auto=format&fit=clip&q=50) You will now need to configure an Authentication Policy Contract. To do so, click "Map New Authentication Policy", then click "Manage Policy Contracts" and "Create New Contract". Name your contract, then go to the next step and add the same four attributes we configured above. Continue through the steps, then click "Save". ![A screenshot showing where to extend the Authentication Policy Contract in PingFederate.](https://images.workoscdn.com/images/c6fb23be-81b2-4415-9fb5-655e58e60490.png?auto=format&fit=clip&q=50) On the "Authentication Policy Mapping" page, select the Authentication Policy Contract you just made and click "Next". In the "Attribute Contract Fulfillment" tab, How you map values to the attributes listed above may differ based on how your PingFederate instance is set up. Below is an example of mapped values from both an Authentication Policy Contract and an LDAP directory. From there, save your settings on the "Summary" tab to lock in the configuration. ![A screenshot showing an example of Authentication Policy Mappings in PingFederate.](https://images.workoscdn.com/images/2141c568-0821-4aa1-899c-3fca01ecf596.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, follow the guidance below. Navigate back to the "Attribute Contact" page and define a `groups` attribute. ![A screenshot showing where to define a groups attribute in PingFederate.](https://images.workoscdn.com/images/0aa645c4-a588-4044-aaab-a57f3e546bdc.png?auto=format&fit=clip&q=50) Then, navigate to the "Attribute Contract Fulfillment" page and map the new `groups` attribute to the data in your provider that includes group memberships, such as the `isMemberOf` LDAP attribute in the example below. ![A screenshot showing a mapped groups attribute in the Attribute Contract Fulfillment area in PingFederate.](https://images.workoscdn.com/images/6115e8ae-c34e-4131-9d94-e6adfd94e9c1.png?auto=format&fit=clip&q=50) > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (4) Upload Metadata File In the connection settings of the WorkOS Dashboard, click "Edit Metadata Configuration". ![A screenshot showing where to edit the Metadata Configuration in the WorkOS Dashboard.](https://images.workoscdn.com/images/2b0764f7-e045-435d-a7ed-05283f7432ac.png?auto=format&fit=clip&q=50) In the modal, upload the PingFederate Metadata file and then select "Save Metadata Configuration". Once the file is uploaded into WorkOS, your connection will then be linked and good to go! ![A screenshot showing where to upload the Metadata file in the WorkOS Dashboard.](https://images.workoscdn.com/images/5145a2f5-63d4-43c6-97a5-c86819d0c94b.png?auto=format&fit=clip&q=50) ### Oracle SAML Learn how to configure a connection to Oracle via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [connection](/glossary/connection). Often, the information required to create a connection will differ by Identity Provider. To create an Oracle SAML connection, you'll need the Identity Provider Metadata URL that is available from the organization's Oracle SAML instance. --- ## What WorkOS provides WorkOS provides the [ACS URL](/glossary/acs-url) and the [SP Entity ID](/glossary/sp-entity-id). They are readily available in your connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot showing where to obtain the SP Entity ID and ACS URL in the WorkOS Dashboard.](https://images.workoscdn.com/images/c1b55179-b848-40c5-b56f-dc15eb325a34.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. The SP Entity ID is a URI used to identify the issuer of a SAML request, response, or assertion. --- ## What you'll need In order to integrate you'll need the IdP Metadata URL. Normally, this will come from the organization's IT management team when they set up your application's SAML configuration in their Oracle instance. But, should that not be the case during your setup, here's how to obtain it. --- ## (1) Configure SAML Application with Service Provider Details Follow the [Oracle Cloud documentation](https://docs.oracle.com/en/cloud/paas/identity-cloud/uaids/add-saml-application.html) to create a new SAML application. Copy and paste the ACS URL and SP Entity ID into the corresponding fields for Service Provider details and configuration. In the Advanced Settings of the SSO Configuration page, ensure that you select Signed SSO for Assertion and Response, and Include Signing Certificate in Signature. --- ## (2) Configure SAML Attributes Expand the Attribute Configuration section on the SSO Configuration page and add the following 4 required attributes: `firstName`, `lastName`, `email`, and `id`. Ensure the following attribute mapping is set: - A user's first name → `firstName` - A user's last name → `lastName` - A user's email address → `email` - A unique identifier representing a user → `id` ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, map the groups in your identity provider to a SAML attribute named `groups`. > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (3) Obtain Identity Provider Metadata Obtain the IdP Metadata URL following the [instructions from Oracle](https://docs.oracle.com/en/cloud/paas/identity-cloud/uaids/access-saml-metadata.html). ![A screenshot showing where the IdP Metadata URL is entered in the WorkOS Dashboard.](https://images.workoscdn.com/images/52e3e5ff-d0da-481e-8e40-a614a9c964a5.png?auto=format&fit=clip&q=50) Alternatively, you can manually configure the connection by providing the IdP URI (Entity ID), [IdP SSO URL](/glossary/idp-sso-url) and X.509 Certificate. ![A screenshot showing the manual configuration details in the WorkOS Dashboard](https://images.workoscdn.com/images/94f7c669-02a8-4d30-9e4f-86ae58b0f318.png?auto=format&fit=clip&q=50) Your connection will then be Active and good to go! ### OneLogin SCIM Learn about syncing your user list with OneLogin SCIM. ## Introduction This guide outlines how to synchronize your application's OneLogin directories using SCIM. To synchronize an organization's users and groups provisioned for your application, you'll need to provide the organization with two pieces of information: - An [Endpoint](/glossary/endpoint) that OneLogin will make requests to. - A [Bearer Token](/glossary/bearer-token) for OneLogin to authenticate its endpoint requests. Both of these are available in your Endpoint's Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). > Steps 2, 3, and 4 below will need to be carried out by the organization when configuring your application in their OneLogin instance. --- ## (1) Set up your directory sync endpoint Login to your WorkOS Dashboard and select "Organizations" from the left hand navigation bar. Select the Organization you'll be configuring a new Directory Sync for. Click "Add Directory". ![A screenshot showing where to find "Add Directory" in the WorkOS Dashboard.](https://images.workoscdn.com/images/2c4f3933-c473-458b-97be-ea22c70f84f0.png?auto=format&fit=clip&q=50) Select "OneLogin" from the dropdown and enter the organization name. Then, click "Create Directory." ![A screenshot showing "Create Directory" details in the WorkOS Dashboard.](https://images.workoscdn.com/images/0e8ef0ef-5030-46c1-a0fa-65540bc67dc5.png?auto=format&fit=clip&q=50) Your OneLogin directory sync has now been created successfully with an Endpoint and Bearer Token. ![A screenshot showing where to find the "Endpoint" and "Bearer Token" for an organization in the WorkOS Dashboard.](https://images.workoscdn.com/images/7bad6045-0611-4c6d-8d11-754f3d878bbb.png?auto=format&fit=clip&q=50) > We have support for custom labeled URLs for Directory Sync endpoints. [Contact us](mailto:support@workos.com) for more info! --- ## (2) Select or create your OneLogin application Log in to the OneLogin admin dashboard, select the "Applications" tab at the top. If the application has already been created, select it and move to step 3. Otherwise, select "Add App". ![A screenshot showing where to select "Add App" in OneLogin](https://images.workoscdn.com/images/c5f77445-e09f-4e21-8911-a240e6deee26.png?auto=format&fit=clip&q=50) Search for "SCIM" in the text field and select the Application with type "SCIM Provisioner with SAML (SCIM V2 Enterprise)". ![A screenshot showing where to search for "SCIM" and select the application "SCIM Provisioner with SAML (SCIM V2 Enterprise)"](https://images.workoscdn.com/images/a47d721e-db6f-490b-b3e0-9ac284bd3464.png?auto=format&fit=clip&q=50) Give your Application a descriptive Display Name and hit "Save". ![A screenshot showing where to add a "Display Name" to your App in OneLogin](https://images.workoscdn.com/images/4dd4042a-847e-4fde-b835-750a2f0c5644.png?auto=format&fit=clip&q=50) --- ## (3) Configure your integration Within the SCIM Application, select the "Configuration" tab on the left. Copy and paste the Endpoint from your [WorkOS Dashboard](https://dashboard.workos.com/) into the "SCIM Base URL" field. Then, copy and paste the Bearer Token from your [WorkOS Dashboard](https://dashboard.workos.com/) into the "SCIM Bearer Token" field. Hit "Enable" under "API Status" and then hit "Save". ![A screenshot showing where to select the "Configure" tab and input your "SCIM Base URL" and "SCIM Bearer Token" in your SCIM App in OneLogin](https://images.workoscdn.com/images/12411c31-4662-4da1-9e94-7348e46ddc50.png?auto=format&fit=clip&q=50) Select the "Provisioning" tab on the left. Check the "Enable provisioning" box and hit "Save". ![A screenshot showing where to select "Provisioning" tab select "Enable Provisioning" in OneLogin](https://images.workoscdn.com/images/94f76ad5-30ad-4d65-a3c7-6a18ec0e0683.png?auto=format&fit=clip&q=50&w=2048) Select the "Parameters" tab on the left. Then select "Groups". ![A screenshot showing where to select the "Parameters" then select the "Groups" in OneLogin SCIM App](https://images.workoscdn.com/images/54c10855-69e5-4484-8ccd-44f2fe89baf3.png?auto=format&fit=clip&q=50) In the modal that pops up, check the box next to "Include in User Provisioning" and hit "Save". ![A screenshot showing how to select "Include in User Provisioning" in the "Parameters" tab in OneLogin](https://images.workoscdn.com/images/09795f59-f7c0-4b04-97d5-9044fb05d987.png?auto=format&fit=clip&q=50) --- ## (4) Assign users and groups to your application In order for your users and groups to be synced, you will need to assign them to your OneLogin Application. Select "Users" from the top navigation menu. Next, find a user you'd like to provision to the SCIM app. Within that user profile, select the "Applications" tab on the left. Then, click the "+" symbol. ![A screenshot showing where to select "+" in the "Applications" tab in OneLogin](https://images.workoscdn.com/images/ee1e01fa-26f3-49e1-8515-3fedfbdee14b.png?auto=format&fit=clip&q=50) Select the appropriate app and hit "Continue". ![A screenshot showing how to select SCIM App to assign OneLogin User](https://images.workoscdn.com/images/f00d45d9-7128-43dd-8bdb-cc48e7eebf7b.png?auto=format&fit=clip&q=50) Select "Save" in the next modal to confirm the change. ![A screenshot showing how to save User Assignment in OneLogin](https://images.workoscdn.com/images/e9e5ef85-5efb-4b71-8283-e8d570f3103e.png?auto=format&fit=clip&q=50) There are many ways to provision groups in OneLogin. Below is one method that we recommend, but other methods can be used. In the top navigation, Select "Users" and then "Roles" from the dropdown. Select "New Role". ![A screenshot showing how to create a "New Role" in OneLogin](https://images.workoscdn.com/images/ecb269b5-bfe0-41f7-b73f-11a152ac0197.png?auto=format&fit=clip&q=50) Give the Role a name (this will be the name of the group), select the appropriate SCIM application, and hit "Save". ![A screenshot showing how to configure and save the "Role" in OneLogin](https://images.workoscdn.com/images/9924f509-c60a-47b5-ae30-017c361d1b55.png?auto=format&fit=clip&q=50) Click the "Users" tab for the role. Search for any users you'd like to assign to that role and hit "Add To Role". Then hit "Save". ![A screenshot showing how to add Users to "Role" in OneLogin](https://images.workoscdn.com/images/b4a4be2a-f75f-4dfe-adb9-dea585be0fce.png?auto=format&fit=clip&q=50&w=2048) Click "Save" in the next modal to confirm. ![A screenshot showing where to click "Save" assignments to "Role" in OneLogin](https://images.workoscdn.com/images/0a6ebdb2-3896-4481-8e11-ca9f1a23ecd0.png?auto=format&fit=clip&q=50&w=2048) Navigate back to your SCIM app and click on the "Rules" tab on the left. Then, hit "Add Rule". ![A screenshot showing the "Rule" tab where you can then click "Add Rule" in OneLogin](https://images.workoscdn.com/images/317311e1-4fac-487f-a30e-2aeeb6e0d30a.png?auto=format&fit=clip&q=50&w=2048) Give your Rule a name. Under "Actions", select "Set Groups in your-app-name". Then, set it to "For each role with value that matches your-role-name". Hit "Save". ![A screenshot showing how to configure a "New Mapping" in OneLogin](https://images.workoscdn.com/images/02d19425-34e2-45b3-bb64-bc3962714493.png?auto=format&fit=clip&q=50) Within your SCIM app under the "Users" tab, you may then need to click on any "Pending" notifications to confirm the update for users. ![A screenshot showing how to confirm updates for Users under the "Users" tab in OneLogin](https://images.workoscdn.com/images/3aa55536-48e8-4322-9e5e-7227c4099f9c.png?auto=format&fit=clip&q=50) Begin provisioning users and groups and witness realtime changes in your [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot showing a linked Directory in the WorkOS Dashboard](https://images.workoscdn.com/images/d33ff319-a791-4ed0-9df4-e7fba02bcce5.png?auto=format&fit=clip&q=50) A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) ## Frequently asked questions ### When a group is removed, I don't see a `dsync.group.deleted` or `dsync.group.user_removed` events - is this expected? It is a known issue with OneLogin SCIM that when a group is removed from the application, any user that is _only_ provisioned through that group will be "inactive" but otherwise no indication is received that the group has changed. The users of the group must be cleaned up before the group itself is removed from the SCIM application. ### OneLogin SAML Learn how to configure a connection to OneLogin via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create an OneLogin SAML Connection, you'll need three pieces of information: an [ACS URL](/glossary/acs-url), an [SP Entity ID](/glossary/sp-entity-id), and the [OneLogin SAML Metadata file](/glossary/idp-metadata). Start by logging into your [WorkOS Dashboard](https://dashboard.workos.com/) and selecting "Organizations" from the left hand navigation bar. Click on the organization you'd like to configure a OneLogin SAML connection for and select "Manually Configure Connection". ![A screenshot showing where to find "Manually Configure Connection" for an Organization in the WorkOS Dashboard.](https://images.workoscdn.com/images/9013d473-bfeb-4078-865b-7d40bc853748.png?auto=format&fit=clip&q=50) Select "OneLogin SAML" from the Identity Provider dropdown, enter a descriptive name for the connection, and then select the "Create Connection" button. ![A screenshot showing how to create a connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/15df7299-f83b-4f48-be6b-b2ab6bfe228c.png?auto=format&fit=clip&q=50) --- ## What WorkOS provides WorkOS provides the [ACS URL](/glossary/acs-url) and [SP Entity ID](/glossary/sp-entity-id). They are readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). The ACS URL is the location an Identity Provider redirects its authentication response to. In OneLogin's case, it needs to be set by the organization when configuring your application in their OneLogin instance. The SP Entity ID is a URI used to identify the issuer of a SAML request and the audience of a SAML response. In this case, the SP Entity ID is used to communicate that WorkOS will be the party performing SAML requests to the organization's OneLogin instance, and that WorkOS is the intended audience of the SAML responses from the OneLogin instance. ![A screenshot showing where to find the ACS URL and SP Entity ID in the WorkOS Dashboard.](https://images.workoscdn.com/images/5b7bc86b-bdcb-4ac5-a76a-a508e2d6ec0a.png?auto=format&fit=clip&q=50) --- ## What you'll need Next, provide the [OneLogin SAML Metadata file](/glossary/idp-metadata). Normally, this will come from the organization's IT Management team when they set up your application's SAML 2.0 configuration in their OneLogin admin dashboard. But, should that not be the case during your setup, the next steps will show you how to obtain it. ![A screenshot showing the "Edit Metadata Configuration" button in the WorkOS Dashboard.](https://images.workoscdn.com/images/017ac221-c3bf-40bd-8606-a04c1d41c377.png?auto=format&fit=clip&q=50) --- ## (1) Log in Log in to [OneLogin](https://app.onelogin.com/login), go to the admin dashboard, and select "Applications" in the navigation bar. ![A screenshot showing the "Applications" button in the OneLogin Dashboard.](https://images.workoscdn.com/images/6d7cdbdf-29aa-4076-aeb3-1d055a6e76ce.png?auto=format&fit=clip&q=50) --- ## (2) Select your application Select your application from the list of applications. ![A screenshot showing your application selection in the OneLogin Dashboard.](https://images.workoscdn.com/images/0d165d03-b73d-4e39-a85d-c81d27affd60.png?auto=format&fit=clip&q=50) --- ## (3) Configure application Select "Configuration" from the left-hand navigation: - Enter the SP Entity ID as the Audience (EntityID) e.g. `https://auth.workos.com/wz5SpShhRIcSEyMM` - Enter the ACS URL as the Recipient e.g. `https://auth.workos.com/sso/saml/acs/wz5SpShhRIcSEyMM` - Enter your ACS URL Validator e.g. `^https:\/\/auth\.workos\.com\/sso\/saml\/acs\/wz5SpShhRIcSEyMM$` - Enter your ACS URL e.g. `https://auth.workos.com/sso/saml/acs/wz5SpShhRIcSEyMM` - Enter your application's login URL ![A screenshot showing how to configure URLs in your OneLogin SAML Application within the OneLogin Dashboard.](https://images.workoscdn.com/images/c9c6e8c0-fece-49c0-a72f-9bb9e087cb66.png?auto=format&fit=clip&q=50) - Select "Service Provider" from the "SAML Initiator" dropdown menu - Select "Assertion" from the "SAML Signature Element" dropdown menu ![A screenshot showing SAML Configuration in the SAML Application within the OneLogin Dashboard.](https://images.workoscdn.com/images/6beae398-67d7-4a3e-91cd-52e669af9ffa.png?auto=format&fit=clip&q=50) --- ## (4) Set up attribute mapping parameters Select "Parameters" from the left-hand navigation and add the following field-value parameter pairs: - `email` → `Email` - `firstName` → `First Name` - `id` → `UUID` - `lastName` → `Last Name` Check the "Include in SAML assertion" flag for each pair. ![A screenshot showing how to configure SAML Attribute Mapping in OneLogin Dashboard.](https://images.workoscdn.com/images/de9efebf-5767-4547-8877-02560c185b5b.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, follow the guidance below. Add a new parameter, and set the "Field name" to `groups`. Under "Flags", click the checkboxes for both "Include in SAML assertion" and "Multi-value parameter". ![A screenshot showing where to add a groups parameter in the OneLogin Dashboard.](https://images.workoscdn.com/images/c29bb81b-3d04-4adf-8dd9-944f7ccbbc14.png?auto=format&fit=clip&q=50) Map the `groups` field to the attribute in OneLogin containing a user's group membership, such as "MemberOf", shown in the example below. For more information on sending group information, refer to the [OneLogin documentation](https://onelogin.service-now.com/support?id=kb_article&sys_id=6561990adb5374101c167e77f496191d). ![A screenshot showing how to map the groups parameter in the OneLogin Dashboard.](https://images.workoscdn.com/images/a70cf3c0-3d41-41d7-9c30-ee81ad497acb.png?auto=format&fit=clip&q=50) > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (5) Upload Metadata File Select "SSO" from the left-hand navigation. Select the "More Actions" dropdown and click on "SAML Metadata". This will download an XML metadata file. ![A screenshot showing how to download Metadata File in OneLogin Dashboard.](https://images.workoscdn.com/images/9a6cfe8d-62a7-4d2a-a1af-d57b3c02eb2e.png?auto=format&fit=clip&q=50) In the Connection Settings of the WorkOS Dashboard, click "Edit Metadata Configuration". ![A screenshot showing the "Edit Metadata Configuration" button in the WorkOS Dashboard. ](https://images.workoscdn.com/images/017ac221-c3bf-40bd-8606-a04c1d41c377.png?auto=format&fit=clip&q=50) In the modal that pops up, upload the OneLogin Metadata file and then select "Save Metadata Configuration". ![A screenshot showing the pop-up after clicking the "Edit Metadata Configuration" button in the WorkOS Dashboard.](https://images.workoscdn.com/images/cb8e0b46-b7e0-47e4-81cf-20601612b31e.png?auto=format&fit=clip&q=50) Once the file has uploaded, your Connection will then be linked and good to go! ### Okta SCIM Learn about syncing your user list with Okta SCIM. ## Introduction This guide outlines how to synchronize your application's Okta directories using SCIM. To synchronize an organization's users and groups provisioned for your application, you'll need to provide the organization with two pieces of information: - An [Endpoint](/glossary/endpoint) that Okta will make requests to. - A [Bearer Token](/glossary/bearer-token) for Okta to authenticate its endpoint requests. After completing step 1 below, both of these are available in your Endpoint's Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). > The rest of the steps below will need to be carried out by the organization when configuring your application in their Okta instance. --- ## (1) Set up your Directory Sync endpoint Login to your WorkOS Dashboard and select "Organizations" from the left hand navigation bar. Select the organization you'll be configuring a new Directory Sync with. Scroll to the "User provisioning" section. Then, click "Configure manually" within the "Directory Sync" section. ![A screenshot showing where to click "Configure manually" in the WorkOS dashboard.](https://images.workoscdn.com/images/a700462c-afd2-4c12-a6cb-59bfc0d34c13.png?auto=format&fit=clip&q=50) Select "Okta" from the Directory Provider dropdown and provide the Name for the Directory Sync connection. Then, click "Create Directory". ![A screenshot showing where to name and create an Okta directory in the WorkOS dashboard.](https://images.workoscdn.com/images/7e564f43-2328-4c0d-a9ab-b7cf3ec7dbeb.png?auto=format&fit=clip&q=50) You'll see WorkOS has created the Endpoint and Bearer Token which you will provide to Okta in the steps below. ![A screenshot showing the Okta directory details in the WorkOS dashboard.](https://images.workoscdn.com/images/de45d3de-7ffc-46e0-b61c-4e8b1b9fce2e.png?auto=format&fit=clip&q=50) > We have support for custom labeled URLs for Directory Sync endpoints. [Contact us](mailto:support@workos.com) for more info! --- ## (2) Select or create your Okta application Log in to [Okta](https://login.okta.com/), go to the Okta admin dashboard and select "Applications" in the navigation bar. ![A screenshot showing where to select "Applications" in Okta.](https://images.workoscdn.com/images/81f7f92f-9cc1-441d-b270-6a7c794122c1.png?auto=format&fit=clip&q=50) If your application is already created, select it from the list of applications and move to Step 3. ![A screenshot showing where to select an already created application in Okta.](https://images.workoscdn.com/images/98447a34-3e6a-404d-8419-b9f105657d1d.png?auto=format&fit=clip&q=50) If you haven't created a SCIM application in Okta, select "Browse App Catalog". ![A screenshot showing where to select "Browse App Catalog" in Okta.](https://images.workoscdn.com/images/312382ac-4381-4a9b-9407-3bd5d1655a3e.png?auto=format&fit=clip&q=50) From your Okta Application dashboard, search for "SCIM 2.0 Test App (OAuth Bearer Token)" and select the corresponding result. ![A screenshot showing where to search for "SCIM 2.0 Test App (OAuth Bearer Token)" in the App Integration Catalog in Okta.](https://images.workoscdn.com/images/12e0e6f9-1de0-49f7-95ba-960c0512387c.png?auto=format&fit=clip&q=50&w=1080) On the following page, click "Add Integration". ![A screenshot showing where to click "Add" in the SCIM 2.0 Test App (OAuth Bearer Token) overview page in Okta.](https://images.workoscdn.com/images/553af5dc-242b-4cf5-86e1-fe570f7b7acf.png?auto=format&fit=clip&q=50&w=1200) Enter a descriptive App name, then click "Next". ![A screenshot showing where to enter a name in the "Application label" field in Okta.](https://images.workoscdn.com/images/18c46d9e-e177-46b4-a462-c302b284daed.png?auto=format&fit=clip&q=50&w=1080) Many applications will work with the default configuration that is set on your new application. If you require any additional configuration for your directory such as configuring Attribute Statements, do so on the Sign-On Options page. Click "Done" to complete creating your application. --- ## (3) Configure your Okta provisioning API integration In your application's Enterprise Okta admin panel, click the "Provisioning" tab. Then, click "Configure API Integration". ![A screenshot showing where to navigate to the "Provisioning" tab to click "Configure API Integration" in Okta.](https://images.workoscdn.com/images/b78d814a-b58d-47df-9523-0bff7e7b2a42.png?auto=format&fit=clip&q=50&w=1080) Check "Enable API Integration". After that, copy and paste the Endpoint from your [WorkOS Dashboard](https://dashboard.workos.com/) in the SCIM 2.0 Base URL field. Then, copy and paste the Bearer Token from your [WorkOS Dashboard](https://dashboard.workos.com/) into the OAuth Bearer Token field. Click "Test API Credentials", and then click "Save". ![A screenshot showing where to configure the provisioning credentials in the "Provisioning" tab in Okta.](https://images.workoscdn.com/images/dbeae5e9-e0b8-402a-9330-4a9eaf82f05b.png?auto=format&fit=clip&q=50) The provisioning tab will now show a new suite of options which we'll utilize in the next Guide Section to continue provisioning your application. --- ## (4) Select options to provision to your application In the "To App" navigation section, check to enable: - Create Users - Update User Attributes - Deactivate Users Click "Save". ![A screenshot showing where to enable "Create Users", "Update User Attributes", and "Deactivate Users" in the "To App" tab in Okta.](https://images.workoscdn.com/images/a148a5b7-9685-4034-b871-7f0908764617.png?auto=format&fit=clip&q=50&w=1080) --- ## (5) Assign users and groups to your application To assign users to the SCIM Application, navigate to the "Assignments" tab, from the "Assign" dropdown, select "Assign to People". ![A screenshot showing where to select "Assign to People" in the "Assign" dropdown in the "Assignments" tab in Okta.](https://images.workoscdn.com/images/ad17bd85-3a0c-4bda-b2af-001c3451ea75.png?auto=format&fit=clip&q=50&w=1080) Select users you'd like to provision and select "Assign". ![A screenshot showing where to select "Assign" for specific users in Okta.](https://images.workoscdn.com/images/24edda3d-d8ea-4b4c-8bc4-23ff389baca9.png?auto=format&fit=clip&q=50&w=1080) When you click "Assign" a lengthy form will open where you can populate all of the user's metadata. Confirm the metadata fields, scroll down to the bottom, and press "Save and Go Back". Repeat this for all users and select "Done". ![A screenshot showing where to select "Save and Go Back" to complete user assignment in Okta.](https://images.workoscdn.com/images/f91bc47f-f734-453a-8bba-f3cf92d13c9e.png?auto=format&fit=clip&q=50&w=1080) To push groups in order to sync group membership, navigate to the "Push Groups" tab, from the "Push Groups" dropdown, select: "Find groups by name". ![A screenshot showing where to select "Find groups by name" in the "Push Groups" dropdown in the "Push Groups" tab in Okta.](https://images.workoscdn.com/images/0640cdd8-631e-4f7c-9483-c3f00f93be2f.png?auto=format&fit=clip&q=50&w=1080) Search for the group you'd like to push and select it. Make sure the box is checked for "Push Immediately" and click "Save". ![A screenshot showing where to search for groups to push in the "Push Groups" tab in Okta.](https://images.workoscdn.com/images/5ac81a96-1849-4c5b-8833-fa6a110e3da9.png?auto=format&fit=clip&q=50&w=1080) In the WorkOS dashboard, you should now see the users and groups synced over. ![A screenshot showing a successfully synced user from an Okta directory in the WorkOS dashboard.](https://images.workoscdn.com/images/3bcbe3b4-e17c-40ac-8dcd-f098b52d8e8a.png?auto=format&fit=clip&q=50) A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) --- ## Configuring user attribute mappings For any non-standard attributes used by the application, some configuration may be required in Okta. Below is a guide on configuring user attribute mappings, so they propagate via SCIM. ### (1) Viewing application attributes From the Okta administrator portal, navigate to Directory → Profile Editor, and find the application for which you'd like to edit mappings. ![Okta profile editor](https://images.workoscdn.com/images/6c58b92b-233c-4329-af2e-d024d7715081.png?auto=format&fit=clip&q=50) Clicking into the application will bring you to a Profile Editor page: ![Okta application profile editor](https://images.workoscdn.com/images/b68c705c-b08d-4d7c-a923-41e0cf7cbfed.png?auto=format&fit=clip&q=50) You'll likely see several attributes listed, which are scoped to the application. If you see an attribute listed you're looking to map to an application, there's no need to create a new attribute and you can skip to [step 3](/integrations/okta-scim/configuring-user-attribute-mappings/3-mapping-an-attribute). ### (2) Adding an attribute If a desired attribute is missing from your application, click the "Add Attribute" button to create a new attribute. ![Okta profile editor add attribute](https://images.workoscdn.com/images/34a7d5da-885c-481a-b44d-60f631c7711c.png?auto=format&fit=clip&q=50) Enter a display name and variable name of your choosing, and ensure the external name matches the key required by the third-party application. For example, if the third-party application pulls the manager value from `manager.value`, the external name should be `manager.value`. For attributes included as part of the SCIM enterprise extension, enter the external namespace as `urn:ietf:params:scim:schemas:extension:enterprise:2.0:User`. ![Okta add attribute dialog](https://images.workoscdn.com/images/d4a7cff9-0226-4462-ab11-c086b4b4533e.png?auto=format&fit=clip&q=50) Once you've entered the required information, click "Save". ### (3) Mapping an attribute To map Okta user profile attributes to your application users, click on the "Mappings" button. ![Okta profile editor mappings](https://images.workoscdn.com/images/542ba367-6147-4ea5-bb18-4d55e13232ea.png?auto=format&fit=clip&q=50) Mappings can be bidirectional, either from the application to the Okta user or from the Okta user to the application. This guide will focus on mapping from the Okta user to the application. Click the "Okta User to (name of application)" tab. ![Okta to application mapping tab](https://images.workoscdn.com/images/de8218c4-b96b-4761-85e9-6843b200e445.png?auto=format&fit=clip&q=50) Find the name of the attribute you'd like to map in the right column. In the corresponding row's left column, enter the name of the Okta user profile attribute you'd like to map over. For example, if you're looking to map manager email in the application, select `managerId` in the left column. ![Okta mapping select attribute](https://images.workoscdn.com/images/97fafcf8-0845-4e09-8699-7ec5560255ce.png?auto=format&fit=clip&q=50) Ensure the apply mappings setting is set to "Apply mapping on user create and update". ![Okta apply mappings selection](https://images.workoscdn.com/images/d1a3c86a-36e9-49ba-bf5a-7538c0992aa5.png?auto=format&fit=clip&q=50) Once your mappings are configured, click "Save Mappings" and "Apply updates now". These new attribute mappings will now propagate to the application. ## Frequently asked questions ### A user appears in a group they are no longer a member of in Okta, why? How can I fix this situation? There is a known issue in Okta where push group membership removals are not sent via SCIM when the affected user is deactivated or unassigned from the app. This commonly happens when a single group is used for both assignment and push, since removing a user triggers deactivation causing the membership removal event to never be sent. The IT admin can fix it by clicking "Push now" on the affected group in the Push Groups tab. ### How often do the Okta SCIM 2.0 directories perform a sync? The Okta SCIM 2.0 directory syncs events in real time. ### Why is a user suspended in Okta still active in WorkOS? Suspending a User in Okta will only affect their login and will not alter their status in any connected applications. Deactivating or Deleting a User in Okta will result in a `inactive` status in connected applications (i.e., WorkOS). For more details, please refer to Okta's official documentation [User Suspension](https://help.okta.com/en-us/content/topics/users-groups-profiles/usgp-suspend.htm) [User Deactivation and Deletion](https://help.okta.com/en-us/content/topics/users-groups-profiles/usgp-deactivate-user-account.htm). ### What is the `idp_id` for directory groups from Okta? Okta only provides a group display name as a group identifier, so this display name is persisted as the `idp_id` and `name` for [directory groups](/reference/directory-sync/directory-group) in WorkOS. ### Okta SAML Learn how to configure a connection to Okta via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [connection](/glossary/connection). Often, the information required to create a connection will differ by Identity Provider. To create an Okta connection, you'll need three pieces of information: an [ACS URL](/glossary/acs-url), an [SP Entity ID](/glossary/sp-entity-id), and an [IdP Metadata URL](/glossary/idp-metadata). Start by logging in to your WorkOS dashboard and browse to the "Organizations" tab on the left hand navigation bar. Select the organization you'd like to configure an Okta connection for, and select "Manually Configure Connection" under "Identity Provider". ![A screenshot showing where to find "Manually Configure Connection" in the WorkOS Dashboard.](https://images.workoscdn.com/images/9270090d-4f59-4b7b-95e9-1132a6bee872.png?auto=format&fit=clip&q=50) Select "Okta SAML" from the Identity Provider dropdown, enter a descriptive name for the connection, and then select the "Create Connection" button. ![A screenshot showing "Create Connection" details in the WorkOS Dashboard.](https://images.workoscdn.com/images/287303da-4bbd-433b-bdd2-06f5002dd5ca.png?auto=format&fit=clip&q=50) --- ## What WorkOS provides WorkOS provides the ACS URL and the SP Entity ID. It's readily available in your connection settings in the [WorkOS Dashboard](https://dashboard.workos.com/get-started). ![A screenshot showing where to find the ACS URL and SP Entity ID in the WorkOS Dashboard.](https://images.workoscdn.com/images/0d9140ab-ca2e-4d91-b494-e96ce5c1df6d.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. In Okta's case, it needs to be set by the organization when configuring your application in their Okta instance. The SP Entity ID is a URI used to identify the issuer of a SAML request, response, or assertion. In this case, the entity ID is used to communicate that WorkOS will be the party performing SAML requests to the organization's Okta instance. Specifically, the ACS URL will need to be set as the "Single Sign-On URL" and the SP Entity ID will need to be set as the "Audience URI (SP Entity ID)" in the "Configure SAML" step of the Okta "Edit SAML Integration" wizard: ![A screenshot showing where to place the WorkOS Single Sign-On URL and SP Entity ID in the Okta Dashboard.](https://images.workoscdn.com/images/52be9941-9e43-4f70-a65e-d4cd8883579c.png?auto=format&fit=clip&q=50) ## What you'll need Next, provide the [IdP Metadata URL](/glossary/idp-metadata). Normally, this information will come from the organization's IT Management team when they set up your application's SAML 2.0 configuration in their Okta admin dashboard. But, should that not be the case during your setup, the next steps will show you how to obtain it. --- ## (1) Log in Log in to [Okta](https://login.okta.com), go to the admin dashboard, and select "Applications" in the navigation bar. ![A screenshot showing how to navigate to existing applications in the Okta Dashboard.](https://images.workoscdn.com/images/b4f8bd68-3265-4ef6-8916-1f9e7eb241a1.png?auto=format&fit=clip&q=50) --- ## (2) Select or create your application If your application is already created, select it from the list of applications and move to Step 5. ![A screenshot showing existing applications in the Okta Dashboard.](https://images.workoscdn.com/images/f763ab3c-0ffc-49b7-8212-f988d0738e94.png?auto=format&fit=clip&q=50) If you haven't created a SAML application in Okta, select "Create App Integration". ![A screenshot showing how to select "Create App Integration" in the Okta Dashboard.](https://images.workoscdn.com/images/cf63d4f1-3929-4426-a0df-959bbd06ce13.png?auto=format&fit=clip&q=50) --- ## (3) Initial SAML Application Setup Select "Create New App", then select "SAML 2.0" as a Sign on method, then click "Next". ![A screenshot showing the sign-in method selection in the Okta Dashboard.](https://images.workoscdn.com/images/036519d9-1d5a-462f-8d36-e87b618a3e94.png?auto=format&fit=clip&q=50) Enter a descriptive App name, then click "Next". ![A screenshot showing App name creation in the Okta Dashboard.](https://images.workoscdn.com/images/facbcbea-3ce0-421e-9725-e05e49bc056a.png?auto=format&fit=clip&q=50) --- ## (4) Configure SAML Application Input the ACS URL from your WorkOS Dashboard as the "Single Sign-On URL" and input the SP Entity ID from your WorkOS Dashboard as the "Audience URI (SP Entity ID)". ![A screenshot showing where to place the WorkOS Single Sign-On URL and SP Entity ID in the Okta Dashboard.](https://images.workoscdn.com/images/52be9941-9e43-4f70-a65e-d4cd8883579c.png?auto=format&fit=clip&q=50) --- ## (5) Upload Metadata URL Click on the "Sign On" tab of the SAML app you just created. Under "Settings", find the "Metadata details" section and copy the Metadata URL. ![A screenshot showing where to find the Metadata URL on the "Sign On" tab in the Okta Dashboard.](https://images.workoscdn.com/images/65d17a86-7ba3-4d48-b74f-44dd95cb9796.png?auto=format&fit=clip&q=50) Back in the WorkOS Dashboard, click "Edit configuration" in the "Identity provider configuration" section of the connection. Choose "Dynamic configuration", paste the copied Metadata URL and click "Save metadata configuration". The connection will then be linked and good to go! ![A screenshot showing where to add the Okta Metadata URL in the WorkOS Dashboard.](https://images.workoscdn.com/images/3f8eca66-248b-46f2-8f59-3e4939d58e74.png?auto=format&fit=clip&q=50) --- ## (6) Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, follow the guidance below. Click on the "Sign On" tab of your SAML app. Open the "Show legacy configuration" dropdown to expand the legacy configuration mapping and then click "Edit". Add a Group attribute statement with a Name of `groups`, and define a filter to map the appropriate Okta groups. To map all groups, use the regex `.*` as shown below. ![A screenshot showing the "Group attribute statements" configuration in the Okta Dashboard.](https://images.workoscdn.com/images/b1b90419-9b45-4980-94b1-31117fa1ff7b.png?auto=format&fit=clip&q=50) > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (7) Submit Application Feedback Select "I'm an Okta customer adding an internal app" from the options menu. Complete the form with any comments and select "Finish". ![A screenshot showing where to submit application feedback in the Okta Dashboard.](https://images.workoscdn.com/images/734d5229-1913-4cfb-b366-295104da4123.png?auto=format&fit=clip&q=50) --- ## (8) Add Users to SAML Application To give users permission to authenticate via this SAML app, you will need to assign individual users and/or groups of users to the Okta app. Click on the "Assignments" tab, and select either "Assign to People" or "Assign to Groups". ![A screenshot showing the Okta Application "Assignments" tab in the Okta Dashboard.](https://images.workoscdn.com/images/a8380fe9-9e90-48ff-b665-8313311c28d1.png?auto=format&fit=clip&q=50) Find the individual user(s) and/or group(s) that you would like to assign to the app, and click "Assign" next to them. Click "Done" when you are finished. ![A screenshot showing the selecting of groups to add to the Application in the Okta Dashboard.](https://images.workoscdn.com/images/c4fddfdc-35b2-4a4f-9d84-1a7e94968d24.png?auto=format&fit=clip&q=50) ### Okta OIDC Learn how to configure a connection to Okta via OIDC. ## Introduction Each SSO identity provider requires specific information to create and configure a new [SSO connection](/glossary/connection). Often, the information required to create an SSO connection will differ by identity provider. To create an Okta OIDC SSO connection, you'll need four pieces of information: a [redirect URI](/glossary/redirect-uri), [client ID](/glossary/client-id), [client secret](/glossary/client-secret), and [discovery endpoint](/glossary/discovery-endpoint). Start by logging in to your WorkOS dashboard and navigate to the **Organizations** page from the left-hand navigation bar. Select the organization you'd like to configure an Okta OIDC SSO connection for, and select **Configure manually** under **Single Sign-On**. ![WorkOS Dashboard Organizations tab with "Configure manually" button highlighted](https://images.workoscdn.com/images/d577cfbe-028b-48cf-8cc0-4cd5d3adf853.png?auto=format&fit=clip&q=50) Select **Okta OIDC** from the identity provider dropdown, enter a descriptive name for the connection, click **Create Connection**. ![Create Connection form with Okta OIDC selected as Identity Provider](https://images.workoscdn.com/images/6e60c859-936e-4894-ac88-0524565ef8c8.png?auto=format&fit=clip&q=50) --- ## What WorkOS provides WorkOS provides the Redirect URI, which can be found in the **Service Provider Details** section on the SSO connection page in the [WorkOS Dashboard](https://dashboard.workos.com/). - [Redirect URI](/glossary/redirect-uri): The endpoint where identity providers send authentication responses after successful login ![The Redirect URI of a OIDC connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/99a7c7d5-50a9-4bff-a3f3-22dc1cfeca58.png?auto=format&fit=clip&q=50) The Redirect URI is the location an identity provider redirects its authentication response to. In Okta's case, it needs to be set as the **Sign-in redirect URI** when configuring your OIDC application in their Okta instance. Specifically, the Redirect URI will need to be added to the **Sign-in redirect URIs** section in the **Create OpenID Connect Integration** wizard, which is outlined in [step 2](/integrations/okta-oidc/2-configure-the-integration). --- ## What you'll need You will need to obtain three pieces of information from the organization: - [Client ID](/glossary/client-id): Application identifier from the OIDC provider - [Client secret](/glossary/client-secret): Authentication secret for the application - [Discovery endpoint](/glossary/discovery-endpoint): Configuration URL containing OIDC metadata Normally, this information will come from the organization's IT Management team when they set up your application's OIDC configuration in their Okta admin dashboard. But, should that not be the case during your setup, the next steps will show you how to obtain it. --- ## (1) Create OIDC integration Log in to the Okta admin console, and select **Applications** in the left-hand sidebar. ![Okta admin console navigation menu with Applications tab highlighted](https://images.workoscdn.com/images/d3e05208-2c35-4cba-a592-62aadf2752a1.png?auto=format&fit=clip&q=50) Click **Create App Integration**. ![Okta Applications page with "Create App Integration" button](https://images.workoscdn.com/images/8059f5a3-0c46-45fb-a4db-30c13c0fc0de.png?auto=format&fit=clip&q=50) In the **Create a new app integration** dialog, select **OIDC - OpenID Connect** and **Web Application**. ![Create app integration dialog with OIDC - OpenID Connect and Web Application selected](https://images.workoscdn.com/images/d6b2f9e8-42f4-4279-9adf-6954644a9758.png?auto=format&fit=clip&q=50) Click **Next**. --- ## (2) Configure the integration Enter a descriptive App name, then configure the Sign-in redirect URI. ![OIDC app configuration form with app name field and sign-in redirect URI section](https://images.workoscdn.com/images/7ed6bf17-6839-48f2-b796-883b181c1e79.png?auto=format&fit=clip&q=50) Locate the **Sign-in redirect URIs** section and click **Add URI**. Copy the [Redirect URI](/integrations/okta-oidc/what-workos-provides) from the SSO connection page in your WorkOS Dashboard and paste it into this field. ![Sign-in redirect URIs configuration with WorkOS redirect URI entered](https://images.workoscdn.com/images/fa2cc4f3-a11a-4612-8b58-4739385babac.png?auto=format&fit=clip&q=50) Scroll down to the **Assignments** section. Select **Limit access to selected groups** and assign the appropriate groups to the application. This can be edited later. ![Assignments section with "Limit access to selected groups" option selected](https://images.workoscdn.com/images/743f90a9-aa9d-48a1-94e4-05b1743f9e81.png?auto=format&fit=clip&q=50) Click **Save**. --- ## (3) Obtain configuration details On the **General** tab, locate the **Client ID** and **Client secret**. Under **Proof Key for Code Exchange (PKCE)**, ensure **Require PKCE as additional verification** is checked. ![Okta app General tab showing Client Credentials with PKCE enabled](https://images.workoscdn.com/images/d2d977fc-08cd-4f8d-8983-bd3e96b9cda9.png?auto=format&fit=clip&q=50) Back in the WorkOS Dashboard, enter the client ID, and client secret into the respective fields in the **Identity Provider Configuration** section of the SSO connection. In the top right-hand navigation, click your user email and locate the **Okta tenant domain** which usually ends with `.okta.com`. Copy this value and define the discovery endpoint in the format: `https://{tenant-domain}/.well-known/openid-configuration`. Enter this URL in the **Discovery Endpoint** field in the WorkOS dashboard. ![WorkOS Dashboard Identity Provider Configuration with client ID, client secret, and discovery endpoint fields](https://images.workoscdn.com/images/24179b09-b86d-46f8-9375-95b9ff9abd36.png?auto=format&fit=clip&q=50) Click **Save Configuration**. --- ## (4) Role assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. Users will automatically be granted the assigned roles within your application when they authenticate. To enable this functionality: ### Set groups claim in Okta Navigate to the **Sign On** tab of your OIDC application, locate the **Token Claims** section, click **Show legacy configuration** and click **Edit**. ![Okta app Sign On tab with Claims section and Edit button](https://images.workoscdn.com/images/d699c5cb-c4f1-4299-acbe-7ed4cc1dfee9.png?auto=format&fit=clip&q=50) ![Okta app Token Claims section and Show legacy configuration section](https://images.workoscdn.com/images/b3b44868-5761-4b74-bd5a-e653b017eba7.png?auto=format&fit=clip&q=50) Set the **Groups claim type** to **Filter**. Define the **Groups claim filter** as `groups` and set a filter to match the appropriate Okta groups. To match all groups, use the regex `.*` as shown below. ![Okta app Legacy group claims configuration](https://images.workoscdn.com/images/3dc662e0-e62d-478b-9de0-4f5666ccea56.png?auto=format&fit=clip&q=50) ### Configure role assignment in WorkOS In Okta, navigate to the **Assignments** tab in the application. Locate the **Filters** sidebar, click on **Groups** to filter and display all the assigned groups available to map. ![Okta dashboard showing assigned groups](https://images.workoscdn.com/images/17d32c5b-fc4b-458b-98f6-99c774af1522.png?auto=format&fit=clip&q=50) From the SSO connection page in the [WorkOS Dashboard](https://dashboard.workos.com/), scroll to the **Groups and role assignments** section. ![WorkOS dashboard highlighting create group button](https://images.workoscdn.com/images/c29ef1a7-d873-49f6-ad43-8c945245a033.png?auto=format&fit=clip&q=50) For each group you want to assign a role, click the **Create group** button and enter the following: 1. Copy the group name from Okta into the **IdP Group ID** field. 2. Optionally, enter a group name into the **Name** field. 3. Assign the appropriate role to the group. ![WorkOS dashboard with open create group dialog and idp\_id, name, and role assignment inputs](https://images.workoscdn.com/images/d542c8c3-e032-41a6-ae72-c8dc586ec88d.png?auto=format&fit=clip&q=50) > Group members without an explicit role will receive the default role. --- ## PKCE (Proof Key for Code Exchange) WorkOS supports [PKCE](https://datatracker.ietf.org/doc/html/rfc7636) for OIDC connections, including Okta. PKCE adds an additional layer of security to the authorization code flow by preventing authorization code interception attacks. In the **Advanced settings** section of your Okta OIDC connection configuration in the WorkOS Dashboard, you can view and manage the PKCE setting. > Only disable PKCE if you encounter issues with your identity provider. Okta supports PKCE, and keeping it enabled is strongly recommended for security. --- ## Next steps Your Okta OIDC connection is now configured and ready to use. Users assigned to the application in Okta will be able to authenticate through WorkOS using their Okta credentials. To start using this connection in your application, refer to the [SSO guide](/sso) for implementation details. ### OpenID Connect Learn how to configure a new generic OIDC connection ## Introduction To set up an OpenID Connect (OIDC) connection on behalf of an organization, you'll need the client credentials and the discovery endpoint of their OIDC provider from the organization's IT team. --- ## What WorkOS provides When setting up an OIDC connection, WorkOS provides one key piece of information in the **Service Provider Details** section for an SSO connection within the [WorkOS Dashboard](https://dashboard.workos.com/): - [Redirect URI](/glossary/redirect-uri): The endpoint where identity providers send authentication responses after successful login ![The Redirect URI of a OIDC connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/99a7c7d5-50a9-4bff-a3f3-22dc1cfeca58.png?auto=format&fit=clip&q=50) The **Redirect URI** serves as the destination for authentication responses and must be configured in the organization's identity provider admin dashboard. --- ## What you will need You will need to obtain three pieces of information from the organization: - [Client ID](/glossary/client-id): Application identifier from the OIDC provider - [Client Secret](/glossary/client-secret): Authentication secret for the application - [Discovery Endpoint](/glossary/discovery-endpoint): Configuration URL containing OIDC metadata Typically, the organization's IT team will provide these values when they configure your application in their identity provider admin dashboard. However, if you need to guide them through the process, the following sections will help. > A Client Secret is required for the **Client secret basic** and **Client secret POST** authentication methods. If you use **Private key JWT**, WorkOS generates a signing key pair instead and no Client Secret is needed. See [Token endpoint authentication method](#token-endpoint-authentication-method). --- ## (1) Create an application with the identity provider For SSO to properly function, the organization needs to create and configure an OpenID Connect application in their identity provider that supports the authorization code grant type. Copy the **Redirect URI** from the WorkOS Dashboard connection settings. Instruct IT contacts to paste this value as the login redirect URI in their OIDC application configuration. This ensures authentication responses are sent to the correct WorkOS endpoint. --- ## (2) Configure ID token claims The organization's OIDC provider needs to include specific claims in the user ID token. Instruct them to add the following claims to their OIDC provider settings: - `sub` (required): Maps to the `idp_id` attribute in WorkOS user profiles - `email` (required): Maps to the `email` attribute in WorkOS user profiles - `given_name`: Maps to the `first_name` attribute in WorkOS user profiles - `family_name`: Maps to the `last_name` attribute in WorkOS user profiles - `name`: Maps to the `name` attribute in WorkOS user profiles The `sub` and `email` claims are always required. The `given_name`, `family_name`, and `name` claims follow your environment's [IdP attributes settings](/sso/attributes). By default, `given_name` and `family_name` are enabled and required, while `name` is disabled and optional. For many providers, these claims are included by default, but some providers require manual configuration. ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To enable this functionality, instruct the organization to add the `groups` claim to the user ID token in their OIDC provider settings. This claim should map to a list of the user's group memberships. > Finish role assignment set-up by navigating to the SSO connection page in the **Organizations** section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (3) Obtain client credentials and discovery endpoint After the organization creates an OpenID Connect application, their identity provider will provision client credentials and a discovery endpoint. The discovery endpoint will always end with `/.well-known/openid-configuration` as described in the [OpenID Provider Configuration Request documentation](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest). You can confirm that the discovery endpoint is correct by entering it in a browser window. If there is a JSON object with metadata about the connection returned, the endpoint is correct. In the WorkOS Dashboard, navigate to your connection settings. Paste the **Client ID**, **Client Secret**, and **Discovery Endpoint** values from the organization's IT team into their respective input fields. Click **Update connection**. ![Input the Client ID, Client Secret, and Discovery Endpoint in the WorkOS Dashboard](https://images.workoscdn.com/images/ed603b39-a06e-4c2f-b96f-7cadaa793be4.png?auto=format&fit=clip&q=50) --- ## Token endpoint authentication method When WorkOS exchanges the authorization code for tokens, it authenticates to the organization's OIDC provider at the token endpoint. WorkOS supports three authentication methods, which you can select in the **Advanced settings** section of your OIDC connection configuration using the **Authentication method** field. | Method | How WorkOS authenticates | Credentials required | | ----------------------- | ------------------------------------------------------------------------------------------------------ | ----------------------------- | | **Client secret basic** | Sends the Client ID and Client Secret in the `Authorization` header (HTTP Basic). This is the default. | Client ID, Client Secret | | **Client secret POST** | Sends the Client ID and Client Secret in the request body. | Client ID, Client Secret | | **Private key JWT** | Signs a client assertion JWT with a WorkOS-managed private key. No Client Secret is stored. | Client ID, public signing key | Choose the method that matches how the organization registered the application with their identity provider. If you are unsure, **Client secret basic** is supported by most providers. ### Private key JWT With **Private key JWT**, WorkOS authenticates by signing a [client assertion](https://datatracker.ietf.org/doc/html/rfc7523) JWT with a private key, rather than presenting a shared Client Secret. WorkOS holds the private key; the organization's identity provider verifies the assertion using the corresponding public key. When you select **Private key JWT**, WorkOS generates an RS256 signing key pair for the connection and the Client Secret field is hidden. The public key becomes available for download in the **Service Provider Details** section, in two formats: - **PEM certificate** (`certificate.pem`): an X.509 certificate - **JWK**: a JSON Web Key Download the format the organization's identity provider expects and instruct your customer's IT team to register it on the OIDC application. Once the public key is registered, the connection can authenticate without a Client Secret. ![Download the public signing key for a Private key JWT OIDC connection.](https://images.workoscdn.com/images/257f13db-cfa8-4013-a578-35981f25b7e7.png?auto=format&fit=clip&q=50) > If you later switch the connection back to **Client secret basic** or **Client secret POST**, you will need to enter a new Client Secret. --- ## PKCE (Proof Key for Code Exchange) WorkOS supports [PKCE](https://datatracker.ietf.org/doc/html/rfc7636) for OIDC connections. PKCE adds an additional layer of security to the authorization code flow by preventing authorization code interception attacks. In the **Advanced settings** section of your OIDC connection configuration, you can view and manage the PKCE setting. > Only disable PKCE if you encounter issues with your identity provider. Most modern identity providers support PKCE, and keeping it enabled is strongly recommended for security. ### NextAuth.js Create a Next.js application with WorkOS SSO and NextAuth.js. ## Introduction In this guide, you'll learn how to use WorkOS to add Single Sign-On (SSO) to a Next.js app that uses [NextAuth.js](https://next-auth.js.org/) for handling authentication. You can check out the [complete source code](https://github.com/workos/workos-next-auth) of this guide on GitHub. ## Before getting started To get the most out of this guide, you'll need: - A [WorkOS account](https://dashboard.workos.com/) - An IdP (e.g. Okta) account ## (1) Install sample application In your a terminal, browse to the directory of your choice and run the following command to clone the starter project: ```bash title="Clone the Sample App" git clone -b start-branch https://github.com/workos-inc/workos-next-auth ``` And install the dependencies ```bash title="Install the Dependencies" npm install ``` This is a basic Next.js app built using TypeScript and styled using TailwindCSS. ## (2) Configuring the environment variables In the project's root folder, rename the `.env.example` file to `.env`. You can find down below the values for the WorkOS client ID and API key. ```plain title=".env" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' ``` As a best practice, your WorkOS API key should be kept secret and set as an environment variable on process start. The SDK is able to read the key automatically if you store it in an environment variable named `WORKOS_API_KEY`; otherwise, you will need to set it manually. The [Client ID](/glossary/client-id) should also be set dynamically based on the release environment. ## (3) SSO Setup with WorkOS The first step is to create an organization, which can be done using the dashboard or [via the API](/reference/organization/create). By default, WorkOS creates a demo organization called "foo-corp.com" which you can use for testing purposes. Take note of the "Organization ID" which can be found in the organization's detailed view. You're going to need it to make SSO work. ![A screenshot highlighting the "Organization ID" in the WorkOS dashboard.](https://images.workoscdn.com/images/af4ef014-f6c4-44b2-b7cc-ccf2db24bde5.png?auto=format&fit=clip&q=50) ## (4) Configure redirect URIs In the [Applications](https://dashboard.workos.com/environment/applications) section of the WorkOS Dashboard, open your application and go to the **Redirects** tab. Add `http://localhost:3000/api/auth/callback/workos` to the redirect URIs to test the SSO login flow locally. You'll also need to add the domain of your application when deploying to production. ![A screenshot highlighting the redirect URIs in the "Configuration" tab in the WorkOS dashboard.](https://images.workoscdn.com/images/7005a351-b083-4a08-a096-cb227c21caa5.png?auto=format&fit=clip&q=50) ## (5) Create an API endpoint The next step is to create a `pages/api/auth/[...nextauth].ts` file which will contain all of your NextAuth.js configurations: ```js title="pages/api/auth/[...nextAuth].ts" import NextAuth from 'next-auth'; import WorkOSProvider from 'next-auth/providers/workos'; export default NextAuth({ providers: [ WorkOSProvider({ clientId: process.env.WORKOS_CLIENT_ID, clientSecret: process.env.WORKOS_API_KEY, client: { token_endpoint_auth_method: 'client_secret_post', }, }), ], pages: { signIn: '/login', }, debug: true, secret: process.env.SECRET, }); ``` You're first configuring WorkOS by passing the necessary options to the `WorkOSProvider()` function. You're then defining a custom login page using the pages option which will be located at `/login`. You then need to wrap the global `App` component with `SessionProvider` from `NextAuth.js`. Add the following code to the `pages/_app.tsx` file: ```js title="pages/_app.tsx" import '../styles/index.css'; import type { AppProps } from 'next/app'; import { SessionProvider } from 'next-auth/react'; export default function App({ Component, pageProps: { session, ...pageProps }, }: AppProps) { return ( ); } ``` ## (6) Creating a custom login page In this step, you'll create a custom login page. To do that, create a new file located at `pages/login.tsx` and add the following code to it: ```js title="pages/login.tsx" import React from 'react'; import { useForm } from 'react-hook-form'; import Head from 'next/head'; import { signIn, signOut, useSession } from 'next-auth/react'; const Login = () => { const { register, handleSubmit, formState: { errors }, } = useForm(); const { data: session } = useSession(); const onSubmit = async ({ team }) => { // TODO: send a request to the get-organization endpoint and return the // organizationId from your database const organization = 'ORGANIZATION_ID'; signIn('workos', undefined, { organization, }); }; return ( <> Next Enterprise | Login {session && (

Signed in as {session.user.email}


)} {!session && (

Continue using enterprise SSO

)} ); }; export default Login; ``` Next, start the development server by running the following command: ```bash title="Start Server" npm run dev ``` The application will be running at `http://localhost:3000/login` and you'll be able to see the following page: ![A screenshot showing the landing page of the example application.](https://images.workoscdn.com/images/af8ddee4-e7f1-49a1-9e7c-05e190b31d6e.png?auto=format&fit=clip&q=50) ## (7) Testing the Single Sign-On flow You should persist The Organization ID in your application's database and associate it with your enterprise customer. Then when a user tries to log in, you first check if they're an enterprise customer and then use the `signIn()` function from NextAuth.js to start the login flow. To test the login flow, hardcode the Organization ID in the form submission handler. ```js title="pages/login.tsx" // code above unchanged const onSubmit = async ({ team }) => { // TODO: create an endpoint that returns the // organizationId from your database /* +diff-start */ const organization = 'ORGANIZATION_ID'; /* +diff-end */ signIn('workos', undefined, { organization, }); }; // code below unchanged ``` If you type anything in the login form and click submit, you'll be redirected to Okta. You'll then need to use your IdP login credentials. After you complete the login process you'll see the logged-in user's email and a "Sign out" button ![A screenshot showing the example application with a successfully logged in user.](https://images.workoscdn.com/images/7fd5daef-1cd9-401d-9884-3130b7b3a095.png?auto=format&fit=clip&q=50) If you're interested in setting up a different Identity Provider, check out the [full list of tutorials](/sso) for setting up an SSO connection. ### NetIQ Learn how to configure a connection to NetIQ via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a NetIQ SAML Connection, you'll need the Identity Provider metadata that is available from the organization's NetIQ instance. Start by logging in to your WorkOS dashboard and browse to the "Organizations" tab on the left hand navigation bar. Select the organization you'd like to configure an NetIQ SAML Connection for, and select "Manually Configure Connection" under "Identity Provider". ![A screenshot showing where to find "Manually Configure Connection" in the WorkOS Dashboard.](https://images.workoscdn.com/images/c6f1423d-020f-4560-aed0-ca4895b5fbc1.png?auto=format&fit=clip&q=50) Select "NetIQ SAML" from the Identity Provider dropdown, enter a descriptive name for the connection, and then select the "Create Connection" button. ![A screenshot showing "Create Connection" details in the WorkOS Dashboard.](https://images.workoscdn.com/images/5c854a7c-0180-45de-aeda-8b52d8275b75.png?auto=format&fit=clip&q=50) --- ## What WorkOS provides WorkOS provides the [ACS URL](/glossary/acs-url), the [SP Metadata](/glossary/sp-metadata) link and the [SP Entity ID](/glossary/sp-entity-id). They are readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot showing where to find the ACS URL and SP Entity ID in the WorkOS Dashboard.](https://images.workoscdn.com/images/e102db99-be9d-4aa5-b250-a690ce57d16e.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. The SP Metadata link contains a metadata file that the organization can use to set up the SAML integration. The SP Entity ID is a URI used to identify the issuer of a SAML request, response, or assertion. --- ## What you'll need In order to integrate you'll need the [IdP Metadata URL](/glossary/idp-metadata). Normally, this will come from the organization's IT Management team when they set up your application's SAML 2.0 configuration in their NetIQ instance. But, should that not be the case during your setup, here's how to obtain it. --- ## (1) Enter Service Provider Details Copy and paste the "ACS URL" and "SP Entity ID" into the corresponding fields for Service Provider details and configuration. For some setups, you can use the metadata found at the SP Metadata link to configure the SAML connection. --- ## (2) Obtain Identity Provider Metadata Copy the IdP Metadata URL from your NetIQ SAML settings and upload it to your WorkOS Connection settings. Your Connection will then be linked and good to go! ![A screenshot showing where to place the NetIQ IdP Metadata URL in the WorkOS Dashboard.](https://images.workoscdn.com/images/e26ae490-1f53-4d88-8c0e-50bb8ed2be64.png?auto=format&fit=clip&q=50) Alternatively, you can manually configure the connection by providing the IdP URI (Entity ID), [IdP SSO URL](/glossary/idp-sso-url) and X.509 Certificate. ![A screenshot showing where to switch to Manual Configuration in the connections detail page.](https://images.workoscdn.com/images/20ea5490-7344-43f4-95bb-129e3aa44595.png?auto=format&fit=clip&q=50) ![A screenshot showing to click "Save Configuration" upon entering the Metadata data.](https://images.workoscdn.com/images/1a39b96e-3564-43b2-82e7-082f74ff4713.png?auto=format&fit=clip&q=50) --- ## (3) Configure Attribute Mapping At minimum, the Attribute Statement in the SAML Response should include `id`, `email`, `firstName`, and `lastName` attributes. ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, map the groups in your identity provider to a SAML attribute named `groups` to return this information in the attribute statement. Once your SAML app is configured to return groups, navigate to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. ### miniOrange Learn how to configure a connection to miniOrange via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a miniOrange SAML Connection, you'll need an IdP Metadata URL. Start by logging in to your WorkOS dashboard and browse to the "Organizations" tab on the left hand navigation bar. Select the organization you'd like to configure a miniOrange SAML Connection for, and select "Manually Configure Connection" under "Identity Provider". ![A screenshot showing the Manual Configure Connection option in the WorkOS Dashboard.](https://images.workoscdn.com/images/24066931-e200-4e59-9996-3e28738a5b48.png?auto=format&fit=clip&q=50) Select "miniOrange SAML" from the Identity Provider dropdown, enter a descriptive name for the connection, and then select the "Create Connection" button. ![A screenshot showing a miniOrange connection being created in the WorkOS Dashboard.](https://images.workoscdn.com/images/08437cb1-adc7-422e-83d9-4886cba0ece3.png?auto=format&fit=clip&q=50) --- ## What WorkOS provides WorkOS provides the [ACS URL](/glossary/acs-url), [SP Entity ID](/glossary/sp-entity-id) and [SP Metadata URL](/glossary/sp-metadata). They're readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). For this configuration, you should only need to use the SP Metadata URL, but other fields are provided should you choose to do a more manual configuration. ![A screenshot showing the Service Provider Details provided by WorkOS for a miniOrange connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/0cf5969a-7cc5-4646-89bb-b19a7c54ec60.png?auto=format&fit=clip&q=50) --- ## What you'll need Next, provide the IdP Metadata URL. Normally, this information will come from the organization's IT Management team when they set up your application's SAML 2.0 configuration in their miniOrange admin dashboard. But, should that not be the case during your setup, the next steps will show you how to obtain it. --- ## (1) Select or create your application Log in to [miniOrange](https://login.xecurify.com/moas/login), go to the admin dashboard and select "Apps" on the left side navigation. If your application is already created, select it from the list of applications and move to Step 2. Otherwise, select "Add Application". ![A screenshot showing where to select Add Application in the miniOrange dashboard.](https://images.workoscdn.com/images/d7abb7b9-41ad-4a8a-80e9-9f13fbfe7cc0.png?auto=format&fit=clip&q=50) Under "SAML/WS-FED", select "Create App". ![A screenshot showing where to select Create App in the miniOrange dashboard.](https://images.workoscdn.com/images/036c42e8-fe89-4699-8149-878fa27cc3bb.png?auto=format&fit=clip&q=50) Search for "custom" in the search box and select "Custom SAML App". ![A screenshot showing where to select Custom SAML App in the miniOrange dashboard.](https://images.workoscdn.com/images/7b5b3d54-f81b-4c72-a883-8d02f72c742e.png?auto=format&fit=clip&q=50) --- ## (2) Initial SAML Application Setup Under the "Basic Settings" tab of the SAML app, select "Import SP Metadata". ![A screenshot highlighting the "Import SP Metadata" button in the miniOrange Dashboard.](https://images.workoscdn.com/images/e162dc6c-3b87-4811-935f-99c6625ac45a.png?auto=format&fit=clip&q=50) Give the SAML app a descriptive name under "App Name". Under "SP Metadata", select "URL" and input the SP Metadata URL from your SSO Connection settings in the WorkOS Dashboard. Then, hit "Import". ![A screenshot showing how to enter an App name and input a metadata URL in the miniOrange dashboard.](https://images.workoscdn.com/images/fe57d767-efc5-4e64-8a11-cd3b1d939eb5.png?auto=format&fit=clip&q=50) Make sure that you have the "Sign Assertion" field toggled on. ![A screenshot showing the "Sign Assertion" toggle activated in the miniOrange dashboard.](https://images.workoscdn.com/images/3100fed7-3173-4679-8151-2f30da20a062.png?auto=format&fit=clip&q=50) Select "Next". ![A screenshot highlighting the "Next" button in the miniOrange dashboard.](https://images.workoscdn.com/images/91e21543-19e0-4c50-b9e9-dd5f954ef4b7.png?auto=format&fit=clip&q=50) --- ## (3) Configure SAML Application Under the "Attribute Mapping" section of the SAML app, select "Add Attribute". ![A screenshot showing where to select "Add Attribute" in the miniOrange dashboard.](https://images.workoscdn.com/images/d72f5337-e2ee-412e-b3b4-153e4e406526.png?auto=format&fit=clip&q=50) Map the following four attributes as shown below, and the select "Save". - `id` → `Username` - `email` → `E-Mail Address` - `firstName` → `First Name` - `lastName` → `Last Name` ![A screenshot showing how to input user attribute mapping in the miniOrange dashboard.](https://images.workoscdn.com/images/66a87e11-ce03-4426-b7b1-044a2c8e9f9a.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, follow the guidance below. On your SAML app's Settings page, scroll down to "Attributes" and add a new attribute. Set the attribute's name to `groups` and map it to the "User Groups" field. Click "Save". ![A screenshot showing how to add a groups attribute in the miniOrange dashboard.](https://images.workoscdn.com/images/6ca4414d-fc41-455c-812f-353eb4e77459.png?auto=format&fit=clip&q=50) > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (4) Upload Metadata URL Back on the "Apps" tab of the miniOrange Dashboard, click "Select" next to the app you've created. From the dropdown, select "Metadata". ![A screenshot highlighting where to select "Metadata" in the miniOrange dashboard.](https://images.workoscdn.com/images/39c6b33f-f3f3-4728-a70d-27672ae2e9f7.png?auto=format&fit=clip&q=50) Under the "Information required to set miniOrange as IdP" section, click the icon next to "Metadata URL" to copy it to your clipboard. ![A screenshot showing where to copy the Metadata URL in the miniOrange dashboard.](https://images.workoscdn.com/images/42746ff9-c33a-4c14-85c0-273cb5a1939d.png?auto=format&fit=clip&q=50) In the Connection settings in the WorkOS Dashboard, click "Edit Metadata Configuration". ![A screenshot highlighting the "Edit Metadata Configuration" button in a Connection details view in the WorkOS Dashboard.](https://images.workoscdn.com/images/5ad0b7db-f33a-4a06-acf5-83809feaa2ad?auto=format&fit=clip&q=50) Paste the Metadata URL from miniOrange into the "Metadata URL" field and select "Save Metadata Configuration". ![A screenshot showing how to input the Metadata URL into the Connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/13ae3b21-964f-471b-972f-f5fc2b570ccd.png?auto=format&fit=clip&q=50) Your Connection will then be linked and good to go! ### Microsoft OAuth Learn how to set up OAuth with Microsoft ## Introduction The Microsoft OAuth integration allows your users to authenticate using their Microsoft credentials through the "Sign in with Microsoft" flow. The configuration process involves creating or configuring an application in Microsoft Azure and setting up OAuth permissions with the client credentials in the WorkOS Dashboard. --- ## Testing with default credentials in the staging environment WorkOS provides a default Microsoft Client ID and Client Secret combination, which allows you to quickly enable and test Microsoft OAuth. Use the [WorkOS API to initiate SSO](/sso/1-add-sso-to-your-app/add-an-endpoint-to-initiate-sso), setting the `provider` parameter to `MicrosoftOAuth`, and WorkOS will automatically use the default credentials until you add your own Microsoft Client ID and Client Secret to the configuration in the WorkOS Dashboard. > The default credentials are only intended for testing and therefore only available in the Staging environment. For your production environment, please follow the steps below to create and specify your own Microsoft Client ID and Client Secret. Please note that when you are using WorkOS default credentials, Microsoft's authentication flow will display WorkOS' name, logo, and other information to users. Once you register your own application and use its Microsoft Client ID and Client Secret for the OAuth flow, you will have the opportunity to customize the app, including its name, logo, contact email, etc. --- ## What WorkOS provides When setting up Microsoft OAuth, WorkOS provides one key piece of information that needs to be configured in your Microsoft Azure application: - [Redirect URI](/glossary/redirect-uri): The endpoint where Microsoft will send authentication responses after successful login The Redirect URI is available in the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select **Authentication** tab and the **OAuth providers** sub-tab. Locate the **Microsoft** section. ![Open the Microsoft configuration dialog](https://images.workoscdn.com/images/c1518c6e-a765-4101-90eb-0795763aff92.png?auto=format&fit=clip&q=50) Click **Manage**. The **Microsoft OAuth** configuration dialog will open. Locate the **Redirect URI**. ![Microsoft OAuth Redirect URI in the WorkOS Dashboard.](https://images.workoscdn.com/images/ba067eab-be24-404e-9d15-d1cc87720a57.png?auto=format&fit=clip&q=50) The **Redirect URI** serves as the destination for authentication responses and must be configured in your Microsoft Azure application's authentication settings. --- ## What you'll need You will need to obtain two pieces of information from a Microsoft Azure application: - **Microsoft Client ID**: Application identifier from Microsoft Azure - **Microsoft Client Secret**: Authentication secret for the application The following sections will guide you through creating an application in your Microsoft Azure Portal and generating these credentials. > IMPORTANT: When registering your app, select **Personal Microsoft accounts only** for **Supported Account Types**. ![The "Supported Account Types" setting in the Microsoft Azure Dashboard.](https://images.workoscdn.com/images/67aea66f-d0f3-45f1-a314-06b3ae570e24.png?auto=format&fit=clip&q=50) --- ## (1) Create or access Microsoft Azure application Sign in to the [Microsoft Azure Portal](https://portal.azure.com/) and navigate to **Microsoft Entra ID** from the left hand navigation. If you don't already have an application, click **App registrations** and then **New registration** to create one. When registering, you must select **Personal Microsoft accounts only** for **Supported Account Types**. If you already have an application, select **App registrations** and then select your relevant application. ![Where to select an application in the Azure Portal.](https://images.workoscdn.com/images/334e0a97-80d5-4458-a3d7-6b4ec3f8f584.png?auto=format&fit=clip&q=50) --- ## (2) Configure authentication settings Select the **Authentication** option for the application. In the **Redirect URIs** section, add the **Redirect URI** from the WorkOS Dashboard. When selecting a platform, choose **Web**. ![Where to enter the Redirect URI in the Azure App Settings.](https://images.workoscdn.com/images/b320ec4d-7dbb-4026-8bdb-7c6235dddb77.png?auto=format&fit=clip&q=50) --- ## (3) Configure token claims Under **Token configuration**, select **Add optional claim**. Select **email**, **family\_name** and **given\_name**. If shown, select the **Turn on the Microsoft Graph email, profile permission** checkbox. In order for the email claim to come through, the **Email** field for the user in Azure needs to be populated. ![Where to add claims in the Azure App Settings.](https://images.workoscdn.com/images/afe439ec-5d81-474f-9877-3657c3d50d1a.png?auto=format&fit=clip&q=50) --- ## (4) Generate client credentials To get the Microsoft Client Secret, navigate to **Certificates & secrets** and click on **New client secret**. Give the client secret a description and select **Add**. Microsoft's client secrets have an expiration date, with the highest value being 24 months. You will need to track these and rotate them before the expiration time. ![Where to create a client secret in the Entra ID App Settings.](https://images.workoscdn.com/images/1f7eca0b-700d-42f8-911a-238a3dee3df8.png?auto=format&fit=clip&q=50) Copy the **value** of the new client secret as you'll need it for the WorkOS configuration. ![Where to copy the Entra ID Client Secret.](https://images.workoscdn.com/images/98510fb9-db6c-43c6-9a79-85284916b169.png?auto=format&fit=clip&q=50) To obtain the Microsoft Client ID, navigate to the **Overview** tab of your application and copy the **Application (client) ID**. ![Where to copy the Entra ID Client ID.](https://images.workoscdn.com/images/6c79e0bc-9560-4a27-96f3-64569da1aa0e.png?auto=format&fit=clip&q=50) --- ## (5) Configure Microsoft credentials in WorkOS Now that you have the **Microsoft Client ID** and **Microsoft Client Secret** from the previous steps, return to the [WorkOS Dashboard](https://dashboard.workos.com). In the **Microsoft OAuth** configuration dialog, select **Your app's credentials**. Paste the credentials from Microsoft into their respective fields in the WorkOS Dashboard. ![Where to enter Microsoft OAuth client credentials into the WorkOS Dashboard.](https://images.workoscdn.com/images/2d7e1ea9-ea44-439c-bbaf-f4c19569b7aa.png?auto=format&fit=clip&q=50) Click **Save** to complete the configuration. After that, you're now able to authenticate users with Microsoft OAuth. You will use the `provider` query parameter in the Get Authorization URL API endpoint to support global Microsoft OAuth for any domain. The `provider` query parameter should be set to `MicrosoftOAuth`. --- ## Configure Additional OAuth Scopes (Optional) WorkOS will request the OAuth scopes that are required for authentication by default. You can optionally configure your integration to request additional OAuth scopes as needed. When the **Return Microsoft OAuth tokens** option is selected, the access token and refresh token from Microsoft will be included in the response from the [Authenticate with code API](/reference/authkit/authentication/code). ![A screenshot showing Microsoft OAuth scopes configuration in the WorkOS Dashboard](https://images.workoscdn.com/images/af28d982-0bc2-4240-be1a-9f97068d036f.png?auto=format&fit=clip&q=50) Any scopes configured here will be included on every Microsoft OAuth request. To specify additional scopes dynamically, use the `provider_scopes` query parameter on the [Get Authorization URL API endpoint](/reference/authkit/authentication/get-authorization-url). Any additional scopes that you plan to request should also be configured as API permissions on your Microsoft Azure application. For more information, see Microsoft's OAuth scopes [documentation](https://learn.microsoft.com/en-us/entra/identity-platform/scopes-oidc). ![A screenshot showing Microsoft OAuth scopes configuration in Azure App Registration](https://images.workoscdn.com/images/537b2f36-cfb0-4c35-83a6-7fee760418d5.png?auto=format&fit=clip&q=50) > IMPORTANT: Your users may see errors during sign-in if the scopes included on an authorization request are not included in the API permissions configured on your Microsoft Azure application. Changes to scopes should be tested in a staging environment before applying them to production. --- ## Frequently asked questions ### How is the WorkOS Microsoft OAuth integration different from implementing regular Microsoft OAuth flow? It's the same Microsoft OAuth flow as you could build yourself, but it's encapsulated within WorkOS SSO. This means you don't need to build it yourself. In addition to Microsoft OAuth, you can use WorkOS SSO to support other identity providers, all with a single integration. ### What is the provider query parameter and how is it used in the Microsoft OAuth integration? You can use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/sso/get-authorization-url) to support global Microsoft OAuth for any domain. The `provider` query parameter should be set to `MicrosoftOAuth`. This is necessary because Microsoft OAuth does not take a user's domain into account when logging in with a "Sign in with Microsoft" button. ### Why do I need to select "Personal Microsoft accounts only" for account types? This setting is required for the WorkOS integration to function properly. It ensures that the OAuth flow works with personal Microsoft accounts rather than organizational accounts, which have different authentication requirements. ### How long do Microsoft client secrets last? Microsoft's client secrets have an expiration date, with the maximum value being 24 months. You will need to track these and rotate them before the expiration time to maintain continuous authentication functionality. ### Microsoft AD FS SAML Configure a connection to Microsoft Active Directory Federation Services. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create an AD FS SAML Connection, you'll need two pieces of information: an [SP Metadata](/glossary/sp-metadata) file and an IdP Metadata URL. --- ## (1) Configure a Relying Party Trust Open the AD FS Management console. ![A screenshot showing the AD FS Management Console.](https://images.workoscdn.com/images/39b62cf2-a830-4cfc-b057-1717cec6e870.png?auto=format&fit=clip&q=50&w=1200) Click "Relying Party Trusts" on the left sidebar. Click "Add Relying Party Trust..." on the right sidebar to open the "AD FS Relying Party Trust Wizard". ![A screenshot showing where to add the AD FS Relying Party Trust.](https://images.workoscdn.com/images/b99f15c0-ac9d-4cd4-bd78-38f00cd3cfee.png?auto=format&fit=clip&q=50&w=1200) Select "Claims aware" and then "Start". ![A screenshot showing where to select claims in the AD FS Relying Party Trust Wizard.](https://images.workoscdn.com/images/1aaf2490-580f-4930-91b4-258326b751c3.png?auto=format&fit=clip&q=50&w=1200) Download the provided Metadata file from WorkOS by heading to the SP Metadata link in the Dashboard. Select "Import data about the relying party from a file" then select the SP Metadata file you downloaded, and click "Next". ![A screenshot showing where to import the WorkOS Metadata File.](https://images.workoscdn.com/images/9cf7ee4f-09d8-4dcc-ab92-29732ca3c691.png?auto=format&fit=clip&q=50&w=1200) Select "Permit everyone" and then "Next". ![A screenshot showing where to configure access control permissions in the AD FS Relying Party Trust Wizard.](https://images.workoscdn.com/images/94d90815-ef73-4cf5-9a8e-9b85108163d3.png?auto=format&fit=clip&q=50&w=1200) --- ## (2) Choose Access Policy Click the "Endpoints" tab and confirm that the "SAML Assertion Consumer Endpoints" matches the SAML Assertion Consumer Endpoint `https://auth.workos.com/sso/saml/acs/:id` and click "Next". ![A screenshot showing where to check the ACS URL in AD FS.](https://images.workoscdn.com/images/c0c58966-3656-4079-b9c4-1ed01e2d2412.png?auto=format&fit=clip&q=50&w=1200) Select "Configure claims issuance policy for this application" and "Close". ![A screenshot showing where to configure the AD FS claims.](https://images.workoscdn.com/images/a786ee79-750e-464f-ad4c-bdf685a7aec0.png?auto=format&fit=clip&q=50&w=1200) --- ## (3) Configure Claims Issuance Policy Click "Add Rule" in the "Edit Claims Issuance Policy" window. ![A screenshot showing where to add a rule in the Edit Claims Issuance Policy window.](https://images.workoscdn.com/images/b0ce3aa1-5a5c-498a-8b40-f9297ed03a29.png?auto=format&fit=clip&q=50&w=1200) Select "Send LDAP Attributes as Claims" and then "Next". ![A screenshot showing where to select a rule template in the Transform Claim Rule Wizard.](https://images.workoscdn.com/images/753196aa-ebd0-4456-a961-4faacbfddbd2.png?auto=format&fit=clip&q=50) Submit "Attributes" as "Claim rule name", then select "Active Directory" as "Attribute Store", and configure the following attribute mappings. Then click "OK". - `E-Mail-Addresses` → `E-Mail Address` - `Given-Name` → `Given Name` - `Surname` → `Surname` - `User-Principal-Name` → `UPN` ![A screenshot showing where to map attributes in the Transform Claim Rule Wizard.](https://images.workoscdn.com/images/e835b332-47de-43e5-a34d-0031395dee9c.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, follow the guidance below. Select "Group" as the "Outgoing Claim Type" and map an LDAP Attribute to send groups. For example, to send all groups, map the "Token-Groups - Unqualified Names" attribute. ![A screenshot showing how to map the Group claim.](https://images.workoscdn.com/images/72de6a78-46cc-4499-8ef6-f7c05fa0a087.png?auto=format&fit=clip&q=50) > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (4) Upload Metadata URL Next you will want to obtain the Metadata URL from your AD FS server. AD FS publishes its metadata to a standard URL by default: `https://SERVER/federationmetadata/2007-06/federationmetadata.xml` where "SERVER" is your federation service FQDN. You can also find your ADFS Federation Metadata URL through the AD FS Management in "AD FS → Service → Endpoints" and navigate to the Metadata section. ![A screenshot showing where to find the AD FS Metadata URL.](https://images.workoscdn.com/images/f9c91a23-847c-4032-9bbb-888d071db27d.png?auto=format&fit=clip&q=50) Once you have obtained the Metadata URL you will then navigate to the connection settings in WorkOS, click "Edit Metadata configuration", and upload the Metadata URL. ![A screenshot showing where to upload the AD FS Metadata URL in the WorkOS Dashboard.](https://images.workoscdn.com/images/0ab739ca-8edd-436d-b6a6-4efe3cf598fc.png?auto=format&fit=clip&q=50) Once uploaded the connection will be verified and linked! ### Login.gov OpenID Connect Learn how to configure a connection to Login.gov via OIDC. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. > Note: [Login.gov](http://login.gov/) is used for government agencies. You will need to go through Login.gov to obtain a test account and get your application cleared for production. Please reference [Login.gov's developer documentation](https://developers.login.gov/testing/) for more information. To create a Login.gov OpenID Connect (OIDC) Connection, you'll need four pieces of information: a [Redirect URI](/glossary/redirect-uri), a Public Certificate, a [Client ID](/glossary/client-id), and a Discovery Endpoint. Start by logging in to your WorkOS dashboard and browse to the "Organizations" tab on the left-hand navigation bar. Select the organization you'd like to configure a Login.gov OIDC Connection for, and select "Manually Configure Connection" under "Identity Provider". ![A screenshot showing where to find "Manually Configure Connection" in the WorkOS Dashboard.](https://images.workoscdn.com/images/32e5ff2f-4756-48ab-8c01-9ea6c04a0162.png?auto=format&fit=clip&q=50) Select "Login.gov OpenID Connect" from the Identity Provider dropdown, enter a descriptive name for the connection, and then select the "Create Connection" button. ![A screenshot showing "Create Connection" details in the WorkOS Dashboard.](https://images.workoscdn.com/images/59b7ae81-487d-4e3b-a1d7-d6e293452d1b.png?auto=format&fit=clip&q=50) --- ## What WorkOS provides WorkOS provides the Redirect URI and the Public Certificate. They are readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/get-started). ![A screenshot showing where to find the Redirect URI and Public Certificate in the WorkOS Dashboard.](https://images.workoscdn.com/images/cabe8cea-016e-4070-abe9-43b19b86699d.png?auto=format&fit=clip&q=50) The Redirect URI is the location Login.gov redirects its authentication and token responses to, and the Public Certificate is used by Login.gov to verify the signed request from WorkOS. Specifically, the Redirect URI will need to be set as one of the "Redirect URIs" and the Public Certificate will need to be set as one of the "Public Certificates" in the Login.gov application settings: ![A screenshot showing where to upload the Public Certificate and Redirect URI within the Login.gov dashboard.](https://images.workoscdn.com/images/2c615ec0-e266-492f-a32b-07d55c04b0ad.png) ## What you'll need In order to integrate you'll need the [Client ID](/glossary/client-id) and the Discovery Endpoint. Normally, this information will come from the organization's IT Management team when they set up your application's Login.gov OpenID Connect configuration in their Identity Provider admin dashboard. But, should that not be the case during your setup, here's how to obtain them. --- ## (1) Access the Login.gov Developer Sandbox Login to your [Login.gov sandbox dashboard](https://dashboard.int.identitysandbox.gov), and select "Apps" from the top menu. ![A screenshot showing the Login.gov sandbox dashboard and how to select the App menu option.](https://images.workoscdn.com/images/21a33031-818d-4b44-8646-648a45fc4e5a.png) > Note: Login.gov is used exclusively by government agencies. If you don't have dashboard access for your Sandbox account, please reach out to the government agency you're working with to get access to their sandbox dashboard. Please reference [Login.gov's developer documentation](https://developers.login.gov/testing/) for more information. --- ## (2) Select or create your application If your application is already created, select it from the list of applications and move to Step 4. If you haven't created an application, select "Create a new test app." ![A screenshot showing where to find the "Create a new test app" button in Login.gov "My app" listing.](https://images.workoscdn.com/images/96e14854-9acc-4ddd-8339-4312b80f7883.png) --- ## (3) Application Setup On the New test app page, select "Yes" under the Production configuration setting. Then, add an App name, Friendly name, and Description for the app. Next, assign an agency team to this client. ![A screenshot showing where to select "Yes" under the Production configuration setting as well as the add an App name, Friendly name, Description, and Team for the Login.gov app during setup.](https://images.workoscdn.com/images/ac9a9962-4058-4876-8fd8-4542f2b93711.png) Select "OpenID Connect Private Key JWT" as the Authentication protocol. Select the appropriate Level of Service, Default Authentication Assurance Level (AAL), and Attribute bundle for your application. ![A screenshot showing where to setup the Application protocol, Level of Service, Default Authentication Assurance Level, and Attributes Bundle during Login.gov application setup.](https://images.workoscdn.com/images/42b994de-61ac-4856-b954-12503cc3e45f.png) Next, you'll need to define an Issuer - something like `urn:gov:gsa:openidconnect.profiles:sp:sso:agency_name:app_name` - replacing your agency and app name. Then, upload a logo and the public certificate file you downloaded from the WorkOS dashboard. ![A screenshot showing where to set the Issuer and upload a Logo and Public Certificate during Login.gov application setup.](https://images.workoscdn.com/images/f20e0870-1ec9-41d4-be5c-76103d177400.png) Finally, you'll need to add the Redirect URIs. The first one you'll need to add is the Redirect URI you copied from the WorkOS Dashboard. You'll also need to add the [Redirect URI for your application](/sso/redirect-uris). There is a Content Security Policy (CSP) check from Login.gov, so all URIs that could potentially be redirected to the authentication flow should be listed here. ![A screenshot showing where to upload the Redirect URI during Login.gov application setup.](https://images.workoscdn.com/images/2fd99552-43e3-4a74-b211-97619af4f7de.png) Scroll down to the bottom of the page and select "Create test app" to finish the setup. --- ## (4) Provide the Client ID and Discovery Endpoint Enter the Issuer you created in the previous step as the Client ID in the WorkOS Dashboard. Additionally, add the discovery endpoint, which for production accounts in Login.gov is: `https://secure.login.gov/.well-known/openid-configuration`. Click "Update connection". ![A screenshot showing where to add the Client ID and Discovery Endpoint and Update Connection within the WorkOS Dashboard.](https://images.workoscdn.com/images/986718f3-0007-4894-9bd2-29892ff955d5.png?auto=format&fit=clip&q=50) --- ## (5) Request Production Deployment Please follow the [Login.gov docs to request a production deployment](https://developers.login.gov/production/) and finish your Login.gov application. ### LinkedIn OAuth Learn how to set up OAuth with LinkedIn ## Introduction The LinkedIn OAuth integration allows your users to authenticate using their LinkedIn credentials. The configuration process involves creating an OAuth application in LinkedIn and configuring the client credentials in your WorkOS Dashboard. --- ## What WorkOS provides When setting up LinkedIn OAuth, WorkOS provides one key piece of information that needs to be configured in your LinkedIn OAuth application: - [Redirect URI](/glossary/redirect-uri): The endpoint where LinkedIn will send authentication responses after successful login The Redirect URI is available in the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select the **Authentication** tab and the **OAuth providers** sub-tab. Locate the **LinkedIn** section. ![The LinkedIn OAuth section in the WorkOS Dashboard.](https://images.workoscdn.com/images/d9cc3fce-75fc-410e-91d4-5706c88c609f.png?auto=format&fit=clip&q=50) Click **Enable**. The **LinkedIn OAuth** configuration dialog will open. Locate the **Redirect URI**. ![The LinkedIn OAuth configuration modal in the WorkOS Dashboard.](https://images.workoscdn.com/images/3b7a3d3e-391d-401f-92a4-74bfd57b0dc5.png?auto=format&fit=clip&q=50) The **Redirect URI** serves as the destination for authentication responses and must be configured in your LinkedIn OAuth application as an authorized redirect URL. --- ## What you'll need You will need to obtain two pieces of information from a LinkedIn Developer application: - **LinkedIn Client ID**: Application identifier from LinkedIn - **LinkedIn Client Secret**: Authentication secret for the application (called Primary Client Secret in LinkedIn) The following sections will guide you through creating an OAuth application in your LinkedIn Developer account and generating these credentials. --- ## (1) Create the LinkedIn OAuth application Log in to your LinkedIn account and navigate to the [LinkedIn Developer Portal](https://developer.linkedin.com). Click **Create app**. ![The LinkedIn page to register a new OAuth application.](https://images.workoscdn.com/images/75a8bb4c-8df2-4c9d-b205-5e9e07d31501.png?auto=format&fit=clip&q=80) Fill out the form with the required details about your application, including the application name, LinkedIn page, and app logo. ![The LinkedIn form to create a new OAuth application.](https://images.workoscdn.com/images/7da6ffdf-adda-4218-ac93-c2b211bfb12e.png?auto=format&fit=clip&q=80) Click **Create app** to create the application. --- ## (2) Configure OAuth settings and obtain client credentials On the application page, click the **Auth** tab. Copy the **Client ID** and **Primary Client Secret** as you'll need them for the WorkOS configuration. ![OAuth client credentials in the LinkedIn developer settings.](https://images.workoscdn.com/images/da63c1b4-44d3-43ca-a962-a1f7e641dc0e.png?auto=format&fit=clip&q=80) Click the pencil button next to **OAuth 2.0 settings** > **Authorized redirect URLs for your app**. Click **Add redirect URL** and paste the **Redirect URI** from the WorkOS Dashboard. Click **Update**. ![OAuth redirect URL in the LinkedIn developer settings.](https://images.workoscdn.com/images/9e838b55-e2c7-4b30-bf68-8531e7bf376a.png?auto=format&fit=clip&q=80) --- ## (3) Add OIDC support Click the **Products** tab and add the **Sign In with LinkedIn using OpenID Connect** product to enable OIDC authentication capabilities. ![The LinkedIn OIDC configuration dashboard.](https://images.workoscdn.com/images/f629579e-0ff1-42da-b1fc-40f577ae6723.png?auto=format&fit=clip&q=80) --- ## (4) Configure LinkedIn credentials in WorkOS Now that you have the **LinkedIn Client ID** and **LinkedIn Client Secret** (Primary Client Secret) from the previous steps, return to the [WorkOS Dashboard](https://dashboard.workos.com). In the **LinkedIn OAuth** configuration dialog, enable the integration. Paste the credentials from LinkedIn into their respective fields in the WorkOS Dashboard. ![The LinkedIn OAuth configuration modal in the WorkOS Dashboard.](https://images.workoscdn.com/images/053443da-9ab9-45a3-b345-4bc1cf0c6fd6.png?auto=format&fit=clip&q=50) Click **Save** to complete the configuration. You are now ready to start authenticating with LinkedIn OAuth. You will use the `provider` query parameter in the Get Authorization URL API endpoint to support global LinkedIn OAuth for any domain. The `provider` query parameter should be set to `LinkedInOAuth`. --- ## Frequently asked questions ### How is the WorkOS LinkedIn OAuth integration different from implementing regular LinkedIn OAuth flow? It's the same LinkedIn OAuth flow as you could build yourself, but it's encapsulated within WorkOS SSO. This means you don't need to build it yourself. In addition to LinkedIn OAuth, you can use WorkOS SSO to support other identity providers, all with a single integration. ### What is the provider query parameter and how is it used in the LinkedIn OAuth integration? You can use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/sso/get-authorization-url) to support global LinkedIn OAuth for any domain. The `provider` query parameter should be set to `LinkedInOAuth`. ### Do I need a LinkedIn Company Page to create an OAuth application? Yes, LinkedIn requires that OAuth applications be associated with a LinkedIn Company Page. This is a requirement from LinkedIn to ensure applications are associated with legitimate businesses or organizations. ### What is the difference between Client ID and Primary Client Secret in LinkedIn? The **Client ID** is the public identifier for your LinkedIn application, while the **Primary Client Secret** is the private authentication key that must be kept secure. The Primary Client Secret is what WorkOS refers to as the LinkedIn Client Secret. ### Why do I need to add the "Sign In with LinkedIn using OpenID Connect" product? This product enables OIDC (OpenID Connect) authentication capabilities for your LinkedIn application, which is required for the WorkOS integration to function properly. Without this product, the OAuth flow will not work correctly. ### LastPass Learn how to configure a connection to LastPass via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a LastPass SAML Connection, you'll need an IdP Metadata XML file. Start by logging in to your WorkOS dashboard and browse to the "Organizations" tab on the left hand navigation bar. Select the organization you'd like to configure a LastPass SAML Connection for, and select "Manually Configure Connection" under "Identity Provider". ![A screenshot showing where to find "Manually Configure Connection" in the WorkOS Dashboard.](https://images.workoscdn.com/images/ff2ce096-00e1-4d34-8523-23a01ebf4642.png?auto=format&fit=clip&q=50) Select "LastPass SAML" from the Identity Provider dropdown, enter a descriptive name for the connection, and then select the "Create Connection" button. ![A screenshot showing "Create Connection" details in the WorkOS Dashboard.](https://images.workoscdn.com/images/5866a365-5f51-4f58-9124-a4c0653831a5.png?auto=format&fit=clip&q=50) --- ## What WorkOS provides WorkOS provides the [ACS URL](/glossary/acs-url), [SP Entity ID](/glossary/sp-entity-id), and [SP Metadata URL](/glossary/sp-metadata). They're readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot showing where to find the ACS URL, SP Metadata, and SP Entity ID in the WorkOS Dashboard.](https://images.workoscdn.com/images/93089510-e362-47c9-9844-4eefd70e18ca.png?auto=format&fit=clip&q=50) --- ## What you'll need Next, provide the [IdP Metadata](/glossary/idp-metadata) file. Normally, this information will come from your enterprise customer's IT Management team when they set up your application's SAML 2.0 configuration in their LastPass admin console. But, should that not be the case during your setup, the next steps will show you how to obtain it. --- ## (1) Select or create your application Log in to [LastPass](https://admin.lastpass.com/applications/saml), go to the admin console and select "Applications" on the top navigation. Then select "SSO apps" from the left side navigation. If your application is already created, select it from the list of applications and move to Step 2. Otherwise, select "Add app". ![A screenshot showing "Add app" in the "SSO apps" section of the Applications tab in the LastPass admin dashboard.](https://images.workoscdn.com/images/e6cc5fbc-e802-4cd4-b3d6-786c31ee7db2.png?auto=format&fit=clip&q=50) In the modal that pops up, click on "Add an unlisted app". ![A screenshot showing the selection of "Add an Unlisted App" for the creation of a new SSO app.](https://images.workoscdn.com/images/fad2dc44-73a1-4b98-b8bb-ee02e7293dfd.png?auto=format&fit=clip&q=50) Give your SAML App a descriptive name and select "Continue". ![A screenshot showing how to add the name for a new SSO app.](https://images.workoscdn.com/images/839575b4-8b1c-45e5-ab10-8fcc509fc1be.png?auto=format&fit=clip&q=50) --- ## (2) Initial SAML Application Setup Under the "Set up LastPass" section of the "Configure app" modal, input the ACS URL from the WorkOS Dashboard Connection details under "ACS". Then click on "Advanced Settings". ![A screenshot showing where to add the ACS URL during the configuration app step in LastPass SAML Settings.](https://images.workoscdn.com/images/01e69cb0-8c93-474f-ad15-6cde111ac699.png?auto=format&fit=clip&q=50) Under "Entity ID", input the SP Entity ID from the WorkOS Dashboard Connection details. Next, under "SAML signature method", select "SHA256". ![A screenshot showing where to add the Entity ID during the configuration app step in LastPass SAML Settings.](https://images.workoscdn.com/images/4b80975b-c0bb-4efd-80dd-3a3c52836ec5.png?auto=format&fit=clip&q=50) Under "Signing and encryption", ensure that you have at least selected "Sign assertion". Then, click on "Add SAML attribute". ![A screenshot showing to select "Sign assertion" checkbox option for "Signing and encryption" in LastPass SAML Settings.](https://images.workoscdn.com/images/0e2a022f-444b-468b-91ad-cb2078142425.png?auto=format&fit=clip&q=50) --- ## (3) Configure SAML Application Map the following four attributes as shown below, and select "Save & assign users". - First Name → `firstName` - Last Name → `lastName` - Email → `email` - User ID → `id` ![A screenshot showing hot to add Attribute Mapping for a LastPass SAML app.](https://images.workoscdn.com/images/3e75c892-a7cc-4167-9e45-c046232c1231.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, add a new SAML attribute for the "Groups" field and input `groups` as the attribute name, as shown below. Then, select "Save & assign users". ![A screenshot showing how to add a groups attribute to a LastPass SAML app.](https://images.workoscdn.com/images/611cd4d7-715b-423c-b110-323f00d7ad8c.png?auto=format&fit=clip&q=50) > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (4) Add Users and Groups to SAML Application On the "Users, groups & roles" page, click on "Assign users, groups & roles". ![A screenshot showing to select "Assign users, groups & roles" for your LastPass SAML app.](https://images.workoscdn.com/images/cec59ee3-85f1-45cd-8ed5-03dfef194de9.png?auto=format&fit=clip&q=50) Search and select any users or groups that you would like to provision to this SAML app. Then, click "Assign". ![A screenshot showing to select Users and Groups in LastPass.](https://images.workoscdn.com/images/fc3fd859-1092-45a8-922f-38b4619863d8.png?auto=format&fit=clip&q=50) Click on "Save & continue". ![A screenshot showing where to save and move to next steps in LastPass.](https://images.workoscdn.com/images/4b775f48-9045-4122-8c9c-4770370edd4b.png?auto=format&fit=clip&q=50) --- ## (5) Upload Metadata file Back on the "SSO apps" tab of the LastPass admin console, select the SAML app that you just created. !A screenshot showing where how to select SAML App in LastPass.]\(https://images.workoscdn.com/images/99a9a771-02bc-4817-b576-414bafa2d6f2.png?auto=format&fit=clip&q=50) On the "Configure app" modal, click on "Expand" to the right of "Set up app". ![A screenshot showing how to expand Set Up App in LastPass.](https://images.workoscdn.com/images/e717af8d-f5aa-4629-ae38-d5d0376d57dd.png?auto=format&fit=clip&q=50) At the bottom of the "Set up app" section, click on "Download metadata (XML)". Save the downloaded XML metadata somewhere accessible. ![A screenshot showing where to download Metadata File in LastPass.](https://images.workoscdn.com/images/bbd5f4bc-8386-4650-9559-f072b265d71b.png?auto=format&fit=clip&q=50) In the Connection settings in the WorkOS Dashboard, click "Edit Metadata Configuration". ![A screenshot showing where to edit Metadata Configuration in WorkOS Dashboard.](https://images.workoscdn.com/images/c485258c-6762-4ea7-9999-a2a43767de23.png?auto=format&fit=clip&q=50) Upload the XML metadata file from LastPass into the "Metadata File" field and select "Save Metadata Configuration". ![A screenshot showing a successful upload of the Metadata File in WorkOS Dashboard.](https://images.workoscdn.com/images/dd796b97-442e-4b74-a6ae-c5f2642b717a.png?auto=format&fit=clip&q=50) Your Connection will then be linked and good to go! ### Keycloak Learn how to configure a connection to Keycloak via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). And often, the information required to create a Connection will differ by Identity Provider. To create an Keycloak SAML Connection, you'll need three pieces of information: an [ACS URL](/glossary/acs-url), an Identity Provider Issuer (also known as an Entity ID), and a Metadata URL. --- ## What WorkOS provides WorkOS provides the ACS URL and [IdP URI (Entity ID)](/glossary/idp-uri-entity-id). It's readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot highlighting the "Service Provider Details" generated by WorkOS in the WorkOS Dashboard.](https://images.workoscdn.com/images/1ee74820-5075-4f2b-a1da-25f2c86204d4.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. In Keycloak's case, it needs to be set by the organization when configuring your application in their Keycloak instance. Specifically, the ACS URL will need to be set as the "Valid Redirect URI" and "Master SAML Processing URL" in the SAML client setup in Keycloak. The Entity ID is a URI used to identify the issuer of a SAML request, response, or assertion. In this case, the entity ID is used to communicate that WorkOS will be the party performing SAML requests to the organization's Keycloak instance. Specifically, the Entity ID will need to be set as the "Client ID" when creating a SAML client in Keycloak. --- ## What you'll need In order to integrate you'll need the Keycloak Metadata URL. Normally, the this will come from the organization's IT Management team when they set up your application's SAML client in their Keycloak instance. But, should that not be the case during your setup, here's how to obtain it. --- ## (1) Log in Log in to your Keycloak Admin Console, and navigate to the Realm you want to set up the SAML client in. Select "Clients" from the side menu. If your client is already created, select it from the list of and move to Step 4. If you haven't created a SAML client in Keycloak, select "Create client". ![A screenshot highlighting the "Create client" button in the Keycloak dashboard.](https://images.workoscdn.com/images/ab144a33-174d-4699-83ad-fa5e59b9b31d.png?auto=format&fit=clip&q=50) --- ## (2) Initial SAML Application Setup On the Create Client setup step, select `SAML` as the "Client type", input the IdP URI (Entity ID) from your WorkOS Dashboard as the "Client ID", and set a name for your Client. Click "Save". ![A screenshot highlighting the input fields "Client type", "Client ID" and "Name" in the Keycloak dashboard.](https://images.workoscdn.com/images/9365694a-b125-47e0-8d2e-1e49425e157b.png?auto=format&fit=clip&q=50) --- ## (3) Configure SAML Application On the Settings page, scroll down and input the ACS URL from your WorkOS Dashboard in the "Valid Redirect URIs" and "Master SAML Processing URL" boxes. ![A screenshot highlighting the fields "Valid redirect URIs" and "Master SAML Processing URL in the Keycloak dashboard.](https://images.workoscdn.com/images/a1dea2f2-ea25-44c9-b88e-39b689a37de2.png?auto=format&fit=clip&q=50) Scroll down further on the Settings page to "Signature and Encryption", and make sure that "Sign assertions" is toggled `On`. Click "Save". ![A screenshot highlighting the "Sign documents" and "Sign assertions" toggles switched on in the Keycloak dashboard.](https://images.workoscdn.com/images/dfd9fc38-79b8-4c7d-8ca7-17d1925e8fa2.png?auto=format&fit=clip&q=50) --- ## (4) Configure User Attributes and Claims Click the "Client scopes" top menu option and click into your Client. ![A screenshot highlighting the "Client scopes" tab and "Assigned client scope" field in the Keycloak dashboard.](https://images.workoscdn.com/images/cc6c1ce7-229f-4d1e-90b2-ecf060649018.png?auto=format&fit=clip&q=50) Click "Configure a new mapper". ![A screenshot highlighting the "Configure a new mapper" button in the Keycloak dashboard.](https://images.workoscdn.com/images/3ed96fbb-d089-49ed-979b-2b360a498db0.png?auto=format&fit=clip&q=50&w=2048) Then select "User Property". ![A screenshot highlighting the "User Property" field in the Keycloak dashboard.](https://images.workoscdn.com/images/6f82859d-a433-4e3c-bde4-10b4700e5ba0.png?auto=format&fit=clip&q=50&w=2048) You'll need to create a "User Property" mapper for the following four attributes: - `id` - `email` - `firstName` - `lastName` This is an example of how to fill out the fields for `id`: ![A screenshot showing the proper mapping for the "id" property in the Keycloak dashboard.](https://images.workoscdn.com/images/1d966f7c-358b-46a6-b8d5-cbcb6f80c192.png?auto=format&fit=clip&q=50&w=2048) Also do this for the `email`, `firstName`, and `lastName` attributes: ![A screenshot showing the proper mapping for the "email" property in the Keycloak dashboard.](https://images.workoscdn.com/images/7f753d8c-a7f3-4250-a772-0fb31bddfb03.png?auto=format&fit=clip&q=50&w=2048) ![A screenshot showing the proper mapping for the first name property in the Keycloak dashboard.](https://images.workoscdn.com/images/d037d45f-9d80-4594-b0d2-4ec65dd76d96.png?auto=format&fit=clip&q=50&w=2048) ![A screenshot showing the proper mapping for the last name property in the Keycloak dashboard.](https://images.workoscdn.com/images/0df763a9-7ca9-4bfb-870b-472bc3ef4b8b.png?auto=format&fit=clip&q=50&w=2048) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, follow the guidance below. On the "Dedicated scopes" page, select "Add mapper" and then "By configuration". ![A screenshot showing how to add a new groups attribute mapper.](https://images.workoscdn.com/images/6475d3b7-33b2-47f5-a55e-efd13600b1e0.png?auto=format&fit=clip&q=50) You can choose either "Group list" or "Role list", whichever option best fits your use case. The example below uses "Group list". For more information on sending group information, refer to the [Keycloak documentation](https://www.keycloak.org/docs/latest/server_admin/#assigning-permissions-using-roles-and-groups). ![A screenshot showing what type of mapper to choose for a groups attribute.](https://images.workoscdn.com/images/42a1cfbd-2499-46a7-bc3c-39b284f25e74.png?auto=format&fit=clip&q=50) Set the Name and the Group attribute name to "groups", and make sure the Single Group Attribute toggle is On. Select "Save". ![A screenshot showing how to configure the groups attribute mapper.](https://images.workoscdn.com/images/d95229b8-a5e1-4543-8047-077a38570b01.png?auto=format&fit=clip&q=50) > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. ## (5) Obtain Identity Provider Details Select "Realm Settings" in the left sidebar navigation menu, and copy the "SAML 2.0 Identity Provider Metadata" link on the General page. ![A screenshot highlighting the "SAML 2.0 Identity Provider Metadata" button in the Keycloak dashboard.](https://images.workoscdn.com/images/166ae678-b776-470e-bf66-62bf202207e1.png?auto=format&fit=clip&q=50) Next, within your connection settings, edit the Metadata Configuration and provide the Metadata URL you obtained from Keycloak. Your Connection will then be verified and good to go! ![A screenshot highlight the "URL Metadata Configuration" input in the WorkOS Dashboard.](https://images.workoscdn.com/images/2579b65a-3d39-4344-8df4-6cdf80506c34.png?auto=format&fit=clip&q=50) ### JumpCloud SCIM Learn about syncing your user list with JumpCloud SCIM. ## Introduction This guide outlines how to synchronize your application's JumpCloud directories using SCIM. To synchronize an organization's users and groups provisioned for your application, you'll need to provide the organization with two pieces of information: - An [Endpoint](/glossary/endpoint) that JumpCloud will make requests to. - A [Bearer Token](/glossary/bearer-token) for JumpCloud to authenticate its endpoint requests. Both of these are available in your Endpoint's Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). > Steps 2, 3, and 4 below will need to be carried out by the organization when configuring your application in their JumpCloud instance. --- ## (1) Set up your Directory Sync endpoint Login to your WorkOS Dashboard and select "Organizations" from the left hand navigation bar. Select the organization you'll be configuring a new Directory Sync for. Under "Actions" click "Add Directory". ![A screenshot highlighting the "Add Directory" option within an Organization in the WorkOS Dashboard.](https://images.workoscdn.com/images/5411a8c2-cc56-4593-bc7c-c21c84443dfc.png?auto=format&fit=clip&q=50) Select "JumpCloud" from the dropdown, and enter the organization name. Then, click "Create Directory." ![A screenshot highlighting the "Create Directory" modal for creating a JumpCloud directory in the WorkOS Dashboard.](https://images.workoscdn.com/images/6aaf218c-8d81-4ed6-aa8f-682dd3235dc2.png?auto=format&fit=clip&q=50) Your JumpCloud directory sync has now been created successfully with an Endpoint and Bearer Token. ![A screenshot highlighting the "Directory Details" for a JumpCloud directory in the WorkOS Dashboard.](https://images.workoscdn.com/images/eaad1aef-522e-4f01-a298-3a6b093aa8a1.png?auto=format&fit=clip&q=50) > We have support for custom labeled URLs for Directory Sync endpoints. [Contact us](mailto:support@workos.com) for more info! --- ## (2) Select or create your JumpCloud application Log in to the JumpCloud admin dashboard, select "SSO" on the left and select your Application. ![Select or Create JumpCloud App](https://images.workoscdn.com/images/26901dbc-8236-46b4-a46f-8c828152fe60.png?auto=format&fit=clip&q=50) If you haven't created an application, you'll need to first create a custom SAML application in JumpCloud. JumpCloud only supports configuring SCIM provisioning in an existing SAML application. You can use our JumpCloud SAML documentation to configure your SAML application before moving on to SCIM provisioning. --- ## (3) Configure your integration Select "Identity Management" from the top navigation menu. ![A screenshot highlighting the "SSO" tab and app selection in the JumpCloud admin dashboard.](https://images.workoscdn.com/images/58194668-19eb-4b3b-b07d-a5023d05e766.png?auto=format&fit=clip&q=50) Scroll down to the "Configuration settings" section. Make sure SCIM 2.0 is selected as the SCIM version. Copy and paste the Endpoint from your [WorkOS Dashboard](https://dashboard.workos.com/) in the "Base URL" field. Then, copy and paste the Bearer Token from your [WorkOS Dashboard](https://dashboard.workos.com/) into the "Token Key" field. Next, test the connection to confirm the configuration settings. ![A screenshot highlighting the "Base URL" and "Token Key" input fields in the JumpCloud admin dashboard.](https://images.workoscdn.com/images/6096c0db-b7f6-45ea-aa44-b1f53f167d12.png?auto=format&fit=clip&q=50) After you receive a success message for the configuration, make sure the Group Management toggle is "On", and then activate the settings. ![A screenshot highlight the "Group Management" field toggled on in the JumpCloud admin dashboard.](https://images.workoscdn.com/images/aa71e757-ec72-4f72-9551-cd43e72cf44b.png?auto=format&fit=clip&q=50) After the activation step is successful, save the configuration. ![A screenshot highlighting the "Save" button in the JumpCloud admin dashboard.](https://images.workoscdn.com/images/3a8a81bc-e204-4368-b281-6aec5666b817.png?auto=format&fit=clip&q=50) --- ## (4) Assign users and groups to your application In order for your users and groups to be synced, you will need to assign them to your JumpCloud Application. Select "User Groups" from the top navigation menu. Select the groups of users you would like to sync and save your changes. ![A screenshot highlighting the User Groups tab in the JumpCloud admin dashboard.](https://images.workoscdn.com/images/505e3ec4-0f83-4e68-a384-1d056f674b23.png?auto=format&fit=clip&q=50) Begin provisioning users and groups and witness realtime changes in your [WorkOS Dashboard](https://dashboard.workos.com/). A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) ## Frequently asked questions ### When a group is disconnected from the SCIM application in JumpCloud, I still see users that are a part of that disconnected group in WorkOS and my application – is this expected? Instead of individually assigning users to a SCIM application, JumpCloud SCIM requires that users are assigned to the application through group membership. To reflect valid user membership in your application, users should be removed from a group while the group is connected to the SCIM application rather than removing them directly from the application. To remove an entire group, the group can be deleted from the JumpCloud User Management area while it is connected to the SCIM application. ### What is the `idp_id` for directory groups from JumpCloud? JumpCloud provides a unique identifier for each group through the SCIM `externalId` field. This is persisted as the `idp_id` for [directory groups](/reference/directory-sync/directory-group) in WorkOS. ### JumpCloud SAML Learn how to configure a connection to JumpCloud via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a JumpCloud SAML Connection, you'll need to upload a JumpCloud Metadata file. --- ## What WorkOS provides WorkOS provides the [ACS URL](/glossary/acs-url) and [SP Entity ID](/glossary/sp-entity-id). They're readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot of the "Service Provider Details" of a JumpCloud Connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/77d299b3-4e00-4259-9580-3a5d47518f7a.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. In JumpCloud's case, the ACS URL and Entity ID need to be set by the organization when configuring your application in their JumpCloud instance. Specifically, the ACS URL and Entity ID will need to be set in the "Single Sign-On Configuration" section of the SAML app. You will input the ACS URL for "ACS URL" and the Entity ID as both "IdP Entity ID" and "SP Entity ID": ![A screenshot highlighting the fields "IdP Entity ID", "SP Entity ID" and "ACS URL" in the JumpCloud dashboard.](https://images.workoscdn.com/images/5897416a-465f-4e71-a2f8-2c12329338b9.png?auto=format&fit=clip&q=50) --- ## What you'll need In order to integrate you'll need the JumpCloud Metadata file. Here's how to obtain it: --- ## (1) Log in Log in to the JumpCloud admin dashboard, select "SSO" on the left and select your Application. ![A screenshot highlighting the SSO tab and app selection in the JumpCloud dashboard.](https://images.workoscdn.com/images/e144fd63-e8a0-40e3-9d6d-db113396b7f8.png?auto=format&fit=clip&q=50) --- ## (2) Configure Attribute Mapping In the "User Attributes" section of the Single Sign-On Configuration page for the SAML app, add the following field-value parameter pairs: - `id` → `email` - `email` → `email` - `firstName` → `firstname` - `lastName` → `lastname` ![A screenshot showing user attribute mapping in the JumpCloud dashboard.](https://images.workoscdn.com/images/47100088-c7b5-4352-96e1-9709f7808b6b.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, follow the guidance below. In the "Group Attributes" section, select the checkbox to "include group attribute", and then set the attribute name to `groups`. ![A screenshot showing 'Group Attributes' in the JumpCloud Admin Console.](https://images.workoscdn.com/images/b6f9fdc0-c660-41ce-8f8e-a99a8c5a4cf0.png?auto=format&fit=clip&q=50) > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. ### Check "Sign Assertion" Be sure to check the "Sign Assertion" box shown below. ![A screenshot highlighting the checked "Sign Assertion" box in the JumpCloud dashboard.](https://images.workoscdn.com/images/e4cca1f9-3f24-45d6-80f7-3ef318eb4ba2.png?auto=format&fit=clip&q=50) --- ## (3) Upload Metadata File Be sure to check "Declare Redirect Endpoint". ![A screenshot highlighting the checked "Declare Redirect Endpoint" box in the JumpCloud dashboard.](https://images.workoscdn.com/images/3a24425c-dd94-4b86-8b3a-f476b6f55665.png?auto=format&fit=clip&q=50) > NOTE: The "Declare Redirect Endpoint" setting needs to be enabled prior to exporting the IdP metadata below as this will alter the metadata. Click the "Export Metadata" button under "JumpCloud Metadata". This will download an XML metadata file. ![A screenshot highlighting the "Export Metadata" button in the JumpCloud dashboard.](https://images.workoscdn.com/images/abd1a6ff-ec7b-427b-b7d5-0813af0107ee.png?auto=format&fit=clip&q=50) In the Connection Settings of the WorkOS Dashboard, click "Edit Metadata Configuration". ![A screenshot highlighting the "Edit Metadata Configuration" button in the WorkOS Dashboard.](https://images.workoscdn.com/images/ead92f35-be05-431f-a987-e4a71745eb3f.png?auto=format&fit=clip&q=50) In the modal that pops up, upload the JumpCloud Metadata file and then select "Save Metadata Configuration". ![A screenshot showing the "XML File Metadata Configuration" modal in the WorkOS Dashboard.](https://images.workoscdn.com/images/060d5353-64ca-426a-a4f2-1b9290aad3f5.png?auto=format&fit=clip&q=50) Once the file has uploaded, your Connection will then be linked and good to go! ### Intuit OAuth Learn how to set up OAuth with Intuit ## Introduction The Intuit OAuth integration allows your users to authenticate using their Intuit credentials. The configuration process involves creating an OAuth application in the Intuit Developer Portal and configuring the client credentials in your WorkOS Dashboard. --- ## What WorkOS provides When setting up Intuit OAuth, WorkOS provides one key piece of information that needs to be configured in your Intuit OAuth application: - [Redirect URI](/glossary/redirect-uri): The endpoint where Intuit will send authentication responses after successful login The Redirect URI is available in the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select the **Authentication** tab and the **Providers** sub-tab. Locate the **Intuit** section. ![The Intuit OAuth section in the WorkOS Dashboard](https://images.workoscdn.com/images/7a608532-0df6-4817-9db3-d50d8481412a.png?auto=format&fit=clip&q=50) Click **Enable**. The **Intuit OAuth** configuration dialog will open. Locate the **Redirect URI**. ![The Intuit OAuth configuration modal in the WorkOS Dashboard](https://images.workoscdn.com/images/0e15b7ba-91dd-4128-a42d-6b986c43fbd5.png?auto=format&fit=clip&q=50) The **Redirect URI** serves as the destination for authentication responses and must be configured in your Intuit OAuth application. --- ## What you'll need You will need to obtain two pieces of information from an Intuit OAuth application: - **Intuit Client ID**: Application identifier from Intuit - **Intuit Client Secret**: Authentication secret for the application The following sections will guide you through creating an OAuth application in the Intuit Developer Portal and generating these credentials. --- ## (1) Create the Intuit OAuth application Log in to your [Intuit Developer account](https://developer.intuit.com/app/developer/homepage) and navigate to the Apps tab in your Workspace. Click on the plus sign tile to create a new application. ![Intuit Apps page with Create tile](https://images.workoscdn.com/images/c8c80cee-afaf-4261-a9b1-f9a35a24f85b.png?auto=format&fit=clip&q=50) --- ## (2) Configure the Intuit OAuth application You will be prompted to select an app type. Select **Quickbooks Online and Payments** and click **Next** to continue. ![Selecting Intuit App Type](https://images.workoscdn.com/images/00ae363c-f1d5-4d9c-aa7f-30e8fce87d9f.png?auto=format&fit=clip&q=50) Choose a name for your application and click **Next** to continue. ![Naming the Intuit App](https://images.workoscdn.com/images/1c5f528e-c4dd-4712-9b29-25c1538bdb35.png?auto=format&fit=clip&q=50) You will be prompted to add permissions. Intuit will require you to add at least one of the listed **Authorization scopes**. This determines the full set of scopes your application is allowed to request. The WorkOS integration will only request the `openid`, `email`, and `profile` scopes as part of the authentication flow and will not actually request any of the API authorization scopes specified on this screen. Click **Done** after adding permissions to complete the initial app setup. ![Adding Intuit App Permissions](https://images.workoscdn.com/images/979d4135-0ad0-4566-a12c-5ab6cf8f59ed.png?auto=format&fit=clip&q=50) --- ## (3) Get production keys for your Intuit OAuth application Your app will be created as a sandbox application with development keys only. You will need production keys for your application to configure the WorkOS integration. In the left navigation menu, select the **App Overview** tab and click on the **Get production keys** tile. ![Get Production Keys for Intuit App](https://images.workoscdn.com/images/20cca6ff-9b02-4bc5-82cc-04489cb50e5c.png?auto=format&fit=clip&q=50) Complete the **App details** and **Compliance** questionnaires. ![Intuit App Details and Compliance](https://images.workoscdn.com/images/e810c6f9-9f42-406a-bac3-ee1ca7f1056d.png?auto=format&fit=clip&q=50) After answering all required questions, you should be able to view your production **Client ID** and **Client Secret**. ![View Production Credentials for Intuit App](https://images.workoscdn.com/images/554ba353-3057-47c3-b737-1cf575a9d8af.png?auto=format&fit=clip&q=50) ## (4) Configure the Redirect URI for your Intuit OAuth application In the left navigation menu, select the **Settings** tab. On the Settings page, click on the **Redirect URIs** tab. Make sure you're editing your **Production** application, and click **Add URI**. ![Configure Redirect URI for Intuit App - 1](https://images.workoscdn.com/images/89737850-57ab-4ae6-9cb5-faebcb150087.png?auto=format&fit=clip&q=50) Enter the **Redirect URI** from the Intuit OAuth configuration in the WorkOS Dashboard. Click **Save**. ![Configure Redirect URI for Intuit App - 2](https://images.workoscdn.com/images/aaebcd22-7461-4849-9783-9cbf32064dcb.png?auto=format&fit=clip&q=50) ## (5) Configure Intuit credentials in WorkOS Now that you have the **Intuit Client ID** and **Intuit Client Secret** from a previous step, return to the [WorkOS Dashboard](https://dashboard.workos.com). In the **Intuit OAuth** configuration dialog, enable the integration. Paste the credentials from Intuit into their respective fields in the WorkOS Dashboard. ![Entering Intuit Credentials in WorkOS Dashboard](https://images.workoscdn.com/images/ed72d331-478a-477c-ab2b-9da4cf31800d.png?auto=format&fit=clip&q=50) Click **Save changes** to complete the configuration. You are now ready to start authenticating with Intuit OAuth. If you are using AuthKit's [Hosted UI](/authkit/hosted-ui), a Continue with Intuit button will be added to your login page. If you are building your own authentication flows outside of AuthKit's hosted UI, you can use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/authkit/authentication/get-authorization-url) to support global Intuit OAuth for any domain. The `provider` query parameter should be set to `IntuitOAuth`. --- ## Frequently asked questions ### How is the WorkOS Intuit OAuth integration different from implementing regular Intuit OAuth flow? It's the same Intuit OAuth flow as you could build yourself, but it's encapsulated within WorkOS SSO. This means you don't need to build it yourself. In addition to Intuit OAuth, you can use WorkOS SSO to support other identity providers, all with a single integration. ### What is the provider query parameter and how is it used in the Intuit OAuth integration? If you are building your own authentication flows outside of AuthKit's hosted UI, you can use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/authkit/authentication/get-authorization-url) to support global Intuit OAuth for any domain. The `provider` query parameter should be set to `IntuitOAuth`. ### What scopes are required for Intuit OAuth? The **openid**, **profile**, and **email** scopes are required to allow the application to read user profile information necessary for authentication. These scopes provide access to the user's basic profile data and email address. ### HiBob Learn about syncing your user list with HiBob. ## Introduction This guide outlines how to synchronize your application's HiBob directories. To synchronize an organization's users and groups provisioned for your application, you'll need the enterprise IT contacts to provide you: - A HiBob Service User ID. - The HiBob Service User's Token. We will provide instructions below on the process in HiBob to create a Service User and collect those parameters. > Note: The HiBob integration isn't enabled by default in the WorkOS Dashboard or Admin Portal. Please reach out to [support@workos.com](mailto:support@workos.com) or via your team's WorkOS Slack channel if you would like HiBob enabled. --- ## (1) Set up your Directory Login to your WorkOS dashboard and select "Organizations" from the left hand Navigation bar Select the Organization you'd like to enable a HiBob Directory Sync connection for. On the Organization's page click "Manually Configure Directory". ![A screenshot highlighting the "Manually Configure Directory" button in the Organization view of the WorkOS Dashboard.](https://images.workoscdn.com/images/66f8d2e8-6337-4e67-97cf-1fcf9ae0a8cb.png?auto=format&fit=clip&q=50) You'll be prompted to select "HiBob" from the "Directory Type Dropdown", as well as enter the name of the directory. Then click "Create Directory". ![A screenshot highlighting the "Create Directory" modal for creating a HiBob directory in the WorkOS Dashboard.](https://images.workoscdn.com/images/0b8c4bdb-e745-4285-a208-3463631766c0.png?auto=format&fit=clip&q=50) WorkOS will create a Directory Sync Connection where you will input a "Service User ID" and an "API Token". The next step will walk you through how an organization's IT contact can generate and gather these details. ![A screenshot highlighting the "Update Directory" button in a HiBob directory in the WorkOS Dashboard.](https://images.workoscdn.com/images/f47caea6-5218-4957-b8a1-3c3512ec52f0.png?auto=format&fit=clip&q=50) --- ## (2) Create a Service User in HiBob HiBob uses a system called Service Users to utilize API actions. These steps walkthrough creating a Service User and obtaining the credentials needed by WorkOS to link with HiBob successfully. Login to HiBob and navigate to "Settings" and then selecting the "Integrations" tab. There will be a tile called Service Users, click on that. ![A screenshot highlighting the "Integrations" tab in the HiBob dashboard.](https://images.workoscdn.com/images/e240994a-4968-40ce-a75b-e3951ce0ac81.png?auto=format&fit=clip&q=50) Press on the New Service user Button The user will be prompted to enter a name (and display name, these can be the same) for the new service user, we recommend something like "WorkOS SCIM User". ![A screenshot showing the "Create a new Service User" modal in the HiBob dashboard.](https://images.workoscdn.com/images/03b23b02-f8d2-4b33-b7f3-02db9dfaee15.png?auto=format&fit=clip&q=50) HiBob will then present you with an ID and a Token, which will be populated into WorkOS, so make sure to inform the customer to provide these. ![A screenshot highlighting the "ID" and "Token" fields for a Service User in the HiBob dashboard.](https://images.workoscdn.com/images/81d6408a-0f04-4486-8864-cf9c08928d86.png?auto=format&fit=clip&q=50&w=2048) > **Important:** Service users have no permissions by default. Enterprise IT contacts must create a permission group and assign specific permissions to the service user. To set up permissions for the service user: 1. In HiBob, create a permission group for the service user (see [HiBob's guide on creating permission groups](https://apidocs.hibob.com/docs/api-service-users#step-2-creating-a-permission-group)) 2. Under the **People's data** tab in the permission group, enable the following permissions: - **View all employees' Root sections** (required for basic employee data: id, email, first name, last name) - **View all employees' Work sections** (required for title, department, site, start date, manager information) - **View all employees' About sections** (standard employee information) - **View all employees' Employment sections** (employment details) 3. Under **Access Rights**, set the permission group to **"Everyone"** to sync all active employees. To include inactive employees, use "Select by condition" and remove the "Lifecycle status equals Employed" filter 4. Assign the service user to this permission group For more details on setting permissions, see [HiBob's permission documentation](https://apidocs.hibob.com/docs/api-service-users#step-3-set-permissions). --- ## (3) Input the HiBob Service User details in WorkOS Back in the connection that was created in your WorkOS dashboard, enter these two fields and press "Save Directory Details." ![A screenshot highlighting the Directory Details modal of a HiBob directory in the WorkOS Dashboard.](https://images.workoscdn.com/images/8bd8dd85-864f-4712-98ac-788821b3b705.png?auto=format&fit=clip&q=50) You should see the connection now displays "Linked" in green. --- ## (4) View users and groups in your dashboard You will now see updates to the users in the directory under the "Users" tab in the HiBob Directory Sync page in WorkOS. ![A screenshot showing the "Users" view of a HiBob directory in the WorkOS Dashboard.](https://images.workoscdn.com/images/8474708e-dd99-472e-aba4-337c8463551d.png?auto=format&fit=clip&q=50) --- ## Frequently asked questions ### What if the directory user profiles from HiBob aren't showing all of the expected user attributes, such as the user address? If some user attributes are not being sent along in the profile, you'll want to start by checking the permissions of the Service User you created in step 2. You can see more about accessing Service User permissions [here](https://apidocs.hibob.com/docs/api-service-users) and some relevant FAQs from HiBob [here](https://help.hibob.com/hc/en-us/articles/4409776408209#how-to-review-permission-group-changes-0-4). ### How often do HiBob directories perform a sync? HiBob directories poll every 30 minutes starting from the time of the initial sync. ### Google SAML Learn how to configure a connection to Google Workspace via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [connection](/glossary/connection). Often, the information required to create a connection will differ by Identity Provider. To create a Google SAML connection, you'll need three pieces of information: an [ACS URL](/glossary/acs-url), a [SP Entity ID](/glossary/sp-entity-id), and an [IdP Metadata URL](/glossary/idp-metadata). Start by logging into your [WorkOS Dashboard](https://dashboard.workos.com/) and selecting "Organizations" from the left hand navigation bar. Click on the organization you'd like to configure a Google SAML connection for and select "Manually Configure Connection". ![A screenshot showing where to find "Manually Configure Connection" for an Organization in the WorkOS Dashboard.](https://images.workoscdn.com/images/26e7f2ca-7d61-4f02-9a67-f3bfbc254ba3.png?auto=format&fit=clip&q=50) Select "Google Workspace SAML" from the Identity Provider dropdown, enter a descriptive name for the connection, and then select the "Create Connection" button. ![A screenshot showing how to create a connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/7f2f8f2b-22d1-443c-a692-5eb7fa506042.png?auto=format&fit=clip&q=50) --- ## What WorkOS provides WorkOS provides the ACS URL and the SP Entity ID. It's readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot showing where to find the ACS URL and SP Entity ID in the WorkOS Dashboard.](https://images.workoscdn.com/images/1d07cb61-b23a-4894-ab9b-fd97d5bc6d6b.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. In Google's case, it needs to be set by the organization when configuring your application in their Google admin dashboard. The SP Entity ID is a URI used to identify the issuer of a SAML request, response, or assertion. In this case, the entity ID is used to communicate that WorkOS will be the party performing SAML requests to the organization's Google instance. Specifically, the ACS URL will need to be set as the "ACS URL" and the SP Entity ID will need to be set as the "Entity ID" in the "Service Provider Details" step of the Google SAML setup. --- ## What you'll need In order to integrate you'll need the metadata XML file from Google. Normally, this information will come from the organization's IT Management team when they set up your application's SAML 2.0 configuration in their Google admin dashboard. But, should that not be the case during your setup, here's how to obtain it. --- ## (1) Log in Log in to the Google Admin dashboard, select "Apps" from the sidebar menu, and then select "Web and Mobile Apps" from the following list. If your application is already created, select it from the list of applications and move to Step 7. If you haven't created a SAML application, select "Add App" and then "Add custom SAML app". ![A screenshot showing where to find "Add custom SAML app" in the Google Dashboard.](https://images.workoscdn.com/images/1a0abd99-4e2c-403f-89b9-a3fd11d6fb9a.png?auto=format&fit=clip&q=50) --- ## (2) Enter Your App's Information Give the app a descriptive name and upload an icon, if applicable. Click "Continue". ![A screenshot showing where to add app name in the Google Dashboard.](https://images.workoscdn.com/images/89ae0c9e-becf-4076-8178-7d4535eac778.png?auto=format&fit=clip&q=50) --- ## (3) Obtain Identity Provider Details Select the "Download Metadata" button to download the metadata file. Save this file, as you'll upload it to the WorkOS Dashboard in Step 7. Click "Continue". ![A screenshot showing where to find "Download Metadata" in the Google Dashboard.](https://images.workoscdn.com/images/92b16c09-8b06-4b8b-b4a0-2f441fd3d878.png?auto=format&fit=clip&q=50) --- ## (4) Enter Service Provider Details Copy and the "ACS URL" from your WorkOS Dashboard and paste it into the "ACS URL" field, and copy the "SP Entity ID" from your WorkOS Dashboard and paste it into the "Entity ID" field in the Google SAML "Service provider details" modal. Select "Continue." ![A screenshot showing where to enter "Entity ID" and "ACS URL" in the Google Dashboard.](https://images.workoscdn.com/images/946113dc-812e-446d-b466-32eec2b27629.png?auto=format&fit=clip&q=50) --- ## (5) Configure Attribute Mapping Provide the following Attribute Mappings and select "Finish". Google SAML does not provide the option to map a user's id attribute claim. ![A screenshot showing completed Attribute Mappings in the Google Dashboard.](https://images.workoscdn.com/images/dcf0968a-346c-4a58-bd76-8e0a87d92d66.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, follow the guidance below. Scroll down to the "Group membership" section. Add any groups you'd like to send under "Google groups", and set the "App attribute" to "groups". Then, select "Finish". ![A screenshot showing how to add a group attribute in the Google dashboard.](https://images.workoscdn.com/images/b7a6e5f7-aaf1-4756-9fc9-04f70f1c8a67.png?auto=format&fit=clip&q=50) > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (6) Configure User Access In the created SAML app's landing page, select the "User Access Section". ![A screenshot showing where to find the "User Access Section" in the Google Dashboard.](https://images.workoscdn.com/images/57080072-5a42-4463-897b-2382c643082a.png?auto=format&fit=clip&q=50) Turn this service ON for the correct organizational units in your Google Directory setup. Save any changes. Google may take up to 24 hours to propagate these changes. The connection in WorkOS will be inactive until then. --- ## (7) Upload Metadata File If you haven't already downloaded the metadata file, select your SAML application, and click "Download Metadata". In the modal, again click "Download Metadata". ![A screenshot showing where to find "Download Metadata" in the Google Dashboard.](https://images.workoscdn.com/images/7e1a8f1f-fb44-435d-961a-d71eff48d207.png?auto=format&fit=clip&q=50) In the connection Settings of the WorkOS Dashboard, click "Edit Metadata Configuration". ![A screenshot showing the "Edit Metadata Configuration" button in the WorkOS Dashboard.](https://images.workoscdn.com/images/afe34aca-df4f-4005-b71e-bf528916a491.png?auto=format&fit=clip&q=50) In the modal, upload the Google Metadata file and then select "Save Metadata Configuration". Once the file is uploaded into WorkOS, your connection will then be linked and good to go! ![A screenshot showing a linked Google SAML connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/9c497a05-f823-4c51-ab54-e5b6feed53fa.png?auto=format&fit=clip&q=50) --- ## Frequently asked questions ### Where is the Relay State in Google SAML? Within the Google SAML setup, there will be a field called "Start URL" which is referred to as the Relay State. ### Google OIDC Learn how to configure a connection to Google via OIDC. ## Introduction Each SSO identity provider requires specific information to create and configure a new [SSO connection](/glossary/connection). Often, the information required to create an SSO connection will differ by identity provider. To create a Google OIDC SSO connection, you'll need three pieces of information: a [redirect URI](/glossary/redirect-uri), [client ID](/glossary/client-id), and [client secret](/glossary/client-secret). Start by logging in to your WorkOS dashboard and navigate to the **Organizations** page from the left-hand navigation bar. Select the organization you'd like to configure a Google OIDC SSO connection for, and select **Configure manually** under **Single Sign-On**. ![WorkOS Dashboard Organizations tab with "Configure manually" button highlighted](https://images.workoscdn.com/images/d577cfbe-028b-48cf-8cc0-4cd5d3adf853.png?auto=format&fit=clip&q=50) Select **Google OIDC** from the identity provider dropdown, click **Create Connection**. ![Create Connection form with Google OIDC selected as Identity Provider](https://images.workoscdn.com/images/35cfe8ab-1825-4f0d-ab93-7c0eb6e0d742.png?auto=format&fit=clip&q=50) > Google OIDC is not available when [SSO group role assignment](/sso/identity-provider-role-assignment) is enabled due to [a limitation](https://issuetracker.google.com/issues/133774835?pli=1) with the groups claim. --- ## What WorkOS provides WorkOS provides the Redirect URI, which can be found in the **Service Provider Details** section on the SSO connection page in the [WorkOS Dashboard](https://dashboard.workos.com/). - [Redirect URI](/glossary/redirect-uri): The endpoint where identity providers send authentication responses after successful login ![The Redirect URI of a OIDC connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/99a7c7d5-50a9-4bff-a3f3-22dc1cfeca58.png?auto=format&fit=clip&q=50) The Redirect URI is the location an identity provider redirects its authentication response to. In Google's case, it needs to be set as an **Authorized redirect URI** when configuring your OAuth client in the Google Cloud Console. Specifically, the Redirect URI will need to be added to the **Authorized redirect URIs** section when creating your OAuth client, which is outlined in [step 3](/integrations/google-oidc/3-create-oauth-client) below. --- ## What you'll need You will need to obtain two pieces of information from the organization: - [Client ID](/glossary/client-id): Application identifier from the OIDC provider - [Client secret](/glossary/client-secret): Authentication secret for the application Normally, this information will come from the organization's IT management team when they set up your application's OAuth configuration in their Google Cloud Console. But, should that not be the case during your setup, the next steps will show you how to obtain it. --- ## (1) Create a Google Cloud project (optional) > If you already have a Google Cloud project, skip this step. Sign in to the [Google Cloud Console](https://console.cloud.google.com). From the top left navigation, click **Select a project**. Select an organization and then click **Create project**. ![Google Cloud Console project selector with "Create project" option](https://images.workoscdn.com/images/941eaf2f-b6a3-4c86-83aa-4cb005dbc1e4.png?auto=format&fit=clip&q=50) Enter a project name. Update the project organization and location if needed. Click **Create**. ![Google Cloud project creation form with project name, organization, and location fields](https://images.workoscdn.com/images/b7cd689d-0e89-4eee-8f32-f6b93522fed1.png?auto=format&fit=clip&q=50) --- ## (2) Configure OAuth app From the top left navigation, click **Select a project**. Select the project you created in the previous step or one that is already set up. ![Google Cloud Console project selector dropdown with available projects](https://images.workoscdn.com/images/675794e5-9a6d-42cc-8d68-46e58a29caab.png?auto=format&fit=clip&q=50) Search for **Google Auth Platform** and select it from the results list. ![Google Cloud Console search results showing Google Auth Platform service](https://images.workoscdn.com/images/ef574ce6-3402-4dbe-9e3e-4d3d00d82212.png?auto=format&fit=clip&q=50) Click **Get started**. ![Google Cloud OAuth App dashboard with highlighted get started button](https://images.workoscdn.com/images/2e35fd83-74db-45b4-ad13-510fb52b57b0.png?auto=format&fit=clip&q=50) On the **App Information** step, enter an app name, such as your organization name. Select a user support email from the dropdown. Click **Next**. ![OAuth consent screen App Information step with app name and user support email fields](https://images.workoscdn.com/images/2365ee0a-497b-4235-9d08-e9e740a140f0.png?auto=format&fit=clip&q=50) On the **Audience** step, select **Internal** and click **Next**. ![OAuth consent screen Audience step with Internal option selected](https://images.workoscdn.com/images/e3689b48-4ada-43a6-818f-244cfebf0393.png?auto=format&fit=clip&q=50) On the **Contact Information** step, enter a contact email and click **Next**. ![OAuth app information screen with contact information field highlighted and demo@foo-corp.com email filled in, next button is highlighted](https://images.workoscdn.com/images/7ef6519e-dc76-473b-901f-388e69762433.png?auto=format&fit=clip&q=50) Agree to the terms of service, click **Continue** and then **Create**. ![OAuth consent screen terms of service acceptance and Create button](https://images.workoscdn.com/images/e211e959-1325-4dfc-8a8c-96d4ee0030cf.png?auto=format&fit=clip&q=50) --- ## (3) Create OAuth client From the left-hand sidebar navigation, click **Clients** and then click **Create client**. ![Google Auth Platform Clients page with "Create client" button](https://images.workoscdn.com/images/24e008c1-4a8e-4bfe-8603-1074453a815b.png?auto=format&fit=clip&q=50) From the **Application type** dropdown, select **Web application**. ![OAuth client creation form with Web application selected as application type](https://images.workoscdn.com/images/17bc8607-23be-457f-9cf1-995730748d55.png?auto=format&fit=clip&q=50) Under the **Authorized redirect URIs** section, click **Add URI**. Copy the Redirect URI from your WorkOS Dashboard and paste it into the new redirect URI field. ![Authorized redirect URIs section with Add URI button and WorkOS redirect URI field](https://images.workoscdn.com/images/b98e091f-9005-4a1f-bfb9-56eb26a88844.png?auto=format&fit=clip&q=50) Click **Create**. --- ## (4) Add organization settings From the **OAuth client created** modal, copy the **Client ID** and **Client Secret** values. ![OAuth client created modal displaying Client ID and client secret](https://images.workoscdn.com/images/51a44c08-a559-456b-926f-33334d7cb755.png?auto=format&fit=clip&q=50) Back in the WorkOS Dashboard, enter the client ID, and client secret you obtained from Google into the respective fields in the **Identity Provider Configuration** section of the SSO connection. Enter `https://accounts.google.com/.well-known/openid-configuration` in the **Discovery Endpoint** field, this is the same value for all Google Cloud Console projects. ![WorkOS Dashboard Identity Provider Configuration with Client ID, Client Secret, and Discovery Endpoint fields](https://images.workoscdn.com/images/d3305808-a772-4f2a-a7e1-c862b9274975.png?auto=format&fit=clip&q=50) Click **Save Configuration**. --- ## Next steps Your Google OIDC connection is now configured and ready to use. Users within your organization will be able to authenticate through WorkOS using their Google credentials. To start using this connection in your application, refer to the [SSO guide](/sso) for implementation details. ### Google OAuth Learn how to set up OAuth with Google Workspace ## Introduction The Google OAuth integration allows your users to authenticate using their Google Workspace credentials. The configuration process involves obtaining client credentials from your Google Cloud Platform Console and configuring them in the WorkOS Dashboard. --- ## Testing with default credentials in the staging environment WorkOS provides a default Google Client ID and Client Secret combination, which allows you to quickly enable and test Google OAuth. Use the [WorkOS API to initiate SSO](/sso/1-add-sso-to-your-app/add-an-endpoint-to-initiate-sso), setting the `provider` parameter to `GoogleOAuth`, and WorkOS will automatically use the default credentials until you add your own Google Client ID and Client Secret to the configuration in the WorkOS Dashboard. > The default credentials are only intended for testing and therefore only available in the Staging environment. For your production environment, please follow the steps below to create and specify your own Google Client ID and Client Secret. Please note that when you are using WorkOS default credentials, Google's authentication flow will display WorkOS' name, logo, and other information to users. Once you register your own application and use its Google Client ID and Client Secret for the OAuth flow, you will have the opportunity to customize the app, including its name, logo, contact email, etc. --- ## What WorkOS provides When setting up Google OAuth, WorkOS provides one key piece of information that needs to be configured in your Google Cloud Platform project: - [Redirect URI](/glossary/redirect-uri): The endpoint where Google will send authentication responses after successful login The Redirect URI is available in the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select the **Authentication** tab and the **OAuth providers** sub-tab. Locate the **Google** section. ![Open the Google configuration dialog](https://images.workoscdn.com/images/1e400f3e-1885-481f-8840-4a3a9f8c7f97.png?auto=format&fit=clip&q=50) Click **Manage**. The **Google OAuth** configuration dialog will open. Locate the **Redirect URI**. ![Google OAuth Redirect URI in the WorkOS Dashboard.](https://images.workoscdn.com/images/020273f1-d216-4aca-8ddd-8963accd7517.png?auto=format&fit=clip&q=50) The **Redirect URI** serves as the destination for authentication responses and must be configured in your Google Cloud Platform project as an authorized redirect URI. --- ## What you'll need You will need to obtain two pieces of information from a Google Cloud Platform project: - **Google Client ID**: Application identifier from Google Cloud Platform - **Google Client Secret**: Authentication secret for the application The following sections will guide you through generating these credentials in your Google Cloud Platform Console. --- ## (1) Access Google Cloud Platform Console Sign in to the [Google Cloud Platform Console Dashboard](https://console.cloud.google.com/) and select your application's project from the project selection dropdown menu in the navigation bar. ![How to select your application in the Google Cloud Platform Console Dashboard.](https://images.workoscdn.com/images/45adf7cf-78e0-4c5a-a6c1-7b3eee62c723.png?auto=format&fit=clip&q=50) --- ## (2) Configure OAuth consent screen In the left navigation menu, select **APIs & Services** and then **OAuth Consent Screen**. ![Where to find the OAuth Consent Screen option in the Google Cloud Platform Console Dashboard.](https://images.workoscdn.com/images/c37375e2-6ef2-41ba-9b65-a125501bfd5a.png?auto=format&fit=clip&q=50) Now within the **Google Auth Platform**, in the left navigation menu, select **Clients**. Click **Create client**. ![How to create a new client in the Google Cloud Platform Console Dashboard.](https://images.workoscdn.com/images/c5ffe36c-e471-4b27-a6b9-936d26837e93.png?auto=format&fit=clip&q=50) In the **Application type** dropdown, select **Web application**. Provide an appropriate name for your OAuth client ID. > As a best practice, your OAuth client ID's name should be different from your application's name. It will not be shown to end users. Under the **Authorized redirect URIs** section, click **Add URI**. Add the **Redirect URI** from the WorkOS Dashboard. ![Where to enter your WorkOS Redirect URI in the Google Cloud Platform Console Dashboard.](https://images.workoscdn.com/images/e18673f7-e490-46a7-ad0c-f71d5ddcb08a.png?auto=format&fit=clip&q=50) Scroll down and click **Create**. It may take up to 5 minutes, but once your OAuth client is created, you'll be presented with your application's client ID and client secret. Be sure to copy these values as they may not be available after closing the dialog. ![The client ID and client secret in the Google Cloud Platform Console Dashboard.](https://images.workoscdn.com/images/13a05048-c45c-43c5-9d56-39faf53ab479.png?auto=format&fit=clip&q=50) --- ## (3) Configure Google credentials in WorkOS Now that you have the **Google Client ID** and **Google Client Secret** from the previous step return to the [WorkOS Dashboard](https://dashboard.workos.com). In the **Google OAuth** configuration dialog, select **Your app's credentials**. Paste the credentials from Google into their respective fields in the WorkOS Dashboard. ![Where to enter the Google Client ID and Google Client Secret in the WorkOS Dashboard.](https://images.workoscdn.com/images/6c209570-926d-49bf-9189-0e2f705e70ee.png?auto=format&fit=clip&q=50) Click **Save** to complete the configuration. --- ## (4) Publish the Google OAuth application In the left navigation menu of the Google Cloud Platform Console, select the **Audience** tab. If your application is not **In production**, click **Publish app**. In the **Push to Production?** dialog that opens, click **Confirm**. If your application is still in testing mode, users will likely get an "Access Blocked" error when attempting to log into your app. ![The publishing status of your Google OAuth application](https://images.workoscdn.com/images/564bc12f-0abb-4866-8a48-eb9451b851fb.png?auto=format&fit=clip&q=50) After that, you're now able to authenticate users with Google OAuth. You will use the `provider` query parameter in the Get Authorization URL API endpoint to support global Google OAuth for any domain. The `provider` query parameter should be set to `GoogleOAuth`. --- ## Customize Google OAuth Domain (Optional) This optional process requires access to your Google Cloud Console and your domain's DNS settings. After implementing the steps above, you'll notice that the Google OAuth sign in form displays "Choose an account to continue to workos.com". This is based on the Authorized Redirect URI in Google. To set this to a domain other than workos.com, Google will ask for proof of ownership of your domain. To help guide you through this process we have a self-service flow. ### (1) Add your custom Google OAuth domain In the **Authentication** tab of the WorkOS Dashboard, find the **Google OAuth** section. Depending on which WorkOS products have been enabled, the **Google OAuth** section may be under the **Methods** or **OAuth providers** sub-tabs in the left navigation menu. Click **Setup Custom Domain**. > Note: This button will only appear if your environment has a valid Google OAuth configuration and a custom domain has not already been configured. ![Where to find the Set Up Custom Domain button in the WorkOS Dashboard.](https://images.workoscdn.com/images/9ba10d03-c0af-41e6-b090-884ba1cddca4.png?auto=format&fit=clip&q=50) Under **Add Custom Domain**, input the domain that you wish to use in place of `auth.workos.com`. This is often a subdomain such as `auth.example.com`. Click on **Set Domain**. ![Where to add a custom domain in the WorkOS Dashboard.](https://images.workoscdn.com/images/d233701c-74c5-4a42-a063-9eaa680dc7c9.png?auto=format&fit=clip&q=50) ### (2) Add CNAME target Add a new CNAME target inside your domain's DNS settings. Set the host to match the domain you set in the previous step and set the value to `cname.workosdns.com`. Once the above is complete, click **Verify DNS**. This verification often takes less than a minute, but is dependent on how long your DNS record takes to propagate. The page will continue polling to check the status of your verification until it is successful. ![The CNAME target of cname.workosdns.com in the WorkOS Dashboard.](https://images.workoscdn.com/images/feebf1a1-1f42-4c0b-b1fc-67d37745b948.png?auto=format&fit=clip&q=50) ### (3) Add new redirect URI to Google Once the DNS has been successfully verified, WorkOS will provide a URI starting with your subdomain in the **Add redirect URI to Google** section. Click on the clipboard icon to copy the URL. ![The clipboard icon in the WorkOS Dashboard.](https://images.workoscdn.com/images/95060659-da91-40d8-849b-9718ef7b00fc.png?auto=format&fit=clip&q=50) In the Google Cloud Platform Console, under your project's **APIs & Services** → **Clients** section, add the URL copied above in the **Authorized redirect URIs** section. To ensure your Google OAuth integration continues to work without any gaps in service, leave your existing redirect URI in place for now. ![Where to enter the redirect URI in the Google Cloud Platform Console.](https://images.workoscdn.com/images/548b4e3e-164e-4358-ab1d-58c5d3071731.png?auto=format&fit=clip&q=50) ### (4) Test Google redirect URI Once the URL has been added and saved on the Google side, navigate back to the WorkOS Dashboard and click on **Test Google Redirect URI**. ![The Test Google Redirect URI button in the WorkOS Dashboard.](https://images.workoscdn.com/images/1e191eb9-a316-407e-ae63-69be88ac3665.png?auto=format&fit=clip&q=50) If the test is successful, you will see a **Successfully tested** message displayed. Click **Save custom Google OAuth settings**. Once these updates have been saved, test out your Google OAuth sign in flow to ensure everything is working properly and your domain is displayed on the form. If everything is looking good, it is safe to remove the old `auth.workos.com` URL from your Google Authorized redirect URIs, and `workos.com` from your Google Authorized domains. --- ## Configure Additional OAuth Scopes (Optional) WorkOS will request the OAuth scopes that are required for authentication by default. You can optionally configure your integration to request additional OAuth scopes as needed. When the **Return Google OAuth tokens** option is selected, the access token and refresh token from Google will be included in the response from the [Authenticate with code API](/reference/authkit/authentication/code). ![A screenshot showing Google OAuth scopes configuration in the WorkOS Dashboard](https://images.workoscdn.com/images/53f64aa3-fbd1-4371-9fba-2e2ff9eb0823.png?auto=format&fit=clip&q=50) Any scopes configured here will be included on every Google OAuth request. To specify additional scopes dynamically, use the `provider_scopes` query parameter on the [Get Authorization URL API endpoint](/reference/authkit/authentication/get-authorization-url). Any additional scopes that you plan to request must also be configured on your OAuth consent screen in the Google Cloud Platform Console. Google considers some scopes to be sensitive or restricted. If requesting any of these sensitive or restricted scopes, your application will need to be verified by Google. For more information, see Google's OAuth scopes [documentation](https://developers.google.com/identity/protocols/oauth2/scopes). ![A screenshot showing Google OAuth scopes configuration in the Google Cloud Console](https://images.workoscdn.com/images/c9f2cc5d-ca3c-466f-9db8-9138ad60cc43.png?auto=format&fit=clip&q=50) > IMPORTANT: Your users will see an "unverified app" screen from Google and may see errors during sign-in if the scopes included on an authorization request differ from the scopes configured on your OAuth consent screen, or if you request sensitive or restricted scopes without going through Google's app verification process. Changes to scopes should be tested in a staging environment before applying them to production. --- ## Frequently asked questions ### How is the WorkOS Google OAuth integration different from implementing regular Google OAuth flow? It's the same Google OAuth flow as you could build yourself, but it's encapsulated within WorkOS SSO. This means you don't need to build it yourself. In addition to Google OAuth, you can use WorkOS SSO to support other identity providers, all with a single integration. ### What is the provider query parameter and how is it used in the Google OAuth integration? You can use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/sso/get-authorization-url) to support global Google OAuth for any domain. The `provider` query parameter should be set to `GoogleOAuth`. ### Google Directory Sync Learn about syncing your user list with Google Workspace. ## Introduction This guide outlines how to synchronize your application's Google Workspace directories. --- ## (1) Select environment Login to your WorkOS dashboard and ensure you have the desired environment selected. ![Select the desired WorkOS environment from the navigation.](https://images.workoscdn.com/images/8f30c9d7-8569-4cb2-8fbe-1d8fc46be717.png?auto=format&fit=clip&q=50) ## (2) Send an admin invite link Select "Organizations" in the navigation. Select the organization that'd like to enable a Google Directory Sync connection. On the Organization page, under "Invite an admin to set up this organization," select "Invite Admin." ![Select "Invite Admin" from the organization page.](https://images.workoscdn.com/images/f879b479-24e6-4c86-acb8-8abb05f2a2ff.png?auto=format&fit=clip&q=50) Select "Directory Sync" and any other features you'd like the organization to be able to onboard. ![Select "Directory Sync" and any other features you'd like the organization to be able to onboard.](https://images.workoscdn.com/images/2ff61c68-3709-4b35-ac0d-f2b5b6333d9b.png?auto=format&fit=clip&q=50) Enter the email addresses of the IT contacts, or copy the setup link and send it to the IT contacts. ![Enter the email addresses of the IT contacts, or copy the setup link.](https://images.workoscdn.com/images/a3414089-79a1-4137-8687-3e803a6f364a.png?auto=format&fit=clip&q=50) --- ## (3) Authenticate with admin credentials Have the organization choose Google as a provider and follow the Google prompts to authenticate with admin credentials. ![A screenshot showing the requested permissions in the Google modal.](https://images.workoscdn.com/images/1809508c-e153-47f7-a9b7-5b243ff95c7c.png?auto=format&fit=clip&q=50) --- ## (4) Select which groups to sync to Your Application The IT contacts can then select to filter which groups and memberships are synced to the directory. If groups are being filtered, then only users with a membership within one of the synced groups will be synced. ![A screenshot showing the setup screen with how to filter groups to sync.](https://images.workoscdn.com/images/43942f32-e228-4745-89a6-fa6ff3e6f4dc.png?auto=format&fit=clip&q=50) --- ## (5) Sync users and groups to Your Application Changes will appear live in the Directory Sync portal under the "Users" tab: ![A screenshot showing users in the "Users" tab of the WorkOS Dashboard.](https://images.workoscdn.com/images/268ff490-71bd-4aa4-9f7d-c01f3548b198.png?auto=format&fit=clip&q=50) A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) ## Frequently asked questions ### Can you selectively sync users and groups from Google Workspace? Yes, you can select to sync certain groups during setup within the Admin Portal as seen in [Step 4](/integrations/google-directory-sync/4-select-which-groups-to-sync-to-your-application). ### When do users get removed from a directory? There are 2 ways a user can be deleted from a Google Workspace directory. 1. The user is removed or archived on Google and no longer returned by their API. 2. When the directory is [filtering specific groups](/integrations/google-directory-sync/4-select-which-groups-to-sync-to-your-application), if a user is removed from all groups that are being filtered in, the user is removed from the directory as well. ### How often do Google Workspace directories perform a sync? Google Workspace directories are synced approximately every 30 minutes starting from the time of the initial sync ### Does Google Directory Sync support nested groups? Yes, nested groups (groups within groups) are supported in Google Directory Sync. This feature is currently available in a restricted preview. Contact [WorkOS support](mailto:support@workos.com) for additional details. ### What is the `idp_id` for directory groups from Google Workspace? Google Workspace provides a unique identifier for each group, which is persisted as the `idp_id` for [directory groups](/reference/directory-sync/directory-group) in WorkOS. ### GitLab OAuth Learn how to set up OAuth with GitLab ## Introduction The GitLab OAuth integration allows your users to authenticate using their GitLab credentials. The configuration process involves creating an OAuth application in GitLab and configuring the client credentials in your WorkOS Dashboard. --- ## What WorkOS provides When setting up GitLab OAuth, WorkOS provides one key piece of information that needs to be configured in your GitLab OAuth application: - [Redirect URI](/glossary/redirect-uri): The endpoint where GitLab will send authentication responses after successful login The Redirect URI is available in the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select the **Authentication** tab and the **OAuth providers** sub-tab. Locate the **GitLab** section. ![The GitLab OAuth section in the WorkOS Dashboard](https://images.workoscdn.com/images/37e84a18-3d18-4fc9-a122-63589ab4ddf0.png?auto=format&fit=clip&q=50) Click **Enable**. The **GitLab OAuth** configuration dialog will open. Locate the **Redirect URI**. ![The GitLab OAuth configuration modal in the WorkOS Dashboard](https://images.workoscdn.com/images/3ec9c4c3-1fc1-4ef6-a2fb-eeca07701d33.png?auto=format&fit=clip&q=50) The **Redirect URI** serves as the destination for authentication responses and must be configured in your GitLab OAuth application as the redirect URI. --- ## What you'll need You will need to obtain two pieces of information from a GitLab OAuth application: - **GitLab Client ID**: Application identifier from GitLab (called Application ID in GitLab) - **GitLab Client Secret**: Authentication secret for the application (called Secret in GitLab) The following sections will guide you through creating an OAuth application in your GitLab account and generating these credentials. --- ## (1) Create the GitLab OAuth application Log in to your [GitLab account](https://gitlab.com) and navigate to your user settings. In the left navigation menu, select your avatar. Click **Edit profile**. Select **Applications**. Click **Add new application**. ![GitLab page to register a new OAuth application.](https://images.workoscdn.com/images/ad782ab8-74ad-4787-91fe-685e0f466509.png?auto=format&fit=clip&q=80) > You can also register a new application under a group, which may be more appropriate if it is maintained by a team of developers, or instance-wide if you have a dedicated GitLab instance. For more on this see the [GitLab docs](https://docs.gitlab.com/integration/oauth_provider/). --- ## (2) Configure the GitLab OAuth application Fill out the form with relevant details about your application, including the application name. For **Redirect URI**, enter the **Redirect URI** from the GitLab OAuth configuration in the WorkOS Dashboard. ![GitLab form to create a new OAuth application.](https://images.workoscdn.com/images/7c86fdf4-c635-46c5-977c-965b85a322fd.png?auto=format&fit=clip&q=80) The **Confidential** flag is enabled by default. It should be exclusively used by a trusted backend server that can securely store the client secret. For native-mobile, single-page, or other JavaScript applications, disable this flag. Select the **openid**, **profile**, and **email** scopes for this app to allow the application to read user profile information, then click **Save application**. --- ## (3) Generate client credentials On the next page, you will see the GitLab **Application ID** and **Secret** for your new OAuth application. ![OAuth client credentials in the GitLab application settings.](https://images.workoscdn.com/images/b7ce3a64-673a-476f-8a3c-cf63c76bf88e.png?auto=format&fit=clip&q=80) Note the **Application ID** and **Secret** values as you'll need them for the WorkOS configuration. --- ## (4) Configure GitLab credentials in WorkOS Now that you have the **GitLab Client ID** (Application ID) and **GitLab Client Secret** (Secret) from the previous step, return to the [WorkOS Dashboard](https://dashboard.workos.com). In the **GitLab OAuth** configuration dialog, enable the integration. Paste the credentials from GitLab into their respective fields in the WorkOS Dashboard. ![Where to enter GitLab client credentials in the WorkOS dashboard.](https://images.workoscdn.com/images/6e9b410d-33bf-485f-b1c4-6a16fbeaa946.png?auto=format&fit=clip&q=80) Click **Save** to complete the configuration. You are now ready to start authenticating with GitLab OAuth. You will use the `provider` query parameter in the Get Authorization URL API endpoint to support global GitLab OAuth for any domain. The `provider` query parameter should be set to `GitLabOAuth`. --- ## Configure Additional OAuth Scopes (Optional) WorkOS will request the OAuth scopes that are required for authentication by default. You can optionally configure your integration to request additional OAuth scopes as needed. When the **Return GitLab OAuth tokens** option is selected, the access token and refresh token from GitLab will be included in the response from the [Authenticate with code API](/reference/authkit/authentication/code). ![A screenshot showing GitLab OAuth scopes configuration in the WorkOS Dashboard](https://images.workoscdn.com/images/8d4803a8-f436-45cb-974e-eaa79522181e.png?auto=format&fit=clip&q=50) Any scopes configured here will be included on every GitLab OAuth request. To specify additional scopes dynamically, use the `provider_scopes` query parameter on the [Get Authorization URL API endpoint](/reference/authkit/authentication/get-authorization-url). Any additional scopes that you plan to request must also be configured on the Application settings page in GitLab. For more information, see GitLab's OAuth scopes [documentation](https://docs.gitlab.com/integration/oauth_provider). ![A screenshot showing GitLab OAuth scopes configuration in GitLab Application Settings](https://images.workoscdn.com/images/25d9971d-55b1-473b-9d7d-d8e42e893725.png?auto=format&fit=clip&q=50) > IMPORTANT: Your users will see an error during sign-in if the scopes included on an authorization request are not included in the scopes configured on the Application settings page in GitLab. Changes to scopes should be tested in a staging environment before applying them to production. --- ## Frequently asked questions ### How is the WorkOS GitLab OAuth integration different from implementing regular GitLab OAuth flow? It's the same GitLab OAuth flow as you could build yourself, but it's encapsulated within WorkOS SSO. This means you don't need to build it yourself. In addition to GitLab OAuth, you can use WorkOS SSO to support other identity providers, all with a single integration. ### What is the provider query parameter and how is it used in the GitLab OAuth integration? You can use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/sso/get-authorization-url) to support global GitLab OAuth for any domain. The `provider` query parameter should be set to `GitLabOAuth`. ### What scopes are required for GitLab OAuth? The **openid**, **profile**, and **email** scopes are required to allow the application to read user profile information necessary for authentication. This scope provides access to the user's basic profile data. ### Can I register the GitLab OAuth application under a group or organization? Yes, you can register a new application under a GitLab group, which may be more appropriate if it is maintained by a team of developers. You can also register it instance-wide if you have a dedicated GitLab instance. See the [GitLab documentation](https://docs.gitlab.com/integration/oauth_provider/) for more details. ### What is the difference between Confidential and non-Confidential applications in GitLab? The **Confidential** flag should be used for applications that can securely store the client secret, typically backend servers. For native mobile apps, single-page applications, or other JavaScript applications that cannot securely store secrets, you should disable this flag. ### GitHub OAuth Learn how to set up OAuth with GitHub ## Introduction The GitHub OAuth integration allows your users to authenticate using their GitHub credentials. WorkOS supports both **GitHub OAuth Apps** and **GitHub Apps** for authentication. The configuration process involves creating an OAuth application or GitHub App in GitHub and configuring the client credentials in the WorkOS Dashboard. --- ## Testing with default credentials in the staging environment WorkOS provides a default GitHub Client ID and Client Secret combination, which allows you to quickly enable and test GitHub OAuth. Use the [WorkOS API to initiate SSO](/sso/1-add-sso-to-your-app/add-an-endpoint-to-initiate-sso), setting the `provider` parameter to `GitHubOAuth`, and WorkOS will automatically use the default credentials until you add your own GitHub Client ID and Client Secret to the configuration in the WorkOS Dashboard. > The default credentials are only intended for testing and therefore only available in the Staging environment. For your production environment, please follow the steps below to create and specify your own GitHub Client ID and Client Secret. Please note that when you are using WorkOS default credentials, GitHub's authentication flow will display WorkOS' name, logo, and other information to users. Once you register your own application and use its GitHub Client ID and Client Secret for the OAuth flow, you will have the opportunity to customize the app, including its name, logo, contact email, etc. --- ## What WorkOS provides When setting up GitHub OAuth, WorkOS provides one key piece of information that needs to be configured in your GitHub OAuth application: - [Redirect URI](/glossary/redirect-uri): The endpoint where GitHub will send authentication responses after successful login The Redirect URI is available in the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select the **Authentication** tab and the **OAuth providers** sub-tab. Locate the **GitHub** section. ![Open the GitHub configuration dialog](https://images.workoscdn.com/images/b4ddb4d0-39f2-4e58-bc15-f3857f63415b.png?auto=format&fit=clip&q=50) Click **Manage**. The **GitHub OAuth** configuration dialog will open. Locate the **Redirect URI**. ![GitHub OAuth Redirect URI in the WorkOS Dashboard](https://images.workoscdn.com/images/18629339-63d6-4b60-b5d5-7e75f7745de5.png?auto=format&fit=clip&q=50) The **Redirect URI** serves as the destination for authentication responses and must be configured in your GitHub OAuth application as the authorization callback URL. --- ## What you'll need You will need to obtain two pieces of information from a GitHub OAuth application: - **GitHub Client ID**: Application identifier from GitHub - **GitHub Client Secret**: Authentication secret for the application The following sections will guide you through creating an OAuth application in your GitHub account and generating these credentials. --- ## (1) Create the GitHub OAuth Application or GitHub App Sign in to GitHub and navigate to [**Developer settings**](https://github.com/settings/developers). You can create either an **OAuth App** or a **GitHub App**. ### Option A: OAuth App Select **OAuth Apps** and create a new OAuth app. Be sure to at least enable the `user:email` scope, as this is required to retrieve the user's email address from GitHub, which is necessary for authentication. You can optionally configure additional scopes as needed. ![The New OAuth App button in GitHub](https://images.workoscdn.com/images/d8991483-a60e-4bc6-985f-2053d8b3c2c9.png?auto=format&fit=clip&q=80) > You can also register a new application under a GitHub Organization, which may be more appropriate if it is maintained by a team of developers. You can also [transfer ownership](https://docs.github.com/en/apps/oauth-apps/maintaining-oauth-apps/transferring-ownership-of-an-oauth-app) of your GitHub OAuth application to a GitHub organization later. ### Option B: GitHub App Select **GitHub Apps** and create a new GitHub App. GitHub Apps offer more granular permissions and can provide refresh tokens with expiration for improved security. For more information, see GitHub's documentation on [differences between GitHub Apps and OAuth Apps](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/differences-between-github-apps-and-oauth-apps). > When using a GitHub App, OAuth scopes are not applicable. Instead, permissions are configured directly on the GitHub App. Be sure to set the **Email addresses** account permission to **Read-only**, as this is required to retrieve the user's email address from GitHub. The access token is limited to the permissions that both your app and the user have. --- ## (2) Configure the application Fill out the application form. For the **Authorization callback URL** (OAuth App) or **Callback URL** (GitHub App), enter the **Redirect URI** from the WorkOS Dashboard. Click **Register application** (OAuth App) or **Create GitHub App** (GitHub App). ![The GitHub form to create a new OAuth application.](https://images.workoscdn.com/images/6282967b-eee8-4937-8ec8-a1f25d7ec873.png?auto=format&fit=clip&q=80) You'll be given a Client ID. Note this value as you'll need it for the WorkOS configuration. Click **Generate a new client secret** to generate a new client secret. Note that this value is only temporarily available, so make sure to save it before proceeding. ![The Client ID and Client Secret in GitHub](https://images.workoscdn.com/images/ba3c133b-3492-4b5b-b10c-69717ca3e50c.png?auto=format&fit=clip&q=80) --- ## (3) Configure GitHub credentials in WorkOS Now that you have the **GitHub Client ID** and **GitHub Client Secret** from the previous step return to the [WorkOS Dashboard](https://dashboard.workos.com/). In the **GitHub OAuth** configuration dialog, select **Your app's credentials**. Paste the credentials from GitHub into their respective fields in the WorkOS Dashboard. ![Where to enter the GitHub Client ID and GitHub Client Secret in the WorkOS Dashboard](https://images.workoscdn.com/images/01d06b09-d622-4815-8757-c3b6825b790b.png?auto=format&fit=clip&q=50) Click **Save** to complete the configuration. You're now able to authenticate users with GitHub OAuth. You will use the `provider` query parameter in the Get Authorization URL API endpoint to support global GitHub OAuth for any domain. The `provider` query parameter should be set to `GitHubOAuth`. --- ## Configure Additional OAuth Scopes (Optional) > This section only applies to GitHub OAuth Apps. GitHub Apps do not use OAuth scopes — permissions are configured directly on the GitHub App in GitHub's settings. WorkOS will request the OAuth scopes that are required for authentication by default. You can optionally configure your integration to request additional OAuth scopes as needed. When the **Return GitHub OAuth tokens** option is selected, the access token from GitHub will be included in the response from the [Authenticate with code API](/reference/authkit/authentication/code). For GitHub Apps, the response will also include a refresh token and expiration when available. ![A screenshot showing GitHub OAuth scopes configuration in the WorkOS Dashboard](https://images.workoscdn.com/images/9cfbd37c-f1cc-436d-8e61-0ccce2612bc6.png?auto=format&fit=clip&q=50) Any scopes configured here will be included on every GitHub OAuth request. To specify additional scopes dynamically, use the `provider_scopes` query parameter on the [Get Authorization URL API endpoint](/reference/authkit/authentication/get-authorization-url). For more information, see GitHub's OAuth scopes [documentation](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps). --- ## Frequently asked questions ### How is the WorkOS GitHub OAuth integration different from implementing regular GitHub OAuth flow? It's the same GitHub OAuth flow as you could build yourself, but it's encapsulated within WorkOS SSO. This means you don't need to build it yourself. In addition to GitHub OAuth, you can use WorkOS SSO to support other identity providers, all with a single integration. ### What is the provider query parameter and how is it used in the GitHub OAuth integration? You can use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/sso/get-authorization-url) to support global GitHub OAuth for any domain. The `provider` query parameter should be set to `GitHubOAuth`. ### Fourth Learn about syncing your user list with Fourth. ## Introduction This guide outlines how to synchronize your application's Fourth directories. To synchronize an organization's users and groups provisioned for your application, you'll need the following information from the organization: - Fourth Organization ID - Fourth username and password > Note: The Fourth integration isn't enabled by default in the WorkOS Dashboard or Admin Portal. Please reach out to [support@workos.com](mailto:support@workos.com) or via your team's WorkOS Slack channel if you would like Fourth enabled. --- ## (1) Set up your directory sync integration Sign in into your WorkOS Dashboard and select "Organizations" from the left hand navigation bar. Select the organization you'll be configuring a new Directory Sync connection with. Click "Manually Configure Directory". ![A screenshot showing where to find "Manually Configure Directory" button for an organization in the WorkOS dashboard.](https://images.workoscdn.com/images/0a0fa511-08ae-4fd9-9cfc-0301b7041b3f.png?auto=format&fit=clip&q=50) Input the Name, and select "Fourth" as the directory type. Click the "Create Directory" button. ![A screenshot showing "Create Directory" details in the WorkOS dashboard.](https://images.workoscdn.com/images/ba13b740-7cbf-42e5-a511-b0c5a9f384e0.png?auto=format&fit=clip&q=50) You will now see your Fourth directory sync has been created successfully with an input for the Organization ID, username, and password. ## (2) Obtain and update directory details Retrieve the Fourth Organization ID from the organization's IT contacts, as well as the username and password that will be used for authentication. Click "Update Directory" in the WorkOS Dashboard. ![A screenshot showing where to find the "Update Directory" button in the WorkOS dashboard.](https://images.workoscdn.com/images/9c641325-3703-4c17-955e-d6b0fc898996.png?auto=format&fit=clip&q=50) Enter the Organization ID, the username and the password. --- ## (3) View users and groups in your dashboard When the connection is successfully made, you will see the green "Linked" icon appear. Now, whenever the organization assigns users or groups to your application, you'll receive Dashboard updates based on changes in their directory. Click on the "Users" tab in the Dashboard to view synced users. ![A screenshot showing where to find the "Users" tab in the WorkOS directory.](https://images.workoscdn.com/images/0784ded9-3fcd-45f1-87cc-44bb41e2031c.png?auto=format&fit=clip&q=50) --- ## Frequently asked questions ### How often do Fourth directories perform a sync? Fourth directories poll every 30 minutes starting from the time of the initial sync. ### Firebase Add Single Sign-On to your Firebase application with WorkOS. ## Introduction In this guide, you'll learn how to use WorkOS to add Single Sign-On (SSO) to a Firebase application. This will allow users to sign in to an existing Firebase application using WorkOS SSO Connections. ## What WorkOS provides WorkOS will provide the following pieces of information: API key, Client ID, and the Issuer URL. - The API key can be found in your WorkOS dashboard under **API Keys**. - The Client ID can be found in your WorkOS dashboard under **Configuration**. - The Issuer URL is constructed with the Client ID. `https://auth.workos.com/sso/`. ## What you'll need - An existing Firebase project --- ## (1) Configure Authentication for your Firebase project Log into Firebase and navigate to your project. Click on the Authentication tile to set up a new Authentication method for your project. ![A screenshot showing where to find the Authentication tile in Firebase.](https://images.workoscdn.com/images/612ce59a-a1c8-4eb9-a209-9d0f6b6c5086.png?auto=format&fit=clip&q=50) Next, click **Get started**. ![A screenshot showing where to find the Get started button in Firebase](https://images.workoscdn.com/images/bd877730-1e9a-487d-8938-10782c912d45.png?auto=format&fit=clip&q=50) Click on the Sign-in method tab and then select the OpenID Connect custom provider. ![A screenshot showing where to find the OpenID Connect custom provider in Firebase](https://images.workoscdn.com/images/ee3fbc76-d94b-491e-842a-5f74eb4a2d62.png?auto=format&fit=clip&q=50) Enter the configuration details for the connection between WorkOS and Firebase. You will need the following pieces of information: - **WorkOS Client ID**: Found on the **Configuration** tab of the WorkOS Dashboard - **WorkOS API Key**: Located on the **API Keys** tab of the WorkOS Dashboard - **Issuer (URL)**: This will be `https://auth.workos.com/sso/` appended with your client ID, ex: `https://auth.workos.com/sso/client_123` - **Provider ID**: This is found in Firebase under the Name of your OIDC provider. This will be important for a later step. ![A screenshot showing the authentication provider configuration details in Firebase](https://images.workoscdn.com/images/5eb66fe3-8cad-4555-9417-ab38924d1288.png?auto=format&fit=clip&q=50) --- ## (2) Configure the Redirect URI in WorkOS Click Next, then copy the **Callback URL** provided by Firebase. ![A screenshot showing where to obtain the Callback URL in Firebase.](https://images.workoscdn.com/images/a33d3b63-e6f9-4a43-8108-012f54d7c7db.png?auto=format&fit=clip&q=50) In the [Applications](https://dashboard.workos.com/environment/applications) section of the WorkOS Dashboard, open your application and go to the **Redirects** tab. Paste the Callback URL in the redirect URIs list. ![A screenshot showing where to enter the Redirect URI in WorkOS.](https://images.workoscdn.com/images/c2c6ef52-e61e-41af-9c37-1e2187bf1744.png?auto=format&fit=clip&q=50) --- ## (3) Create a Firebase web app and get configuration details On the Firebase Project Overview page, click the web icon above **Add an app to get started**, or navigate to your project settings page if your project is already set up. ![A screenshot showing where to create a web app in Firebase.](https://images.workoscdn.com/images/777e0c57-2c9d-4516-9e3e-985460ed38b6.png?auto=format&fit=clip&q=50) Choose a name for your application, and then take note of the firebaseConfig from the Add Firebase SDK step. ![A screenshot showing where to obtain the firebaseConfig details in Firebase.](https://images.workoscdn.com/images/64b62bc6-4891-4627-9a2a-9440e0d27aa7.png?auto=format&fit=clip&q=50) --- ## (4) Configure Firebase login in your application Your Firebase configuration and Provider ID can now be used along with any Organization ID from an Active WorkOS SSO connection to log users in to your Firebase app. Here is a basic example showing how this can be set up. Replace the `firebaseConfig` variable value with the config from your Firebase app, the `OAuthProvider` value with your Provider ID, and the organization under `provider.setCustomParameters` with the organization to target. This organization should have an active SSO connection already set up. > The `connection` parameter may be used in place of the `organization` parameter to target a connection. Finally, run the app and click the sign-in button. You will now see the user signed in on the Authentication section's user tab in Firebase. You can also view the user information by decoding the access token which is logged to the console. ![A screenshot showing a successfully authenticated user in Firebase.](https://images.workoscdn.com/images/a4d521f9-3765-4d2d-909c-5340a462ba3e.png?auto=format&fit=clip&q=50) ### Entra ID SCIM (formerly Azure AD) Learn about syncing your user list with Entra ID SCIM. ## Introduction This guide outlines how to synchronize your application's Entra ID directories using SCIM. To synchronize an organization's users and groups provisioned for your application, you'll need to provide the organization with two pieces of information: - An [Endpoint](/glossary/endpoint) that Entra ID will make requests to. - A [Bearer Token](/glossary/bearer-token) for Entra ID to authenticate its endpoint requests. Both of these are available in your Endpoint's Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). > Steps 2, 3, and 4 below will need to be carried out by IT contacts when configuring your application in their Entra ID instance. --- ## (1) Set up your Directory Sync endpoint Sign in to your WorkOS Dashboard and select "Organizations" from the left hand navigation bar. Select the organization you'll be configuring a new Directory Sync for. Click "Add Directory". ![A screenshot showing where to add a new directory in the WorkOS dashboard.](https://images.workoscdn.com/images/cf3a5ae2-4add-47ca-887e-d4d78c33d786.png?auto=format&fit=clip&q=50) Select "Entra ID" from the dropdown, and enter the organization name. Then, click "Create Directory." ![A screenshot showing the "Create Directory" menu in the WorkOS dashboard.](https://images.workoscdn.com/images/6244ecf4-65a0-4421-b984-d513704ef882.png?auto=format&fit=clip&q=50) > We have support for whitelabeled URLs for Directory Sync endpoints. [Contact us](mailto:support@workos.com) for more info! Your Entra ID directory sync has now been created successfully with an Endpoint and Bearer Token. ![A screenshot showing the Azure SCIM endpoint and bearer token in the WorkOS dashboard.](https://images.workoscdn.com/images/38a98a55-96fa-403d-86f8-cfb313cd51e5.png?auto=format&fit=clip&q=50) --- ## (2) Select or create your Azure application Sign in to the Entra ID Admin Center Dashboard. Select "Enterprise applications" from the list of Azure services. ![A screenshot showing where to select "Enterprise applications" in the Azure Active Directory Admin Center Dashboard](https://images.workoscdn.com/images/25d08d2e-48b8-49b0-b8e9-d57641606b57.png?auto=format&fit=clip&q=50) If your application is already created, select it from the list of applications and move to Step 3. ![A screenshot showing where to select the application of choice in the All Applications menu in Azure.](https://images.workoscdn.com/images/7430b6b1-2d16-4df1-b11a-a51d51bc4725.png?auto=format&fit=clip&q=50) If you haven't created a SCIM application in Azure, select "New Application". ![A screenshot showing where to select a new application in the All Applications menu in Azure.](https://images.workoscdn.com/images/8e9587aa-e259-4175-952c-bebe476457a2.png?auto=format&fit=clip&q=50) Select "Create your own application" and continue. ![A screenshot showing where to select "Create your own application" in the All Applications menu in Azure.](https://images.workoscdn.com/images/ef501e51-ca06-47ef-a731-f509960fbf70.png?auto=format&fit=clip&q=50) Give your application a descriptive name, and select the "Integrate any other application you don't find in the gallery (Non-gallery)" option, then click "Create". ![A screenshot showing where to configure the name of a new application in Azure.](https://images.workoscdn.com/images/cbd435b0-2313-4922-9fa3-87de57b39de8.png?auto=format&fit=clip&q=50) --- ## (3) Configure your integration Select "Provisioning" from the "Manage" section found in the navigation menu. ![A screenshot showing where to select "Provisioning" from the "Manage" section in Azure.](https://images.workoscdn.com/images/39c18ede-837f-4735-8fa7-6cc3eb855776.png?auto=format&fit=clip&q=50) Click the "Get Started" button. ![A screenshot showing where to select "Get Started" in the "Provisioning" menu in Azure.](https://images.workoscdn.com/images/e7d7e41f-1dec-4119-a3c4-fcc349a39eb5.png?auto=format&fit=clip&q=50) Select the "Automatic" Provisioning Mode from the dropdown menu. In the "Admin Credentials" section, copy and paste the Endpoint from your [WorkOS Dashboard](https://dashboard.workos.com/) in the "Tenant URL" field. Then, copy and paste the Bearer Token from your [WorkOS Dashboard](https://dashboard.workos.com/) into the Secret Token field. Click "Test Connection" to receive confirmation that your connection has been set up correctly. Then, select "Save" to persist the credentials. ![A screenshot showing where to configure the provisioning mode and credentials in Azure.](https://images.workoscdn.com/images/22d127dc-6834-4a84-b579-c7ae045cd339.png?auto=format&fit=clip&q=50) --- ## (4) Set and enable Attribute mappings Expand the "Mappings" section. ![A screenshot showing where to expand "Mappings" in Azure.](https://images.workoscdn.com/images/f78bb399-3ab3-4822-a6bf-e8e96db93cdd.png?auto=format&fit=clip&q=50) Make sure the group and user attribute mappings are enabled, and are mapping the correct fields. The default mapping should work, but your specific Azure setup may require you to add a custom mapping. ![A screenshot showing where to ensure User attribute mappings are enabled in Azure.](https://images.workoscdn.com/images/ab0daea3-dda3-4e3d-9199-9d30a710fdb2.png?auto=format&fit=clip&q=50) Make sure that you are mapping `objectId` to `externalId` within the Attribute Mapping section. ![A screenshot showing where to ensure object ID is mapped to external ID in the Attribute Mapping section in Azure.](https://images.workoscdn.com/images/389cb8cc-9bfd-4f0b-b623-1304cf863c64.png?auto=format&fit=clip&q=50) --- ## (5) Assign users and groups to your application In order for your users and groups to be synced, you will need to assign them to your Entra ID SCIM Application. Select "Users and groups" from the "Manage" section of the navigation menu. ![A screenshot showing where to navigate to "Users and groups" from the "Manage" section in Azure.](https://images.workoscdn.com/images/d4f01d7f-6dc4-46c6-a524-a6c5fe47cf7a.png?auto=format&fit=clip&q=50) Select "Add user/group" from the top menu. ![A screenshot showing where to select "Add user/group" in the Users and groups menu in Azure.](https://images.workoscdn.com/images/68717808-6ca4-47ff-8bc0-690f3bfffe0e.png?auto=format&fit=clip&q=50) Select "None selected" under the "Users and Groups". In the menu, select the users and groups that you want to add to the SCIM application, and click "Select". ![A screenshot showing where to select users for a SCIM application in Azure.](https://images.workoscdn.com/images/b6e2c4f6-ef9b-4881-8d9c-a23ae55a1490.png?auto=format&fit=clip&q=50) Select "Assign" to add the selected users and groups to your SCIM application. ![A screenshot showing where to assign the selected users for the SCIM application in Azure.](https://images.workoscdn.com/images/e2f7221f-9789-4288-bd66-5450d150db0b.png?auto=format&fit=clip&q=50) --- ## (6) Turn on provisioning for your SCIM application In the Provisioning menu, confirm the "Provisioning Status" is set to "On" and that the "Scope" is set to "Sync only assigned users and groups". ![A screenshot showing where to ensure that the "Provisioning Status" is "On" and "Scope" is set to "Sync only assigned users and groups" in Azure.](https://images.workoscdn.com/images/67041f59-27dc-4026-b6a2-c43568c59dfd.png?auto=format&fit=clip&q=50) Begin provisioning users and groups and witness realtime changes in your [WorkOS Dashboard](https://dashboard.workos.com/). A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) --- ## Configuring user attribute mappings For any non-standard attributes used by the application, some configuration may be required in Microsoft Entra. Below is a guide on configuring user attribute mappings, so they propagate via SCIM. ### (1) Viewing application attributes From your Microsoft Entra SCIM application, navigate to the Manage → Provisioning page. Expand the Mappings section and click "Provision Microsoft Entra ID Users". ![Microsoft Entra enterprise application provisioning tab](https://images.workoscdn.com/images/cb7b0eb7-8ff7-452e-b3c5-14eede22c4da.png?auto=format&fit=clip&q=50) This will display a list of attribute mappings and settings: ![Microsoft Entra attribute mapping settings](https://images.workoscdn.com/images/472657ed-812c-4f3a-b57d-601e573adf48.png?auto=format&fit=clip&q=50) ### (2) Adding or editing an attribute To add a missing attribute, click the "Add New Mapping" button at the bottom left of the mappings list. To edit an existing attribute, click the "Edit" button next to the existing attribute you'd like to edit. ![Microsoft Entra add new mapping button](https://images.workoscdn.com/images/2319dab9-6392-4a7f-9988-fe8cf5260301.png?auto=format&fit=clip&q=50) To configure the mapping, select the source and target attribute from the dropdowns, and ensure "Apply this mapping" is set to "Always". For example, to map division, the source attribute has been selected as `employeeOrgData.division` and the target attribute has been selected as `urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:division`. ![Microsoft Entra configure mapping dialog](https://images.workoscdn.com/images/984c0ffe-0d18-4f04-a69b-d4e09b4a51d3.png?auto=format&fit=clip&q=50) These new attribute mappings will now propagate to your application when the next SCIM push occurs. --- ## Provisioning on demand By default, Entra ID SCIM 2.0 directories sync changes on a scheduled time interval, typically every 40 minutes. For use cases where more immediate provisioning or deprovisioning of users, groups, or group memberships is needed, Entra ID provides [provisioning on demand](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/provision-on-demand?pivots=app-provisioning). To provision on demand, from the enterprise application navigate to the "Provisioning" tab and click "Provision on demand". ![Entra ID provision on demand button](https://images.workoscdn.com/images/de50df7b-4088-4e95-a711-ad04e43474c5.png?auto=format&fit=clip&q=50) To provision a user, select the user from the dropdown and click "Provision". ![Entra ID provision user on demand](https://images.workoscdn.com/images/121aaa24-d160-40a4-824f-44cc2a5ff84d.png?auto=format&fit=clip&q=50) To provision a group or group membership, select the group from the dropdown, and select "View members only". Then select the group memberships to provision and click "Provision". ![Entra ID provision group memberships on demand](https://images.workoscdn.com/images/34167704-985a-4b0b-b110-89e19d618b37.png?auto=format&fit=clip&q=50) Upon clicking "Provision", SCIM requests will immediately be sent to the application. To deprovision a user, group, or group membership, remove it from the Entra application and follow the above provisioning on demand steps. --- ## Frequently asked questions ### No email addresses are coming through for users from Entra. How do I get emails for my Entra users? For cloud-managed users, Entra ID pulls the email from the `mail` attribute in Exchange. If your customer doesn't have this set up, they will need to configure attribute mapping in their SCIM app in Entra in order to provision users with WorkOS. They can use [this tutorial from Microsoft](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/customize-application-attributes). They'll want to map a known email attribute, such as UPN, to the `emails[type eq "work"].value` SCIM attribute. For directories with synchronized-users, they will need to map the `userPrincipalName` attribute into the `emails[type eq "work"].value` SCIM attribute. ### Sometimes, reactivating "suspended" users does not re-add them to their Entra groups. Why is that and how can I fix it? When a user is deleted from the entire directory, instead of only being deprovisioned from the SCIM app, the user may be soft-deleted (their state is set as "suspended"). Reactivating these suspended users will not send SCIM requests to re-add the user to the groups. To do so, the IT contact will need to select the "Restart Provisioning" button for the SCIM app in Azure. ![A screenshot showing where to restart provisioning in Entra.](https://images.workoscdn.com/images/757f8920-da4b-46ac-90b0-9780b150eb62.png?auto=format&fit=clip&q=50) ### Can profile images be accessed with Entra ID SCIM? Entra ID's SCIM provisioning does not support transmitting image. ### Why do I receive a `dsync.user.updated` event after `dsync.user.created`? Entra ID sends a newly provisioned user over to WorkOS in two separate actions. WorkOS will then send these actions as two individual events to your app. This is expected behavior. ### How often do Entra ID SCIM 2.0 directories perform a sync? By default, Entra ID SCIM 2.0 directories sync changes on a scheduled time interval, typically every 40 minutes. For more details, please refer to Entra ID's [official documentation](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/application-provisioning-when-will-provisioning-finish-specific-user#how-long-will-it-take-to-provision-users). [Provisioning on demand](/integrations/entra-id-scim/provisioning-on-demand) is also available, which can sync select users, groups, or group memberships in real-time. ### What is the `idp_id` for directory groups from Entra ID? Entra ID provides a unique object identifier for each group through the SCIM `externalId` field. This is persisted as the `idp_id` for [directory groups](/reference/directory-sync/directory-group) in WorkOS. ### Entra ID SAML (formerly Azure AD) Learn how to configure a connection to Entra ID via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). And often, the information required to create a Connection will differ by Identity Provider. To create an Entra ID SAML Connection, you'll need the Identity Provider Metadata URL that is available from the organization's Entra ID instance. --- ## What WorkOS Provides WorkOS provides the [ACS URL](/glossary/acs-url) and [IdP URI (Entity ID)](/glossary/idp-uri-entity-id). It's readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/get-started). ![A screenshot showing the ACS URL and Entity ID in the WorkOS dashboard.](https://images.workoscdn.com/images/5051f1e9-36dd-4032-b2db-873c9d26a7da.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. In Entra ID's case, it needs to be set by the organization when configuring your application in their Entra ID instance. Specifically, the ACS URL will need to be set as the "Reply URL (Assertion Consumer Service URL)" in the "Basic SAML Configuration" step of the Entra ID "Set up Single Sign-On with SAML" wizard: ![A screenshot showing the location to place the WorkOS ACS URL in the Entra Dashboard.](https://images.workoscdn.com/images/61fa14dd-fa98-437b-8e99-5c0cec1c4b2b.png?auto=format&fit=clip&q=50) The [Entity ID](/glossary/idp-uri-entity-id) is a URI used to identify the issuer of a SAML request, response, or assertion. In this case, the entity ID is used to communicate that WorkOS will be the party performing SAML requests to the organization's Entra ID instance. Specifically, the Entity ID will need to be set as the "Identifier (Entity ID)" in the "Basic SAML Configuration" step of the Entra ID "Set up Single Sign-On with SAML" wizard: ![A screenshot showing the location to place the WorkOS Entity ID in the Entra Dashboard.](https://images.workoscdn.com/images/96cbcf4e-705e-43e5-9cc3-7fd24f0be2a2.png?auto=format&fit=clip&q=50) --- ## What you'll need In order to integrate you'll need the Entra ID IdP Metadata URL. Normally, this information will come from the organization's IT Management team when they set up your application's SAML 2.0 configuration in their Entra admin dashboard. Here's how to obtain them: --- ## (1) Log in Log in to the [Entra ID Active Directory Admin dashboard](https://portal.azure.com/). Select "Enterprise Applications" from the list of Entra services. ![A screenshot showing where to select "Enterprise Applications" in the Entra dashboard.](https://images.workoscdn.com/images/37f3b3d2-fcdb-4a5f-8d93-970ec0239446.png?auto=format&fit=clip&q=50) --- ## (2) Select or create your application If your application is already created, select it from the list of Enterprise applications and move to Step 7. ![A screenshot showing where to select an existing application in the Entra dashboard.](https://images.workoscdn.com/images/a61ca1b9-4e06-4dc6-80de-eac3fea212cd.png?auto=format&fit=clip&q=50) If you haven't created a SAML Application in Entra, select "New Application". ![A screenshot showing where to select "New Application" in the Entra dashboard.](https://images.workoscdn.com/images/3c26fec7-f77a-4757-8a04-6998ff7beb26.png?auto=format&fit=clip&q=50) --- ## (3) Initial SAML Application Setup Select "Create your own application", then enter a descriptive app name. Under "What are you looking to do with your application?", select "Integrate any other application you don't find in the gallery (Non-gallery)", then select "Create". ![A screenshot showing where to input the name of the new application in the Entra dashboard.](https://images.workoscdn.com/images/9f998b1b-87b4-4f1d-a50c-0a17f8bb3f98.png?auto=format&fit=clip&q=50) Select "Single Sign-On" from the "Manage" section in the left sidebar navigation menu, and then "SAML". ![A screenshot showing how to select "SAML" as the Single Sign-On method of the Entra application in the Entra dashboard.](https://images.workoscdn.com/images/f90c0d1a-ed45-4bee-b77f-dcf37a63a6bd.png?auto=format&fit=clip&q=50) --- ## (4) Configure SAML Application Click the Edit icon in the top right corner of the first step "Basic SAML Configuration". ![A screenshot showing where to select "Edit" for the "Basic SAML Configuration" step in the Entra dashboard.](https://images.workoscdn.com/images/e7a4397c-8120-43c6-9b66-e6a2251cd5bd.png?auto=format&fit=clip&q=50) Input the IdP URI (Entity ID) from your WorkOS Dashboard as the "Identifier (Entity ID)". Input the ACS URL from your WorkOS Dashboard as the "Reply URL (Assertion Consumer Service URL)". ![A screenshot showing where to input the WorkOS ACS URL and WorkOS Entity ID in the Entra dashboard.](https://images.workoscdn.com/images/dd406379-af79-44b5-8d5a-4076659258c8.png?auto=format&fit=clip&q=50) --- ## (5) Configure User Attributes and Claims Click the Edit icon in the top right corner of the second step "Attributes & Claims". ![A screenshot showing where to select "Edit" for the "Attributes & Claims" step in the Entra dashboard.](https://images.workoscdn.com/images/6155597f-a4b8-4a3c-a7f3-a6e8d4e0865d.png?auto=format&fit=clip&q=50) Make sure the following attribute mapping is set: - `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress` → `user.mail` - `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname` → `user.givenname` - `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name` → `user.userprincipalname` - `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname` → `user.surname` Below is an example of how to format your claim within the Entra claim editor. Make sure the 'Namespace' value ends in `/claims`. ![A screenshot showing the "Manage Claim" configuration in the Entra dashboard.](https://images.workoscdn.com/images/93ec5d1b-9ecd-49f5-8d2a-a718b5ea58b2.png?auto=format&fit=clip&q=50) ![A screenshot showing the "Attribute & Claims" configuration in the Entra dashboard.](https://images.workoscdn.com/images/f41b5a7c-1842-4567-9f46-85caa7309176.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, follow the guidance below. Select "Add a group claim" from the top menu. Next, select which groups you'd like to return in the Group Claims settings. For example, in Entra ID, you could select "Groups assigned to the application" to only send groups assigned to the SAML app. Finally, select "Save" once finished configuring the groups. ![A screenshot showing how to add a groups claim to your SAML app in the Entra dashboard.](https://images.workoscdn.com/images/4e33755c-945f-4164-873f-33482e3a2c43.png?auto=format&fit=clip&q=50) > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (6) Add Users to SAML Application In order for your users or groups of users to be authenticated, you will need to assign them to your Entra ID SAML application. Select "Users and groups" from the "Manage" section of the navigation menu. ![A screenshot showing where to select "Users and groups" in the Entra dashboard.](https://images.workoscdn.com/images/7fe69c75-311e-409b-905a-dbd6b6087394.png?auto=format&fit=clip&q=50) Select "Add user/group" from the top menu. ![A screenshot showing where to select "Add user/group" in the Entra dashboard.](https://images.workoscdn.com/images/817e4d3d-7470-4e20-b9f1-af74ea8adc73.png?auto=format&fit=clip&q=50) Select "None selected" under the "Users and Groups". In the menu, select the users and groups of users that you want to add to the SAML application, and click "Select". ![A screenshot showing where to select "None Selected" under "Users and Groups" and add a user in the Entra dashboard.](https://images.workoscdn.com/images/85f005d7-3655-46ac-9554-77fda2c44747.png?auto=format&fit=clip&q=50) Select "Assign" to add the selected users and groups of users to your SAML application. ![A screenshot showing where to select "Assign" in the Entra dashboard.](https://images.workoscdn.com/images/5420b145-6086-4141-b096-9ae9f6ea8529.png?auto=format&fit=clip&q=50) --- ## (7) Obtain Identity Provider Details Select "Single Sign-On" from the "Manage" section in the left sidebar navigation menu. Navigate down to Section 3 of the "Single Sign-On" page, to "SAML Signing Certificate". Copy the URL provided in "App Federation Metadata URL". ![A screenshot showing where to select the "App Federation Metadata URL" in the Entra dashboard.](https://images.workoscdn.com/images/c4ee0b27-ddd7-4aab-96c0-ced1019b4cd7.png?auto=format&fit=clip&q=50) Next, within your connection settings under "Identity Provider Configuration", select "Edit Configuration" and enter the Entra metadata URL. ![A screenshot showing where to select "Edit Configuration" on the "SSO Connection" page in the WorkOS dashboard.](https://images.workoscdn.com/images/080cded6-eba5-41af-ab93-2845e464acb8.png?auto=format&fit=clip&q=50) ![A screenshot showing where to paste the Metadata URL on the "SSO Connection" page in the WorkOS dashboard.](https://images.workoscdn.com/images/28377a44-73d6-4617-84c8-be836e19862c.png?auto=format&fit=clip&q=50) Your Connection will then be verified and good to go! ![A screenshot showing an active Entra SAML connection in the WorkOS dashboard.](https://images.workoscdn.com/images/e02c6b1e-7ab6-4cb0-a39d-c2255d8b5b6e.png?auto=format&fit=clip&q=50) ### Entra ID OIDC (formerly Azure AD) Learn how to configure a connection to Entra ID via OIDC. ## Introduction Each SSO identity provider requires specific information to create and configure a new [SSO connection](/glossary/connection). Often, the information required to create an SSO connection will differ by identity provider. To create an Entra ID OIDC SSO connection, you'll need four pieces of information: a [redirect URI](/glossary/redirect-uri), [application (client) ID](/glossary/client-id), [client secret](/glossary/client-secret) and [discovery endpoint](/glossary/discovery-endpoint). Start by logging in to your WorkOS dashboard and navigate to the **Organizations** page from the left-hand navigation bar. Select the organization you'd like to configure an Entra ID OIDC SSO connection for, and select **Configure manually** under **Single Sign-On**. ![WorkOS Dashboard Organizations tab with "Configure manually" button highlighted](https://images.workoscdn.com/images/d577cfbe-028b-48cf-8cc0-4cd5d3adf853.png?auto=format&fit=clip&q=50) Select **Entra ID (Azure AD) OIDC** from the identity provider dropdown, enter a descriptive name for the connection, click **Create Connection**. ![Create Connection form with Entra ID (Azure AD) OIDC selected as Identity Provider](https://images.workoscdn.com/images/90fe747d-88e3-40da-a028-161132401a5c.png?auto=format&fit=clip&q=50) --- ## What WorkOS provides WorkOS provides the Redirect URI, which can be found in the **Service Provider Details** section on the SSO connection page in the [WorkOS Dashboard](https://dashboard.workos.com/). - [Redirect URI](/glossary/redirect-uri): The endpoint where identity providers send authentication responses after successful login ![The Redirect URI of a OIDC connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/99a7c7d5-50a9-4bff-a3f3-22dc1cfeca58.png?auto=format&fit=clip&q=50) The Redirect URI is the location an identity provider redirects its authentication response to. In Entra ID's case, it needs to be set during application registration when configuring your OIDC application, which is outlined in [step 1](/integrations/entra-id-oidc/1-register-an-application) below. --- ## What you'll need You will need to obtain three pieces of information from the organization: - [Application (Client) ID](/glossary/client-id): Application identifier from the OIDC provider - [Client Secret](/glossary/client-secret): Authentication secret for the application - [Discovery endpoint](/glossary/discovery-endpoint): Configuration URL containing OIDC metadata Normally, this information will come from the organization's IT Management team when they set up your application's OIDC configuration in their Entra ID admin center. But, should that not be the case during your setup, the next steps will show you how to obtain it. --- ## (1) Register an application Sign in to the [Microsoft Entra admin center](https://entra.microsoft.com/). In the left navigation menu, expand the **Identity** section. Expand the **Applications** sub-section. Select the **App registrations** tab. Click **New registration**. ![Microsoft Entra admin center navigation showing Identity > Applications > App registrations](https://images.workoscdn.com/images/67c07f6f-f60d-48da-b950-eac73d094dfb.png?auto=format&fit=clip&q=50) Enter an appropriate app name, such as your organization or application name. Select one of these **Supported account types**: - Accounts in this organizational directory only (Default Directory only - Single tenant) (Default) - Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) In the **Redirect URI** field, select the **Web** option from the dropdown menu. Copy the [Redirect URI](/integrations/entra-id-oidc/what-workos-provides) from the SSO connection page in the WorkOS Dashboard and paste it into the input field. ![App registration form with name, supported account types, and redirect URI fields](https://images.workoscdn.com/images/d09699ac-00d4-4a8f-9ff7-9090c79d805b.png?auto=format&fit=clip&q=50) Click **Register**. --- ## (2) Obtain required configuration details Now you'll need to gather three pieces of information from your Entra ID application that will be configured in your WorkOS dashboard: the client ID, client secret, and discovery endpoint. Keep these values handy to input into the WorkOS Dashboard. ### Get the client ID From the application **Overview** page, copy the **Application (client) ID**. ![Entra ID application Overview page showing Application (client) ID field](https://images.workoscdn.com/images/70506649-66e4-490a-82b0-69175d0f3381.png?auto=format&fit=clip&q=50) ### Create and retrieve the client secret Navigate to the **Certificates & secrets** page. Click **New client secret**. ![Certificates & secrets page with "New client secret" button](https://images.workoscdn.com/images/28afb31c-3e94-4263-aedb-9924e0a4678d.png?auto=format&fit=clip&q=50) Enter an appropriate secret description and select an expiration period. Click **Add**. ![Add a client secret panel with the description, expires at fields highlighted](https://images.workoscdn.com/images/6d72665b-7ad0-4837-ac58-b9acbe2d7fee.png?auto=format&fit=clip&q=50) Copy the newly created client secret **Value** immediately as it will not be shown again after you navigate away from this page. ![Client secret creation form with description field and generated secret value](https://images.workoscdn.com/images/7e1604a5-1bdb-4a0c-80d5-8b4401c4269e.png?auto=format&fit=clip&q=50) ### Get the discovery endpoint From the application **Overview** page, click the **Endpoints** tab. ![Entra ID application Overview page with Endpoints tab highlighted](https://images.workoscdn.com/images/70fee14e-bb7d-43ab-8bb8-70150af299b6.png?auto=format&fit=clip&q=50) Scroll down to find and copy the **OpenID Connect metadata document** URL. This is your Discovery Endpoint. ![Endpoints list showing OpenID Connect metadata document URL](https://images.workoscdn.com/images/aca9c724-2a6f-4449-b435-f63bd538d60f.png?auto=format&fit=clip&q=50) ### Update the SSO connection settings Back in the WorkOS Dashboard on the SSO connection page, enter the client ID, client secret, and discovery endpoint you obtained from Entra ID into the respective fields in the **\{SSO connection name} Settings** section. ![WorkOS Dashboard Identity Provider Configuration with Client ID, Client Secret, and Discovery Endpoint fields](https://images.workoscdn.com/images/714cb015-94db-4080-ad53-942da1804c01.png?auto=format&fit=clip&q=50) Click **Update connection** to save. --- ## (3) Configure token claims Navigate to the **Token configuration** page. Click **Add optional claim**. ![Token configuration page with "Add optional claim" button](https://images.workoscdn.com/images/c71dc730-995d-48d3-a5eb-3b28166fa6c0.png?auto=format&fit=clip&q=50) Select **ID** token type, and then select the following claims: - `email` - `family_name` - `given_name` ![Optional claims dialog with ID token type selected and email, family\_name, given\_name claims](https://images.workoscdn.com/images/0cfa531a-de60-4ead-9655-0a473dbd5658.png?auto=format&fit=clip&q=50) Click **Add**. In the pop-up, select **Turn on the Microsoft Graph email, profile permission**, then click **Add**. ![Add optional claim panel with turn on Microsoft Graph checkbox highlighted](https://images.workoscdn.com/images/644ac9db-6bb6-4ca5-bd65-af23ceec5b6a.png?auto=format&fit=clip&q=50) --- ## (4) Assign users and groups In the left navigation menu, expand the **Identity** section. Expand the **Applications** sub-section. Select the **Enterprise applications** tab. Search for your application by name and select it. ![Enterprise applications search interface with application list](https://images.workoscdn.com/images/7ca10480-3bc6-4d1e-99cd-7de8543e374d.png?auto=format&fit=clip&q=50) From the Enterprise application page, select the **Users and groups** tab. Click **Add user/group**. ![Enterprise application Users and groups tab with "Add user/group" button](https://images.workoscdn.com/images/15448828-6288-4350-9ac3-27c9997f04e4.png?auto=format&fit=clip&q=50) Select appropriate users and groups to add to the OIDC application. ![User and group assignment interface with selection options and Assign button](https://images.workoscdn.com/images/e3964bfc-92b2-497d-b291-098cbe1ee94f.png?auto=format&fit=clip&q=50) When finished, click **Assign** to add the selected users to your OIDC application. ![Add assignment page with Assign button highlighted](https://images.workoscdn.com/images/80e136c6-6e9f-41f4-aed9-85421746906b.png?auto=format&fit=clip&q=50) --- ## (5) Role assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. Users will automatically be granted the assigned roles within your application when they authenticate. To enable this functionality: ### Configure groups claim in Entra ID From the app registration, navigate to the **Token configuration** page. Click **Add groups claim**. ![Token configuration page with "Add groups claim" button](https://images.workoscdn.com/images/d6342c8f-1f32-43c3-a91e-16cacdd62b31.png?auto=format&fit=clip&q=50) In the **Group Claims** panel, select appropriate groups. For example, you could select **Groups assigned to the application** to only send groups assigned to the OIDC app in Entra ID. Click **Add**. ![Group Claims configuration panel with group selection options](https://images.workoscdn.com/images/5cf70ad4-6eb3-4f6e-87c6-16b15c1c781f.png?auto=format&fit=clip&q=50) ### Configure role assignment in WorkOS From the SSO connection page in the [WorkOS Dashboard](https://dashboard.workos.com/), scroll to the **Groups and role assignments** section. ![WorkOS dashboard highlighting create group button](https://images.workoscdn.com/images/c29ef1a7-d873-49f6-ad43-8c945245a033.png?auto=format&fit=clip&q=50) For each group you want to assign a role, click the **Create group** button and enter the following: 1. Copy the group id from Entra ID into the **IdP Group ID** field. 2. Optionally, enter a group name into the **Name** field. 3. Assign the appropriate role to the group. ![WorkOS dashboard with open create group dialog and idp\_id, name, and role assignment inputs](https://images.workoscdn.com/images/d542c8c3-e032-41a6-ae72-c8dc586ec88d.png?auto=format&fit=clip&q=50) > Group members without an explicit role will receive the default role. --- ## PKCE (Proof Key for Code Exchange) WorkOS supports [PKCE](https://datatracker.ietf.org/doc/html/rfc7636) for OIDC connections, including Entra ID. PKCE adds an additional layer of security to the authorization code flow by preventing authorization code interception attacks. In the **Advanced settings** section of your Entra ID OIDC connection configuration in the WorkOS Dashboard, you can view and manage the PKCE setting. > Only disable PKCE if you encounter issues with your identity provider. Entra ID supports PKCE, and keeping it enabled is strongly recommended for security. --- ## Next steps Your Entra ID OIDC connection is now configured and ready to use. Users assigned to the application in Entra ID will be able to authenticate through WorkOS using their Microsoft credentials. To start using this connection in your application, refer to the [SSO guide](/sso) for implementation details. ### Duo Learn how to configure a connection to Duo via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a Duo SAML Connection, you'll need three pieces of information: an [ACS URL](/glossary/acs-url) (provide by WorkOS), an [SP Entity ID](/glossary/sp-entity-id) (provided by WorkOS), and the [Metadata URL](/glossary/idp-metadata) (provided by Duo). Duo is also unique in that it requires a 3rd party IdP to federate the authentication. This means that along with the three pieces of information, you'll also need to configure a Single Sign-On Authentication Source and a Cloud Application in your Duo Workspace. The high level overview of the authentication flow: Your App → WorkOS → Duo → Your SSO IdP → Duo → WorkOS → Your App ![A flowchart showing the authentication flow of Duo using WorkOS.](https://images.workoscdn.com/docs/integrations/sso/duo-saml/v1/duo-saml-1.png?auto=format&fit=clip&q=50) --- ## (1) Create a new Duo SAML Connection in WorkOS Navigate to the Organization in your WorkOS Dashboard under which you would like to set up this new SSO Connection. Click "Manually Configure Connection" and select Duo SAML from the list of SSO Identity Providers. You'll want to select "Duo SAML" as the Identity Provider and give the Connection a descriptive name. Once this is filled out, click "Create Connection". ![A screenshot showing how to create a Duo SAML connection in the WorkOS dashboard.](https://images.workoscdn.com/images/cfd42823-38c8-4994-b05c-b7c3609d1755.png?auto=format&fit=clip&q=50) Take note of the Connection Details as you'll need to enter those in Duo later on. This page is also where you'll enter the Metadata URL in a later step. ![A screenshot showing where to access Service Provider details in the connection settings.](https://images.workoscdn.com/images/98f72b30-9e6b-4e96-be86-176939471b6b.png?auto=format&fit=clip&q=50) --- ## (2) Select or create your application WorkOS will allow you to use any Duo supported IdP to handle the Federated authentication. Since each IdP will have different ways of setting up the SSO connection between Duo and the IdP, please refer to the [documentation that Duo provides to configure a Duo SSO Connection](https://duo.com/docs/sso#enable-duo-single-sign-on). --- ## (3) Create a Cloud Application in Duo After configuring the Duo SSO Connection with the IdP of your choice, the next step is to create a Cloud Application in Duo. This app will handle the connection between WorkOS and Duo. Navigate to the Duo Admin Panel and click on Applications on the left sidebar. Click "Protect an Application" and locate the entry for "Generic SAML Service Provider" with a protection type of "2FA with SSO hosted by Duo (Single Sign-On)" in the applications list. Click _Protect_ to the far-right to start configuring "Generic SAML Service Provider". ![A screenshot showing how to create a Cloud App in Duo.](https://images.workoscdn.com/images/8404f0a8-a56f-4c58-b03e-d0ec48ef66b8.png?auto=format&fit=clip&q=50) Next, configure the Generic Service Provider settings. There are pieces of information on this page that need to come from WorkOS and your Duo SSO Connection, and also information to copy and enter in the WorkOS Connection. Start by gathering the Metadata URL to enter in the WorkOS Duo SAML Connection that you created in the prior step. ![A screenshot showing where to copy the IdP Metadata URL in Duo.](https://images.workoscdn.com/images/250ed44e-4044-441e-ab02-a045ed011cb2.png?auto=format&fit=clip&q=50) --- ## (4) Enter Duo SAML Settings in your WorkOS Dashboard Navigate to your WorkOS Duo SAML Connection and paste the Metadata URL in to the Metadata field. You won't see the connection flip to Active yet as there is still some configuration to do on the Duo side. ![A screenshot showing how to add the IdP metadata in the WorkOS dashboard.](https://images.workoscdn.com/images/73a827e1-fa4f-4399-a1e6-3589abd0874a.png?auto=format&fit=clip&q=50) From the WorkOS Connection page you are currently on, copy the ACS URL value from the field just above the SAML Settings. ![A screenshot highlighting the ACS URL in the WorkOS dashboard.](https://images.workoscdn.com/images/45ce0799-449b-417e-8f2b-08cdaacdfea6.png?auto=format&fit=clip&q=50) Navigate to the Duo Applications Generic Service Provider configuration settings and paste the ACS URL in the Assertion Consumer Service (ACS) URL field under the Service Provider section. ![A screenshot showing where to input the ACS URL in Duo settings.](https://images.workoscdn.com/images/d7bff970-44e9-4320-b675-53d54d2ab4c9.png?auto=format&fit=clip&q=50) Next, copy the SP Entity ID value from the WorkOS Connection page. ![A screenshot highlighting the Entity ID in the WorkOS dashboard.](https://images.workoscdn.com/images/5dfd097f-1027-48af-9cdc-6ad2fd97f3d3.png?auto=format&fit=clip&q=50) Paste the SP Entity ID into the Entity ID field under the Service Provider section in the Duo Applications Generic Service Provider configuration. You may leave the Single Logout URL, Service Provider Login URL, and Default Relay State fields empty. ![A screenshot showing where to input the Entity ID in Duo settings.](https://images.workoscdn.com/images/5938b3ee-95a7-4dcf-aa2a-9e064d8c8311.png?auto=format&fit=clip&q=50) Scroll down on this page to the SAML Response section. Ensure that the NameID format has the id that you'd like to use for the unique identifier selected and matches the NameID attribute that you'd like to use as the value. If you're using email as the unique ID, the options would look like the below. ![A screenshot showing how to configure SAML Response NameID in Duo.](https://images.workoscdn.com/images/e2ae9786-2a3f-4408-9c15-b33ba4c34f39.png?auto=format&fit=clip&q=50) Ensure the Signature algorithm is SHA256 and that the Signing options have both Sign response and Sign assertion selected. ![A screenshot showing where to configure the SAML Response Signing.](https://images.workoscdn.com/images/c491cab0-5abe-4b63-89cc-c5b8dbed9657.png?auto=format&fit=clip&q=50) Next make sure that you are mapping the attributes which WorkOS requires: `id`, `email`, `firstName`, and `lastName`. In the Map Attributes section enter these on the right side under SAML Response Attribute. on the left side, click the empty field box and select the pre-populated values that look like ``. Duo will automatically grab the corresponding fields and map them to the expected values. You can map any values you like, but WorkOS requires that these four values are included in SAML responses. If your users don't have a last name value for instance, you could map Display Name or any other value to `lastName`, but `lastName` still needs to be included or WorkOS will reject the SAML Response. Here's an example of the attribute mappings: ![A screenshot showing where to configure SAML Attribute Mapping in Duo.](https://images.workoscdn.com/images/dc4517d1-7f02-4199-a06e-e3d31ac56b76.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, follow the guidance below. In the "Role Attributes" section, enter `groups` as the "Attribute name". Then map the role names to their corresponding Duo groups. In the example below, the "Admins" role is mapped to the Admins group and the "Developers" role is mapped to the Developers group. ![A screenshot showing how to configure a groups attribute in Duo.](https://images.workoscdn.com/images/a13b9af3-65fc-4595-acd6-ecc3bc026fc3.png?auto=format&fit=clip&q=50) > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. ### Save your changes You may leave all of the other fields as their defaults. Scroll to the very bottom of the page and click the Save button. ![A screenshot highlighting the finished SAML Configuration in Duo.](https://images.workoscdn.com/images/dbe959a3-41eb-4dca-b1bd-69f1a389b10e.png?auto=format&fit=clip&q=50) --- ## (5) Verify Connection Status in WorkOS Navigate back to the WorkOS dashboard. After a minute or two you should see the Connection become Active as indicated by the green badge next to the connection name. ![A screenshot highlighting active status of the Duo connection.](https://images.workoscdn.com/images/9d79fcfe-386d-4bd7-a69d-e8e0578f0352.png?auto=format&fit=clip&q=50) ### CyberArk SCIM Learn about syncing your user list with CyberArk SCIM. ## Introduction This guide outlines how to synchronize your application's CyberArk directories using SCIM. To synchronize an organization's users and groups provisioned for your application, you'll need to provide the organization with two pieces of information: - An [Endpoint](/glossary/endpoint) that CyberArk will make requests to. - A [Bearer Token](/glossary/bearer-token) for CyberArk to authenticate its endpoint requests. After completing step 1 below, both of these are available in your Endpoint's Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). > The rest of the steps below will need to be carried out by the organization when configuring your application in their CyberArk instance. --- ## (1) Set up your directory in the WorkOS Dashboard In your WorkOS Dashboard, select or create an Organization. Then select "Manually Configure Directory". ![A screenshot showing where to select "Manually Configure Directory" in the WorkOS dashboard.](https://images.workoscdn.com/images/2865e608-6524-4bd6-8f35-070de0d6cf2b.png?auto=format&fit=clip&q=50) Select "CyberArk" as the Directory Provider and add a descriptive name for the directory sync connection. ![A screenshot showing the proper configuration of the "Create Directory" modal in the WorkOS dashboard.](https://images.workoscdn.com/images/ea86a861-c18c-4d8b-ad92-5942f11a98c7.png?auto=format&fit=clip&q=50) On the Directory Sync connection settings page, save the Endpoint and the Bearer Token. You'll input these in the CyberArk settings. ![A screenshot showing the Endpoint and Bearer Token in the WorkOS dashboard.](https://images.workoscdn.com/images/f77f41f5-8641-4452-b933-3a2d3f2351c5.png?auto=format&fit=clip&q=50) > We have support for whitelabeled URLs for Directory Sync endpoints. [Contact us](mailto:support@workos.com) for more info! --- ## (2) Select or create your CyberArk application CyberArk supports SCIM provisioning in the context of a SAML app. The usual set up is to enable SAML first, following [our docs here](/integrations/cyberark-saml). Log in to the CyberArk Admin Portal, and navigate to your SAML app. Open the "Provisioning" tab, and select the box to "Enable provisioning for this application". ![A screenshot showing where to enable the "Enable provisioning for this application" setting in the CyberArk dashboard.](https://images.workoscdn.com/images/83b18d01-90d6-4cf2-8866-84c2046cd1f5.png?auto=format&fit=clip&q=50) Click "Yes" in the confirmation modal. ![A screenshot showing where to select "Yes" in the confirmation modal in the CyberArk dashboard.](https://images.workoscdn.com/images/38f35897-4fb6-47d0-9445-53b0405b8809.png) Enter the Endpoint from the WorkOS Dashboard into the "SCIM Service URL" field, and enter the Bearer Token from the WorkOS Dashboard into the corresponding field in the Provisioning tab. Select "Verify" to save these credentials. ![A screenshot showing where to input the WorkOS Endpoint as the "SCIM Service URL" and the Bearer Token in the CyberArk dashboard.](https://images.workoscdn.com/images/2bee64a8-cbb8-4d31-9f35-4f2bb3c237bd.png) Once the credentials have been verified, more options will be appear below. Deselect "Do not de-provision (deactivate or delete) users in target application" as seen below. ![A screenshot showing which checkboxes to disable in the CyberArk dashboard.](https://images.workoscdn.com/images/f8e6980a-76f7-4cf5-a5c5-958dae8268ba.png) --- ## (3) Configure your role mappings in CyberArk Users assigned to the SAML app will be synced, and roles mapped will be synced as groups. The roles are mapped on the Provisioning settings page, by selecting the "Add" button. ![A screenshot showing where to select "Add" in the CyberArk dashboard.](https://images.workoscdn.com/images/8a6039da-ccc0-493d-9888-40337e70da74.png) In the role mapping modal, select the role you'd like to map, and then create a destination group. The name will be what you see as the group name in directory sync. All users assigned to that role will be members of the mapped group. Select "Done". ![A screenshot showing how to configure the "Role" and "Destination Group" settings in the "Role Mapping" modal of the CyberArk dashboard.](https://images.workoscdn.com/images/34f5f6cf-5011-4540-a911-d68d583e8411.png) After the role mapping is completed, click "Save". The SCIM configuration part of the setup is complete. --- ## (4) Trigger the directory sync run in CyberArk In CyberArk, navigate to the Settings → Users → Outbound Provisioning page. Under Synchronizations, start the sync. You can also set up scheduled syncs here. ![A screenshot showing where to select "Start Sync" in the "Outbound Provisioning" settings in the CyberArk dashboard.](https://images.workoscdn.com/images/fe15e2da-4312-4b22-9750-6d9657d569f2.png) In the CyberArk SCIM directory in the WorkOS dashboard, select the "Users" tab and you will now see the users and groups synced over. ![A screenshot showing the populated "Users" tab in the CyberArk SCIM directory in the WorkOS dashboard.](https://images.workoscdn.com/images/fd7f1d1b-4390-44e5-9aa6-95308d911829.png) A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) ## Frequently asked questions ### When a group is removed, I don't see a `dsync.group.deleted` or `dsync.group.user_removed` events - is this expected? Instead of individually assigning users to a SCIM application, CyberArk SCIM requires that users are assigned to the application through group membership. It is a known issue with CyberArk SCIM that when a group is removed from the app, no indication is received that the group has changed. The users of the group must be cleaned up before the group itself is removed from the SCIM application. ### CyberArk SAML Learn how to configure a connection to CyberArk via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a CyberArk SAML Connection, you'll need the Identity Provider metadata that is available from your CyberArk instance. --- ## What WorkOS provides The first thing you'll need to do is create a new CyberArk SAML connection in your [WorkOS dashboard](https://dashboard.workos.com/). Start by logging in to your WorkOS dashboard and browse to the "Organizations" tab on the left hand navigation bar. Select the organization you'd like to configure a CyberArk SAML Connection for, and then click "Manually Configure Connection". ![A screenshot showing where to select "Manually Configure Connection" in the WorkOS dashboard.](https://images.workoscdn.com/images/72c85573-ffe7-4be4-8fe1-2ea60db0c77a.png?auto=format&fit=clip&q=50) Select "CyberArk SAML" as the Identity Provider, give the Connection a descriptive name, and click "Create Connection". ![A screenshot showing the "Create Connection" modal in the WorkOS dashboard.](https://images.workoscdn.com/images/d5ef1aab-8d6d-47ff-9af8-ae237ed31440.png?auto=format&fit=clip&q=50) WorkOS provides the [ACS URL](/glossary/acs-url) and [SP Entity ID](/glossary/sp-entity-id). They are readily available in your Connection Settings in the [WorkOS dashboard](https://dashboard.workos.com/). ![A screenshot showing where to locate the "ACS URL" and "SP Entity ID" in the WorkOS dashboard.](https://images.workoscdn.com/images/d443909c-712a-4084-9ac8-2b47f560a6fa.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. In CyberArk's case, it needs to be set by the organization when configuring your application in their CyberArk instance. The SP Entity ID is a URI used to identify the issuer of a SAML request and the audience of a SAML response. In this case, the SP Entity ID is used to communicate that WorkOS will be the party performing SAML requests to the organization's CyberArk instance, and that WorkOS is the intended audience of the SAML responses from the CyberArk instance. Specifically, the ACS URL will need to be set as the "Assertion Consumer Service (ACS) URL", and the SP Entity ID will need to be set as the "SP Entity Id / Issuer / Audience", in the "Service Provider Configuration" section of the "Trust" tab in the SAML App. ![A screenshot showing where to input the WorkOS ACS URL and SP Entity ID in the "SP Entity ID" and "ACS URL" fields in the CyberArk dashboard.](https://images.workoscdn.com/images/bb1b0fe6-0e13-4c45-8bfd-fd0b4d9dc028.png?auto=format&fit=clip&q=50) --- ## What you'll need Next, provide the Identity Provider metadata. Normally, this information will come from the organization's IT Management team when they set up your application's SAML configuration in their CyberArk Identity Admin Portal. If that's not the case during your setup, the following steps describe how to get the necessary information. --- ## (1) Log in Log in to the [CyberArk Identity Admin Portal](https://pod0.idaptive.app/my) and select "Web Apps" from the left-side navigation. ![A screenshot showing where to select 'Web Apps" in the CyberArk dashboard.](https://images.workoscdn.com/images/1e496ecf-4948-4161-8d0e-7dd085d1cc74.png?auto=format&fit=clip&q=50) --- ## (2) Select or create your application If your application is already created, select it from the list of applications and move to Step 4. If you haven't created a SAML application in CyberArk, select "Add Web Apps". ![A screenshot showing where to select "Add Web Apps" in the CyberArk dashboard.](https://images.workoscdn.com/images/034f7256-e5d1-40bf-a258-4532ba462966.png?auto=format&fit=clip&q=50) Select the "Custom" tab and then click to add "SAML". ![A screenshot showing how to select the "SAML" web application type in the CyberArk dashboard.](https://images.workoscdn.com/images/48709bed-91f5-4549-8fec-3766ca10b5ee.png?auto=format&fit=clip&q=50) Select "Yes" to begin setting up the SAML App. ![A screenshot indicating to select "Yes" in the confirmation to add the new application in the CyberArk dashboard.](https://images.workoscdn.com/images/2877ea73-3e8b-4370-9dd2-b3a64ea8990a.png?auto=format&fit=clip&q=50) --- ## (3) Initial SAML Application Setup Enter a descriptive App Name and Description, then click "Save". ![A screenshot showing how to populate the "Name" and "Description" fields in the CyberArk dashboard.](https://images.workoscdn.com/images/bb5bf913-edae-4286-9a72-20eaa12ca1e7.png?auto=format&fit=clip&q=50) Next, navigate to the "Trust" tab and enter the SP Entity ID from the Connection Settings into "SP Entity Id / Issuer / Audience" and the ACS URL from the Connection Settings into "Assertion Consumer Service (ACS) URL" in the "Service Provider Configuration" section of the "Trust" tab in the SAML App. > IMPORTANT: Be sure to check "Both" under "Sign Response or Assertion?". ![A screenshot showing where to input the WorkOS ACS URL and SP Entity ID in the "SP Entity ID" and "ACS URL" fields in the CyberArk dashboard.](https://images.workoscdn.com/images/bb1b0fe6-0e13-4c45-8bfd-fd0b4d9dc028.png?auto=format&fit=clip&q=50) --- ## (4) Configure Attribute Mapping Select the "SAML Response" tab and use the "Add" button to add the following key-value pairs. Then, click "Save". - `id` → `LoginUser.Uuid` - `email` → `LoginUser.Email` - `firstName` → `LoginUser.FirstName` - `lastName` → `LoginUser.LastName` ![A screenshot showing the "SAML Response" tab successfully configured in the CyberArk dashboard.](https://images.workoscdn.com/images/63c47f86-6205-4c23-b4b2-1c2950d94fe7.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, first add a new attribute in the "SAML Response" tab. In the "Attribute Name" column, input `groups`, and map it to the "Attribute Value" for a user's group membership, such as `LoginUser.GroupNames`, as shown in the example below. ![A screenshot showing the groups attribute successfully configured in CyberArk.](https://images.workoscdn.com/images/e5b30513-3915-46a3-b876-650898f8f288.png?auto=format&fit=clip&q=50) Once your SAML app is configured to return groups, navigate to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (5) Add Users to SAML Application To give users permission to authenticate via this SAML app, you will need to assign individual users and/or groups of users to the CyberArk SAML app. Click on the "Permissions" tab, and select "Add". ![A screenshot showing where to select "Add" in the "Permissions" tab of the application in the CyberArk dashboard.](https://images.workoscdn.com/images/473838e4-cf5f-4feb-a577-f167ac907f01.png?auto=format&fit=clip&q=50) Search for the individual user(s) and/or group(s) that you would like to assign to the app, and check the box next to them. Click "Add" when you are finished. Once users have been successfully added, you should also notice the "Status" of your CyberArk SAML app change to "Deployed". ![A screenshot showing the selection of a user to add to the SAML application in the CyberArk dashboard.](https://images.workoscdn.com/images/a09d23b6-5eb7-4fdf-999b-fff77159d43c.png?auto=format&fit=clip&q=50) --- ## (6) Copy Metadata On the "Trust" tab of the SAML App, go to the "Service Provider Configuration Section" and select "Metadata". Then click on "Copy URL" button to copy the Metadata URL. This URL will get entered in the WorkOS dashboard in the next step. ![A screenshot showing where to obtain the "Metadata URL" in the CyberArk dashboard.](https://images.workoscdn.com/images/5da3432f-1105-44f1-9433-d1002d1c832d.png?auto=format&fit=clip&q=50) --- ## (7) Provide Metadata Finally, select "Edit Metadata Configuration" and input the Metadata URL in your WorkOS Connection Settings. Your Connection will then be verified and good to go! ![A screenshot showing where to select "Edit Metadata Configuration" in the "Identity Provider Configuration" in the WorkOS dashboard.](https://images.workoscdn.com/images/bedce7fc-3dcd-468d-ab31-1e65f8f14cb9.png?auto=format&fit=clip&q=50) ### Cloudflare Learn how to configure a connection to Cloudflare via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a Cloudflare SAML Connection, you'll need to manually enter the SSO URL, [IdP Entity ID](/glossary/idp-uri-entity-id), and X.509 Certificate obtained from your Cloudflare instance. Instructions on where to obtain these will be covered in this guide. --- ## What WorkOS provides The first thing you'll need to do is create a new Cloudflare SAML connection in your [WorkOS Dashboard](https://dashboard.workos.com/). Start by logging in to your WorkOS dashboard and browse to the "Organizations" tab on the left hand navigation bar. Select the organization you'd like to configure a Cloudflare SAML Connection for, and from the dropdown menu select "Add Connection". ![A screenshot showing how to add an SSO connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/685a5cfc-14f2-44b9-95de-3b6af1c1b4b1.png?auto=format&fit=clip&q=50) Select "Cloudflare SAML" as the Identity Provider and give the Connection a descriptive name. Once this is filled out, click "Create Connection". ![A screenshot showing how to create a Cloudflare SAML Connection.](https://images.workoscdn.com/images/bb5d99c0-0f69-4ef6-b67d-654dd2311745.png?auto=format&fit=clip&q=50) WorkOS provides the [ACS URL](/glossary/acs-url) and the [SP Entity ID](/glossary/sp-entity-id). These are available in your Connection's Settings in the Developer Dashboard. ![A screenshot showing where to find the Service Provider details in the WorkOS Dashboard.](https://images.workoscdn.com/images/bea6f73d-6dae-452b-be22-f22861c9497c.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. In Cloudflare's case, it needs to be set by the organization when configuring the application in the Cloudflare instance. The SP Entity ID is a URI used to identify the issuer of a SAML request. In this case, the entity ID is used to communicate that WorkOS will be the party performing SAML requests to the organization's Cloudflare instance. --- ## What you'll need Cloudflare SAML is a unique integration in that it sits between WorkOS and the Identity Provider. This allows for additional rules to be configured, but also means there are two connections that need to be made. The first necessary connection is between Cloudflare and the IdP, and the second connection is between WorkOS and Cloudflare. --- ## (1) Connect Cloudflare with your Identity Provider First, create the connection between Cloudflare and the Identity Provider. Cloudflare Access allows you to connect with any IdP that supports a SAML 2.0 connection. Follow the [documentation from Cloudflare](https://developers.cloudflare.com/cloudflare-one/identity/idp-integration/generic-saml) to configure a SAML application connection between Cloudflare and your IdP. The one deviation from the Cloudflare documentation is that the SAML attributes must include `email`, `firstName`, `lastName`, and `id`. Email is included by default as the "Email attribute name", but you will need to add the other three as SAML attributes. When setting up the connection, be sure to enter `email`, `firstName`, `lastName`, and `id` as SAML attributes. ![A screenshot showing how to configure SAML attributes in Cloudflare Access.](https://images.workoscdn.com/images/57473539-2c40-4c16-b59b-471cbdce1764.png?auto=format&fit=clip&q=50) Save the connection and then click the "Test" button. When successful, you will see a success screen including your `saml_attributes` that have been added. ![A screenshot showing a successful test of Cloudflare Access.](https://images.workoscdn.com/images/bd575c26-8d01-4e12-8e7e-70198da3e33d.png?auto=format&fit=clip&q=50) --- ## (2) Add an Application in Cloudflare Access Next, create the connection between Cloudflare and WorkOS. From the Cloudflare Zero Trust dashboard Access menu, select "Applications", then "Add an application". ![A screenshot showing where to add an application in Cloudflare Access.](https://images.workoscdn.com/images/ae6525fa-194c-44f5-a20b-f6ea14667ec2.png?auto=format&fit=clip&q=50) Select "SaaS" for the type of application. ![A screenshot highlighting the SaaS application type in Cloudflare.](https://images.workoscdn.com/images/9202ac92-d1b7-4ad7-9c2d-486528e8edcb.png?auto=format&fit=clip&q=50) Copy the ACS URL and Entity ID from the Connection Settings in your WorkOS Dashboard. ![A screenshot showing where to find the Service Provider details in the WorkOS Dashboard.](https://images.workoscdn.com/images/bea6f73d-6dae-452b-be22-f22861c9497c.png?auto=format&fit=clip&q=50) Select the name of your application from the dropdown menu. If your application is not listed, type the name to save it. Paste the ACS URL and SP Entity ID to the corresponding fields in Cloudflare. Then select the Name ID Format that you would like to use for this application. For this example we'll use Unique ID. ![A screenshot showing where to input Service Provider details into the Cloudflare application.](https://images.workoscdn.com/images/2417371c-2a7d-41e7-a98b-295461e1741f.png?auto=format&fit=clip&q=50) --- ## (3) Configure Attribute Mapping Now, Configure the attribute statements. WorkOS requires that `email`, `firstName`, `lastName`, and `id` be included. Cloudflare automatically sends `id` and `email`, so you only need to add `firstName` and `lastName`. These attributes were configured in Step 1, and the mapped values are the same here. Add `firstName` and `lastName` to both the right and left sides of the SAML attribute statements. ![A screenshot showing where to configure Cloudflare attribute mapping.](https://images.workoscdn.com/images/6d0a7e54-e912-4cb7-8688-427d595d30e6.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information, add a new attribute statement with `groups` as the "Name" and map it to the "IdP attribute" for `groups`, as shown in the example below. ![A screenshot showing how to configure a groups attribute in Cloudflare.](https://images.workoscdn.com/images/659df99d-79b9-4fd4-bcec-69b337504cfe.png?auto=format&fit=clip&q=50) #### Resolving groups attribute issues If you're having issues getting the `groups` attribute to come through, it's possible that Cloudflare is sending it as a nested structure, specifically an array of group objects rather than plain strings. WorkOS expects `groups` to be a top-level attribute where each value is a simple string, such as the group name or ID. To resolve this, go to the **Advanced Settings** section of your Cloudflare Access application and define a [JSONata transformation](https://developers.cloudflare.com/cloudflare-one/applications/configure-apps/saas-apps/generic-saml-saas/#jsonata-transforms) to map the structured `groups` attribute into the expected format. For example, to extract the `name` from each group object, use the following transformation: `$ ~> | $ | { "groups": groups.name } |` ![A screenshot showing JSONata transform applied to the groups attribute](https://images.workoscdn.com/images/3be403b4-26a1-40b6-a64e-3503f6f69a21.png?auto=format&fit=clip&q=50) This will transform an input like: ```json { "groups": [ { "name": "Engineering", "id": "abc123" }, { "name": "Finance", "id": "def456" } ] } ``` Into the expected format: ```json { "groups": ["Engineering", "Finance"] } ``` You may also use groups.id if you prefer to map group IDs instead. > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. --- ## (4) Finish SSO Application Configuration Select the Identity Provider that you are using from the list. In this example we are using an Okta SAML connection. ![A screenshot highlighting where to select the Identity Provider in the Cloudflare application.](https://images.workoscdn.com/images/0f4ea850-5111-4659-a67f-8887cde842dd.png?auto=format&fit=clip&q=50) Configure at least one policy and one rule, then click next. For this example the Policy sets the session length to 30 minutes for everyone. ![A screenshot showing where to configure policy and rules for the Cloudflare application.](https://images.workoscdn.com/images/c6141486-5b88-47e5-88d8-161294698ece.png?auto=format&fit=clip&q=50) --- ## (5) Copy Connection Credentials The SSO endpoint, Entity ID, and Public key (X.509 certificate) all will be entered in the Connection details in the [WorkOS Dashboard](https://dashboard.workos.com/). The SSO endpoint and Entity ID can be entered as-is, but the Public Key needs to be formatted as an X.509 certificate. ![A screenshot showing where to copy the connection credentials from the Cloudflare dashboard.](https://images.workoscdn.com/images/81f19129-0b22-4f78-b238-e9b087a3a52b.png?auto=format&fit=clip&q=50) To format the Public Key, copy the value to a text editor and add the following header and footer to the Public Key. Ensure there are no spaces above or below the Key value, then save with the file extension ".cert". ```shell title="Certificate format" -----BEGIN CERTIFICATE----- -----END CERTIFICATE----- ``` The format of the file should look like this when you're finished. ```shell title="Completed Certificate Format" -----BEGIN CERTIFICATE----- MIIDUTCCAjmgAwIBAgIRAN557boQ2ZxW4Ww08cZYK2IwDQYJKoZIhvcNAQELBQAw YjELMAkGA1UEBhMCVVMxDjAMxxxxxAgTBVRleGFzMQ8wDQYDVQQHEwZBdXN0aW4x EzARBgNVBAoTCkNsb3VkZmxhcmUxHTAbBgNVBAMTFGNsb3VkZmxhcmVhY2Nlc3Mu Y29tMB4XDTxxxxxwMjE5MzMxM1oXDTMyMDIwMjE5MzMxM1owYjELMAkGA1UEBhMC VVMxDjAMBgNVBAgTBVRleGFzMQ8wDQYDVQQHEwZBdXN0aW4xEzARBgNVBAoTCkNs b3VkZmxhcmUxHTAbBgNVBAMTFGNsb3VkZmxxxxxhY2Nlc3MuY29tMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA49p6jXzk65DeG4DI2NgW0UOOJrd+9qYS OCuBYq/e4IqSeqchsm1JDY9MjB6xmiw+urC1qWuj0MS4dwAJQwiGFbCGDh5m4FAF mZm5VaMkW5Q+MG5zXRfeLmhvLuT0XVBcDlkwPC3k28/moKi1KlwPcujLF43+rf2d 8Rm6ZNCJgfVzRxxxxxPd5NGpNlEZ0ViPXM1gsO15/1Iginevv+xKqRTx0vMsNLWJ BwWLAAqm5b6U9XQefwy9lPqPywFwCuZEMXwI9Rpm0f2xmOK56EudtdSkQ1JtSgYX x9rf/97NfP8wI2x1IncQtwdWNdW5cvxMqYU/Za6WZvjNCnpFQGXLJQIDAQABowIw ADANBgkqhkiG9w0BAQsFAAOCAQEARZ0h2ZeNXSme0EbQeJfEFOX+mj9rPkHIJFfQ G7+dRG6DwDubxG56TsvUINcJX8O5C6oQ0T6dRutO/jG5LxJqmCz5wLUTA/6/YLDk 95gbYyJ/yfLm4sd6DEoXzWSld+EZ5b86pxFnvR/+cPY2tcSghQ+moZKR5THwHLsZ hie2Pr6UVvuS5D9BC4ijR+cPyB5r4qliI9C1p8phuZctoX9dPpFY+UwkWgUDx9sz UXFJsqueoibxfVqh4Jzdw+2XH6xN3WvTdJN4Sh1fqEpBeOxxxxxlRrCAJiMnLtG6 QgHF9ZnNRbIFcUHF/lyWY3oxcvgeUwEnE5QVVbdoMMGKKgffbQ== -----END CERTIFICATE----- ``` --- ## (6) Provide Connection Credentials Navigate to the Connection in your Developer Dashboard. Enter the SSO endpoint in the [IdP SSO URL](/glossary/idp-sso-url) field and enter the "Access Entity ID or Issuer" value into the "IdP URI (Entity ID)" field. Upload the file that you saved for the X.509 certificate to the "Add an X.509 Certificate" field. Click Save Configuration. ![A screenshot showing where upload the Metadata configuration details.](https://images.workoscdn.com/images/2d149107-fbc3-4e09-a644-b68dc5ff151b.png?auto=format&fit=clip&q=50) Your Connection will then be Active and good to go! ### Clever OIDC Learn how to configure a connection to Clever via OIDC. ## Introduction Each SSO identity provider requires specific information to create and configure a new [SSO connection](/glossary/connection). Often, the information required to create an SSO connection will differ by identity provider. To create a Clever OIDC SSO connection, you'll need three pieces of information: a [redirect URI](/glossary/redirect-uri), [client ID](/glossary/client-id), and [client secret](/glossary/client-secret). Start by logging into your WorkOS dashboard and navigate to the **Organizations** page from the left-hand navigation bar. Select the organization you'd like to configure a Clever OIDC SSO connection for, and select **Configure manually** under **Single Sign-On**. ![WorkOS Dashboard Organizations tab with "Configure manually" button highlighted](https://images.workoscdn.com/images/d577cfbe-028b-48cf-8cc0-4cd5d3adf853.png?auto=format&fit=clip&q=50) Select **Clever OIDC** from the identity provider dropdown. Click **Create Connection**. ![Create Connection form with Clever OIDC selected as Identity Provider](https://images.workoscdn.com/images/2a5545f1-70ea-4347-8d99-a39c5850085c.png?auto=format&fit=clip&q=50) --- ## What WorkOS provides WorkOS provides the Redirect URI, which can be found in the **Service Provider Details** section on the SSO connection page in the [WorkOS Dashboard](https://dashboard.workos.com/). - [Redirect URI](/glossary/redirect-uri): The endpoint where identity providers send authentication responses after successful login ![The Redirect URI of a OIDC connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/062a78e9-1d87-4643-890f-ebd1221e645b.png?auto=format&fit=clip&q=50) The Redirect URI is the location an identity provider redirects its authentication response to. In Clever's case, it needs to be added to the OAuth settings in the Clever admin as outlined in [step 1](/integrations/clever-oidc/1-configure-the-redirect-uri). --- ## What you'll need You will need to obtain two pieces of information from the organization: - [Client ID](/glossary/client-id): Application identifier from the OIDC provider - [Client secret](/glossary/client-secret): Authentication secret for the application Typically, this information comes from the organization's IT team when they set up your application's OIDC configuration in their Clever admin dashboard. However, if that's not the case during your setup, the next steps will show you how to obtain it. --- ## (1) Configure the Redirect URI Sign in to [Clever](https://apps.clever.com/). In the left navigation bar, select the **Settings** tab. In the horizontal menu, select the **Integration** tab. Locate the **OAuth Settings** section and click **Edit**. ![Setting the redirect URI in the Clever admin dashboard](https://images.workoscdn.com/images/0f7a4169-8cf1-4239-9d03-9f2022fb6a88.png?auto=format&fit=clip&q=50) The **Update OAuth Settings** dialog will open. Copy the [Redirect URI](/integrations/clever-oidc/what-workos-provides) from the SSO connection page in the WorkOS Dashboard into the **REDIRECT URIS** field. Click **Save**. --- ## (2) Obtain configuration details While on the **Settings** tab in Clever, select the **General** tab in the horizontal menu. After creating an application, a client ID and client secret are provisioned. Locate the **CLIENT ID** and **CLIENT SECRET** fields and copy the values. ![Copying the client id and secret from the Clever admin dashboard](https://images.workoscdn.com/images/b4c527e1-0335-428e-a658-ef3ecfd820a3.png?auto=format&fit=clip&q=50) Back in the [WorkOS Dashboard](https://dashboard.workos.com/) on the SSO connection page, enter the client ID and client secret you obtained from Clever into the respective fields in the **Settings** section. ![WorkOS Dashboard Settings with Client ID and Client Secret fields](https://images.workoscdn.com/images/d7ebf399-4cc9-4588-9961-6160d6bbd9bf.png?auto=format&fit=clip&q=50) Click **Update connection** to save. --- ## (3) Test Single Sign-On Test signing in to verify that the single sign-on connection was configured correctly. From the SSO connection page in the WorkOS Dashboard, click **Test SSO** to initiate a test authentication flow. --- ## Next steps Your Clever OIDC connection is now configured and ready to use. Users assigned to the application in Clever will be able to authenticate through WorkOS using their Clever credentials. To start using this connection in your application, refer to the [SSO guide](/sso) for implementation details. ### ClassLink Learn how to configure a connection to ClassLink via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a ClassLink SAML Connection, you'll need the Identity Provider Metadata URL that is available from the organization's ClassLink SAML instance. Start by logging in to your WorkOS dashboard and browse to the "Organizations" tab on the left hand navigation bar. Select the organization you'd like to configure a ClassLink SAML Connection for, and select "Manually Configure Connection" under "Identity Provider". ![A screenshot showing the "Manual Configure Connection" option in the WorkOS Dashboard.](https://images.workoscdn.com/images/fe7f0470-1d95-4708-b364-6dfea9e94e59.png?auto=format&fit=clip&q=50) Select "ClassLink SAML" from the Identity Provider dropdown, enter a descriptive name for the connection, and then select the "Create Connection" button. ![A screenshot showing a ClassLink connection being created in the WorkOS Dashboard.](https://images.workoscdn.com/images/20fabb8d-91a2-4f7d-965f-837f886a8481.png?auto=format&fit=clip&q=50) --- ## What WorkOS provides WorkOS provides the [ACS URL](/glossary/acs-url), the [SP Metadata](/glossary/sp-metadata) link and the [SP Entity ID](/glossary/sp-entity-id). They are readily available in your Connection Settings in the [Developer Dashboard](https://dashboard.workos.com/). The SP Metadata link contains a metadata file that the organization can use to set up the SAML integration. ![A screenshot showing the Service Provider Details provided by WorkOS for a ClassLink connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/46a922ac-10d2-424a-9b10-762702f8fc05.png?auto=format&fit=clip&q=50) --- ## What you'll need In order to integrate you'll need the [IdP Metadata URL](/glossary/idp-metadata). Normally, this will come from the organization's IT Management team when they set up your application's SAML 2.0 configuration in their ClassLink instance. Here's how to obtain them: --- ## (1) Select or create your application Login to the ClassLink Management Console (CMC), click Single Sign-On and select SAML Console. Click ADD NEW or COPY EXISTING. Copy Existing contains pre-configured SAML apps which need to be updated to fit your unique settings. ![A screenshot showing where to select "Add Application" in the ClassLink console.](https://images.workoscdn.com/images/2adb6c82-eeb2-4fee-9eb1-cd1655d08e35.png?auto=format&fit=clip&q=50) --- ## (2) Initial SAML Application Setup Edit the new application by click the three dots menu icon, and then selecting Edit. ![A screenshot showing where to edit the ClassLink application.](https://images.workoscdn.com/images/70877547-fcac-40ec-a98f-87f5333ad59f.png?auto=format&fit=clip&q=50) Update the Metadata URL in the ClassLink application settings with the SP Metadata URL provided to you by WorkOS. ![A screenshot showing where to enter the SP Metadata URL in the ClassLink application settings.](https://images.workoscdn.com/images/d97393b1-5066-4f48-a6e4-bb5cf1a2c6c8.png?auto=format&fit=clip&q=50) --- ## (3) Configure SAML Application Under the "Attribute Mapping" section of the SAML app, map the following four attributes as shown below, and the select "Update". - `id` → `Login id` - `email` → `Email` - `firstName` → `Given Name` - `lastName` → `Family Name` ![A screenshot showing how to input user attribute mapping in the ClassLink dashboard.](https://images.workoscdn.com/images/a6f3d9da-cb06-4eda-a243-f3fb84f9df76.png?auto=format&fit=clip&q=50) ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, map the groups in your identity provider to a SAML attribute named `groups`. > Finish role assignment set-up by navigating to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. ## (4) Upload Metadata URL Copy the IdP Metadata URL from your ClassLink SAML settings and upload it to your WorkOS Connection settings. ![A screenshot highlighting where the ClassLink Metadata URL is located in the ClassLink console.](https://images.workoscdn.com/images/a75ed9fa-3b21-469b-93e4-3b8483da3717.png?auto=format&fit=clip&q=50) In the Connection settings in the WorkOS Dashboard, click "Edit Metadata Configuration". ![A screenshot highlighting the "Edit Metadata Configuration" button in a Connection details view in the WorkOS Dashboard.](https://images.workoscdn.com/images/c03dd1dc-84b3-4909-bee5-61249280e35f.png?auto=format&fit=clip&q=50) Paste the Metadata URL from ClassLink into the "Metadata URL" field and select "Save Metadata Configuration". ![A screenshot showing how to input the Metadata URL into the Connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/88884c90-bb7d-4f18-9a7c-bb7c7ad1fee2.png?auto=format&fit=clip&q=50) Your Connection will then be linked and good to go! ### Cezanne HR Learn about syncing your user list with Cezanne HR. ## Introduction This guide outlines how to synchronize your application's Cezanne HR directories. To synchronize an organization's users and groups provisioned for your application, you'll need the following information from the organization: - Cezanne HR Client ID - Cezanne HR Client Secret > Note: The Cezanne HR integration isn't enabled by default in the WorkOS Dashboard or Admin Portal. Please reach out to [support@workos.com](mailto:support@workos.com) or via your team's WorkOS Slack channel if you would like Cezanne HR enabled. --- ## (1) Set up your Directory Sync Connection Login to your WorkOS Dashboard and select "Organizations" from the left hand navigation bar. Select the organization you'll be configuring a new Directory Sync Connection with. Click "Manually Configure Connection". ![A screenshot showing where to find "Manually Configure Directory" button for an organization in the WorkOS dashboard.](https://images.workoscdn.com/images/e65f54ae-6010-4492-a838-8583dc614e50.png?auto=format&fit=clip&q=50) Input the Name, and select "Cezanne HR" as the directory type. Click the "Create Directory" button. ![A screenshot showing "Create Directory" details in the WorkOS dashboard.](https://images.workoscdn.com/images/1217ac5a-6d04-4783-8ce5-b005c14aa005.png?auto=format&fit=clip&q=50) You will now see your Cezanne HR directory sync has created successfully with an input for the Client ID and Client Secret --- ## (2) Obtain a Cezanne HR Client ID and Client Secret To obtain these credentials, you will need to request a new API Application from the Cezanne HR Support Team. --- ## (3) Enter the details in the Directory's detail page Click "Update Directory". There are two fields to enter, the Client ID and Client Secret that Cezanne support provided for you. ![A screenshot showing where to find the "Update Directory" button in the WorkOS dashboard.](https://images.workoscdn.com/images/1b94ab4a-b001-47ea-a89f-548011881ff0.png?auto=format&fit=clip&q=50) --- ## (4) Sync Users and Groups to Your Application When the connection is successfully made, you will see the green "Linked" icon appear. Now, whenever the organization assigns users or groups to your application, you'll receive Dashboard updates based on changes in their directory. Click on the "Users" tab in the Dashboard to view synced users. ![A screenshot showing where to find the "Users" tab in the WorkOS directory.](https://images.workoscdn.com/images/ed0393d9-84de-416b-8410-b5596e091d67.png?auto=format&fit=clip&q=50) A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) ## Frequently asked questions ### How often do Cezanne HR directories perform a sync? Cezanne HR directories poll every 30 minutes starting from the time of the initial sync. ### CAS SAML Learn how to configure a connection to CAS via SAML. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a CAS SAML Connection, you'll need the Identity Provider Metadata URL that is available from your customer's CAS SAML instance. --- ## What WorkOS provides WorkOS provides the [ACS URL](/glossary/acs-url), the [SP Metadata](/glossary/sp-metadata) link and the [SP Entity ID](/glossary/sp-entity-id). They are readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot highlighting the "Service Provider Details" of a CAS SAML connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/68f2825e-7787-4100-b7d5-8339ed75b6be.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. The SP Metadata link contains a metadata file that the organization can use to set up the SAML integration. The SP Entity ID is a URI used to identify the issuer of a SAML request, response, or assertion. --- ## What you'll need In order to integrate you'll need the [IdP Metadata URL](/glossary/idp-metadata). Normally, this will come from the organization's IT Management team when they set up your application's SAML 2.0 configuration in their CAS instance. But, should that not be the case during your setup, here's how to obtain it. --- ## (1) Enter Service Provider Details Copy and paste the "ACS URL" and "SP Entity ID" into the corresponding fields for Service Provider details and configuration. For some setups, you can use the metadata found at the SP Metadata link to configure the SAML connection. --- ## (2) Obtain Identity Provider Metadata Copy the IdP Metadata URL from your CAS SAML settings and upload it to your WorkOS Connection settings. Your Connection will then be linked and good to go! ![A screenshot highlighting the "URL Metadata Configuration" input of a CAS SAML Connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/a32e166f-ab97-47f1-988d-6799b303160f.png?auto=format&fit=clip&q=50) Alternatively, you can manually configure the connection by providing the IdP URI (Entity ID), [IdP SSO URL](/glossary/idp-sso-url) and X.509 Certificate. ![A screenshot highlighting the "Switch to Manual Configuration" button on the URL Metadata Configuration modal of a CAS SAML connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/4b40807d-0f4c-4b0f-81a5-05f832b88b25.png?auto=format&fit=clip&q=50) ![A screenshot showing the input fields for manual configuration of a CAS SAML connection in the WorkOS Dashboard.](https://images.workoscdn.com/images/0eb372eb-551f-4ad8-8d89-9519ce10dfbe.png?auto=format&fit=clip&q=50) --- ## (3) Configure Attribute Mapping At minimum, the Attribute Statement in the SAML Response should include `id`, `email`, `firstName`, and `lastName` attributes. ### Role Assignment (optional) With [identity provider role assignment](/sso/identity-provider-role-assignment), users can receive roles within your application based on their group memberships. To return this information in the attribute statement, map the groups in your identity provider to a SAML attribute named `groups`. Once your SAML app is configured to return groups, navigate to the SSO connection page in the _Organization_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). Create SSO groups by referencing the IdP Group ID. Then, assign roles to these SSO groups so group members are automatically granted roles within your application. ### Bubble Plugin Add WorkOS features to your Bubble application. ## Introduction The [Bubble plugin for WorkOS](https://bubble.io/plugin/workos-sso-1666727595127x530956156372516860) allows you to easily integrate [WorkOS API](/reference) endpoints in your application's workflows. This plugin includes actions for SSO, Directory Sync, Admin Portal, and webhook validation. --- ## Install the WorkOS SSO and API Plugins In the **Plugins** tab of your app editor in Bubble, click **Add Plugins**, then search for WorkOS. Install the plugins for both WorkOS SSO and WorkOS API and then click **Done**. ![A screenshot showing how to install the WorkOS SSO plugin in Bubble.](https://images.workoscdn.com/images/03cf97a8-e0e9-49bc-be67-e21501ff5ab4.png?auto=format&fit=clip&q=50) ![A screenshot showing how to install the WorkOS API plugin in Bubble.](https://images.workoscdn.com/images/165832c3-88d2-49e5-9153-8fd1009367aa.png?auto=format&fit=clip&q=50) The next step is to enter your secret keys/parameters on the **Plugins** settings page as seen below. The API key can be found in your WorkOS dashboard under **API Keys**. > In the WorkOS SSO plugin the API Key value can be entered directly. ![A screenshot showing where to enter environment variables in Bubble for the WorkOS SSO plugin.](https://images.workoscdn.com/images/40fd465f-b73c-4dd2-8478-375eb68757ae.png?auto=format&fit=clip&q=50) > In the WorkOS API plugin the API Key value needs to be preceded by **Bearer**. ![A screenshot showing where to enter environment variables in Bubble for the WorkOS API plugin.](https://images.workoscdn.com/images/4bd64da1-4212-4ef9-a1bc-8064d60eac64.png?auto=format&fit=clip&q=50) Now you're set up to use the plugin directly in your workflows. --- ## Single Sign-On Whether you are implementing a Single Sign-On authorization flow for your application using a no-code platform or building your app from the ground up, the steps that you need to take on a high level are the same. You can find more information in our [SSO Quickstart Guide](/sso). ### Use SSO in a Workflow To configure SSO, you will need: - An active SSO connection, which can be configured manually or by using the [Admin Portal](/admin-portal). - A [connection](/reference/sso/connection) ID or [organization](/reference/organization) ID associated with the user logging in. If WorkOS does not handle user management on your application's behalf, it is necessary to keep track of the association between your users and their WorkOS connection or organization IDs in your database. - [Redirect URI](/glossary/redirect-uri), which is the URL to redirect the user to when they are authorized. This is provided by Bubble in the **Plugins** tab. Navigate to the **Workflow** page in your application and add a new event. Select the action that will trigger the workflow to start. In this case, the workflow is triggered when the submit button is clicked. Under the **Account** menu option, select **Signup/login with a social network**, then select **WorkOS SSO** from the **OAuth provider** dropdown menu. Enter either the connection ID, organization ID, or provider. > Select whether you will use connection, organization, or provider (OAuth connections only), and delete the other defaults. The value should be entered in the `organization=` format. ![A screenshot showing how to enter the parameter values in a Bubble workflow.](https://images.workoscdn.com/images/c39e8579-e064-4f79-b6ad-a3ec8d5c1118.png?auto=format&fit=clip&q=50) When a user launches this workflow, they will be prompted to log in through the associated WorkOS SSO connection. Upon a successful login, if the user does not exist in the application database, a new user will be created and logged in as the current user. If the user already exists, that user will be logged in as the current user. --- ## Directory Sync To start using [Directory Sync](/directory-sync), you will need to configure a new directory connection between your customer's directory provider and WorkOS. This can be completed manually or by using the [Admin Portal](/admin-portal). Once a directory connection is activated in WorkOS, you can configure webhooks to send events to your Bubble application using the WorkOS plugin through a backend workflow. ### Enable backend workflows To enable backend workflows, navigate to the **Settings** page of your Bubble app under the **API** tab, and select **Enable Workflow API and backend workflows**. You are now able to configure backend workflows in the **Workflow** section. ![A screenshot showing how enable backend workflows in Bubble.](https://images.workoscdn.com/images/e3443ee9-38fb-4d1a-98d3-40d0af2bfa3d.png?auto=format&fit=clip&q=50) ### Create a new workflow to receive webhooks To create a new workflow that subscribes to WorkOS webhooks, navigate to the **Workflows** section of your app in Bubble and select **backend workflows** from the page selection dropdown. ![A screenshot showing how to navigate to and create a new backend workflow in Bubble.](https://images.workoscdn.com/images/ec2377c0-1d06-40a0-9608-710690f539b3.png?auto=format&fit=clip&q=50) Create a new API Workflow. In the **detected data option** ensure that **include headers** is selected before clicking **Detect data**. ![A screenshot showing how to configure a backend workflow to detect data in Bubble.](https://images.workoscdn.com/images/67a1be1b-7ec7-4f6a-8c30-d3804eca2aa7.png?auto=format&fit=clip&q=50) A pop-up window will show a test URL to validate the webhook body. ![A screenshot showing when a backend workflow is ready to detect data in Bubble.](https://images.workoscdn.com/images/070d64e5-899f-499c-9fca-74eb5cbc267a.png?auto=format&fit=clip&q=50) Navigate to the **Webhooks** tab in your WorkOS dashboard and enter this test URL as your webhook endpoint. ![A screenshot showing how to configure a webhook endpoint in the WorkOS dashboard.](https://images.workoscdn.com/images/85e7b624-c107-49d2-82af-9c7a026caeb9.png?auto=format&fit=clip&q=50) Then, click the **Send Test Event** button to send a test event. ![A screenshot showing where to send a test webhook event in the WorkOS dashboard.](https://images.workoscdn.com/images/87937fdf-a9e7-4804-a780-5e5d96b40a18.png?auto=format&fit=clip&q=50) Bubble will recognize the event and validate the endpoint. Click save to complete the subscription to WorkOS webhook events for this workflow. ![A screenshot showing a successfully detected webhook event in Bubble.](https://images.workoscdn.com/images/aa9531f1-7df5-4053-9021-e9cca649dbcc.png?auto=format&fit=clip&q=50) ### Implement the webhook validation action After the new workflow is set up to listen for new events, it is recommended that you use the webhook validation action to verify that the webhooks being received are from WorkOS. This action verifies the request is valid by using the webhook body, signature, and secret that you provide from your WorkOS dashboard. To properly define the webhook parameter, you should use the raw body text of the request data. Similarly, the `webhook_signature` should be defined using the `workos-signature` in the request data headers. ![A screenshot showing how to select the webhook validation action in Bubble.](https://images.workoscdn.com/images/e43720ac-5669-4a8d-8ac3-5a220ed2c730.png?auto=format&fit=clip&q=50) After the event is validated, you can use the data from the body to log the webhook and make changes to users. ### Reconcile the users The plugin also includes endpoints, documented under the directory sync section of the [API Reference](/reference), that can be used to reconcile users. Periodically calling the [List Directory Users](/reference/directory-sync/directory-user/list) endpoint and verifying that the returned date matches what you have stored in your user table helps ensure your application has up-to-date information about your users, so you can use it with confidence. --- ## Admin Portal The [Admin Portal](/admin-portal) provides an out-of-the-box UI for IT contacts to configure SSO and Directory Sync connections. The WorkOS API plugin provides an API call that launches the Admin Portal if you would like to display it on the settings page of your application. You can also copy and paste these links directly from the WorkOS dashboard in the connection settings. Upon completing the setup flow with the Admin Portal, IT contacts will be able to test the new connection and validate that it has been configured correctly. ![A screenshot showing how to select the admin portal action in Bubble.](https://images.workoscdn.com/images/14cafa76-cb94-4880-800c-5b8b2aa93777.png?auto=format&fit=clip&q=50) ### Breathe HR Learn about syncing your user list with Breathe HR. ## Introduction This guide outlines how to synchronize your application's Breathe HR directories. To synchronize an organization's users and groups provisioned for your application, you'll need the following information from the organization: - Breathe HR API key > Note: The Breathe HR integration isn't enabled by default in the WorkOS Dashboard or Admin Portal. Please reach out to [support@workos.com](mailto:support@workos.com) or via your team's WorkOS Slack channel if you would like Breathe HR enabled. --- ## (1) Create an API Key The organization will need to create an API key for you. An API key can be generated from the Admin Settings menu. ![A screenshot showing where to select "Settings" in the Breathe HR dashboard.](https://images.workoscdn.com/images/3defb6ef-fe7d-458f-8639-d0410fc11f51.png) Under "Integrations", select "API Setup". ![A screenshot showing where to select "API Setup" in the Breathe HR dashboard settings.](https://images.workoscdn.com/images/d6c8d0e9-1d71-428e-b368-4bcd5240432c.png) Next, select "Enable API". ![A screenshot showing where to select "Enable API" on the "API Setup" page in the Breathe HR dashboard.](https://images.workoscdn.com/images/890c4a8e-4217-433f-b67f-037dda40a7c5.png) Verify that you'd like to enable the API to access user information. ![A screenshot showing to mark the checkbox denoting "I understand and want to continue" in the "Warning" modal in the Breathe HR dashboard.](https://images.workoscdn.com/images/e6623c61-c520-4636-a029-c91fb2b5a33f.png) Save the production API key – this will be used in the next step. ![A screenshot showing where to select the production API key in the "API Setup" section of the Breathe HR dashboard.](https://images.workoscdn.com/images/d66a8ba2-bcf6-44bf-a714-e08164cdf632.png) --- ## (2) Create your Directory Sync Connection Login to your WorkOS dashboard and select "Organizations" from the left hand Navigation bar Select the Organization you'd like to enable a Breathe HR Directory Sync connection for. On the Organization's page click "Add Directory". ![A screenshot showing where to select "Add Directory" in the WorkOS dashboard.](https://images.workoscdn.com/images/f6bdcf89-cfc4-46e6-a67c-d2f428e6052a.png) Select "Breathe HR" as the Directory Provider, and then provide a descriptive name for the connection. Select "Create Directory". ![A screenshot showing the configuration of the "Create Directory" modal to create a Breathe HR Directory in the WorkOS dashboard.](https://images.workoscdn.com/images/32c361da-6bf7-428b-84c0-5b1f27db5c51.png) --- ## (3) Set up your Directory Sync Connection Click "Update Directory" on the Directory details page. ![A screenshot showing where to select "Update Directory" in the WorkOS dashboard.](https://images.workoscdn.com/images/d2f1bfb0-f119-4582-8c6c-83e11bbbbd87.png) Input the Breathe HR API key and click "Save Directory Details". ![A screenshot showing the input of the Breathe HR API key into the "Directory Details" modal in the WorkOS dashboard.](https://images.workoscdn.com/images/12ede429-9f2b-4cff-8e30-00e2b3594a85.png) --- ## (4) Sync Users and Groups to Your Application Now, you should see users and groups synced over from Breathe HR. Departments from Breathe HR are synced as groups in WorkOS. All users are synced, but only those marked as "Current employee" or "Pending leaver" are active. ![A screenshot showing a successfully linked Breathe HR Directory in the WorkOS dashboard.](https://images.workoscdn.com/images/26b9a26a-1abc-4517-9251-104da59f7251.png) A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) ## Frequently asked questions ### How often do Breathe HR directories perform a sync? Breathe HR directories poll every 30 minutes starting from the time of the initial sync. ### BambooHR Learn about syncing your user list with BambooHR. ## Introduction This guide outlines how to synchronize your application's BambooHR directories. To synchronize an organization's users and groups provisioned for your application, you'll need the following information from the organization: - The BambooHR subdomain. - A BambooHR API key to authenticate requests. > Note: The BambooHR integration isn't enabled by default in the WorkOS Dashboard or Admin Portal. Please reach out to [support@workos.com](mailto:support@workos.com) or via your team's WorkOS Slack channel if you would like BambooHR enabled. --- ## (1) Create your Directory Sync Connection Login to your WorkOS Dashboard and select "Organizations" from the left hand navigation bar. Select the organization you'll be configuring a new Directory Sync Connection with. Click "Manually Configure Connection". ![A screenshot showing where to find "Manually Configure Connection" for an Organization in the WorkOS Dashboard.](https://images.workoscdn.com/images/60d14679-0ff2-4b7b-9e75-82ea0ae158f5.png?auto=format&fit=clip&q=50) Input the Name, and select "BambooHR" as the directory type. Click the "Create Directory" button. ![A screenshot showing "Create Directory" details in the WorkOS Dashboard.](https://images.workoscdn.com/images/e696881c-64b9-40c4-aa8e-593913179c92.png?auto=format&fit=clip&q=50) You will now see your BambooHR directory sync has created successfully with an [Endpoint](/glossary/endpoint), as well as fields to input your subdomain and API Key from BambooHR. --- ## (2) Retrieve the details from an organization's IT contact To generate an API key, an IT contact should log into BambooHR and click their name in the upper right-hand corner of the BambooHR console. Select "API Keys" from the list. ![A screenshot showing where to find the "API Keys" option in the BambooHR Dashboard.](https://images.workoscdn.com/images/6165e109-527d-4960-adc2-b7882262e526.png?auto=format&fit=clip&q=80) Next, the IT contact should click "Add New Key". ![A screenshot showing where to find the "Add New Key" in the BambooHR Dashboard.](https://images.workoscdn.com/images/eb6b50be-6a2c-478b-aa3f-0d7b69240ddd.png?auto=format&fit=clip&q=80) Give your key a descriptive name and select "Generate Key." ![A screenshot showing where to find "Generate Key" in the BambooHR Dashboard.](https://images.workoscdn.com/images/a176f1f3-10a0-4803-acd2-fbbe69fb9719.png?auto=format&fit=clip&q=80) Select "Copy Key" and save this API key, which you'll upload in the next step. ![A screenshot showing where to find "Copy Key" in the BambooHR Dashboard.](https://images.workoscdn.com/images/69c5bff2-023f-4a1e-8cdf-48edc4609a29.png?auto=format&fit=clip&q=80) --- ## (3) Set up your Directory Sync Connection Click "Update Directory". There are two fields to enter, one is the API key you created in step 2. The other is "Subdomain" which is the subdomain name of the Company's BambooHR instance. ![A screenshot showing where to find the "Update Directory" button in the WorkOS Dashboard.](https://images.workoscdn.com/images/f562e95e-faf9-4658-ac27-1d1396abcccb.png?auto=format&fit=clip&q=50) --- ## (4) Sync Users and Groups to Your Application When the connection is successfully made, you will see the green "Linked" icon appear. Now, whenever your customer assigns users or groups to your application, you'll receive Dashboard updates based on changes in their directory. A detailed guide to integrate the WorkOS API with your application can be found [here](/directory-sync) ## Frequently Asked Questions ### How do I add BambooHR's custom fields? For BambooHR's custom fields, please contact [support@workos.com](mailto:support@workos.com) with your directory ID and a list of the custom fields you would like to be added. ### How often do BambooHR directories perform a sync? BambooHR directories poll every 30 minutes starting from the time of the initial sync. ### AWS Cognito Learn how to use WorkOS with your existing AWS Cognito applications. ## Introduction This guide outlines the steps to make WorkOS SSO Connections available to AWS Cognito applications without requiring changes to your existing application code. The integration works by configuring WorkOS connections as third-party [Identity Providers](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-identity-federation.html) inside a Cognito User Pool which enables users to sign in to a Cognito application leveraging all SSO integrations supported by WorkOS. > The AWS Cognito integration is in feature preview. Reach out to [WorkOS support](mailto:support@workos.com?subject=AWS%20Cognito%20Integration) if you want early access. --- ## (1) Configure AWS IAM role WorkOS manages the configuration of the Cognito Identity Providers by leveraging AWS role delegation. You will need to create an IAM role in your AWS account that grants permissions to the WorkOS AWS account. This is can be easily accomplished through the AWS Console. ![Create AWS IAM role](https://images.workoscdn.com/images/0a36c5ff-505e-46ba-805a-66d13c9150ed.png?auto=format&fit=clip&q=50) The external ID will be provided by the WorkOS support team upon request. The AWS account ID should be `611361754156` which is the ID of a dedicated WorkOS AWS account used for Cognito integrations. You will need to attach the following policy to the role so that the Identity Providers can be managed when the role is assumed by WorkOS. ```json language="json" title="IAM Policy" { "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor", "Effect": "Allow", "Action": ["cognito-idp:*"], "Resource": "*" } ] } ``` Complete the creation of the role and take note of the name you provide as it will be used in the following step. ## (2) Provide AWS details to WorkOS Once the role has been configured you will need to provide the following details from your AWS account to the WorkOS support team. - Account ID - Role name - User pool ID Once the WorkOS support team has configured your AWS details, you should see Identity Providers configured in the specified User Pool for every connection configured in WorkOS. Newly added WorkOS connections will automatically be created in the specified User Pool. ## (3) Enable Identity Providers for App Client Now that the Identity Providers have been configured, they will need to be enabled for the App Client you wish to use the WorkOS Connections with. From the user pool navigate to **App integration** → **_Your App Client_** → **Edit hosted UI settings** and select the newly created Identity Providers. ![App Client Identity Provider settings](https://images.workoscdn.com/images/e0f4a7c1-4131-4110-a6a3-9f5466110745.png?auto=format&fit=clip&q=50) > If you do not complete this step you will receive a **Login option is not available** error from Cognito upon sign in. ## (4) Configure redirect URI Locate the domain of the Cognito User Pool and configure the following redirect URI in the [Applications](https://dashboard.workos.com/environment/applications) section of the WorkOS Dashboard. Open your application and go to the **Redirects** tab. ```plain title="Cognito callback URI" https:///oauth2/idpresponse ``` ## (5) Sign in with WorkOS connection Once an Identity Provider has been created in the Cognito User Pool, you may initiate authentication by passing the `idp_identifier` query parameter to the [OAuth2 Authorize endpoint](https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html) provided by Cognito using the details from the App Client that was previously configured with the Identity Providers. You may pass either a WorkOS [Organization](/reference/organization) or [Connection](/reference/sso/connection) ID as the `idp_identifier`. Passing this query parameter will result in Cognito bypassing it's standard sign-in page and immediately redirecting the user to the appropriate sign-in page of the upstream identity provider configured in the WorkOS Connection. Once the user is authenticated they will be redirected to your Cognito App Client redirect URL with the Cognito `code` query parameter. ### Auth0 Learn how to configure a connection to Auth0 via SAML. > Looking to migrate from Auth0 to WorkOS? Check out the [full migration guide](/migrate/auth0). ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a Connection will differ by Identity Provider. To create a Auth0 SAML Connection, you'll need the Identity Provider metadata that is available from the organization's Auth0 instance. Start by logging in to your WorkOS dashboard and browse to the "Organizations" tab on the left hand navigation bar. Select the organization you'd like to configure an Auth0 SAML Connection for, and select "Manually Configure Connection" under "Identity Provider". ![A screenshot showing where to find "Manually Configure Connection" in the WorkOS Dashboard.](https://images.workoscdn.com/images/2c3eff01-e84c-4e65-9739-ae72facb9eaa.png?auto=format&fit=clip&q=50) Select "Auth0 SAML" from the Identity Provider dropdown, enter a descriptive name for the connection, and then select the "Create Connection" button. ![A screenshot showing "Create Connection" details in the WorkOS Dashboard.](https://images.workoscdn.com/images/6e0f49c0-06fb-4a18-b805-31e3a10b27bb.png?auto=format&fit=clip&q=50) --- ## What WorkOS Provides WorkOS provides the [ACS URL](/glossary/acs-url) and [SP Entity ID](/glossary/sp-entity-id), which are readily available in your Connection Settings in the [WorkOS Dashboard](https://dashboard.workos.com/). ![A screenshot showing where to find the ACS URL and SP Entity ID in the WorkOS Dashboard.](https://images.workoscdn.com/images/ec8cb8f8-b440-47d5-9a80-7b51ca9950bd.png?auto=format&fit=clip&q=50) The ACS URL is the location an Identity Provider redirects its authentication response to. In Auth0's case, the ACS URL needs to be set by the organization when configuring your application in their Auth0 instance. The SP Entity ID is a URI used to identify the issuer of a SAML request and the audience of a SAML response. In this case, the SP Entity ID is used to communicate that WorkOS will be the party performing SAML requests to the organization's Auth0 instance, and that WorkOS is the intended audience of the SAML responses from the Auth0 instance. Specifically, the ACS URL will need to be set as the "Application Callback URL" on the SAML2 Web App Settings page found under the "Addons" tab in an Auth0 application. You will need to toggle on the SAML2 Web App for the settings modal to appear where you can add the ACS URL under the Application Callback URL input. ![A screenshot showing a toggle to turn on the SAML2 web app addon for Auth0 applications.](https://images.workoscdn.com/images/63ffadf6-ed3b-429d-a4a7-a5294b1a3a0d.png?auto=format&fit=clip&q=50) ![A screenshot showing where to set the ACS URL in the SAML2 web app settings for Auth0 applications.](https://images.workoscdn.com/images/294645cc-18d2-4969-a9ed-6ec69f2bca3d.png?auto=format&fit=clip&q=50) The SP Entity ID will need to be set as the "audience" value in the Settings JSON object on the SAML2 Web App Settings page. After the Application Callback URL and Audience have been added, scroll to the bottom and click "Enable". ![A screenshot showing where to set the SP Entity ID in the SAML2 web app settings for Auth0 applications.](https://images.workoscdn.com/images/4fd65ff7-6296-43d8-8e65-0bd528028f70.png?auto=format&fit=clip&q=50) --- ## What you'll need In order to integrate you'll need the Auth0 IdP Metadata URL. Normally, this information will come from the organization's IT Management team when they set up your application's SAML 2.0 configuration in their Auth0 admin dashboard. Here's how to obtain them: --- ## (1) Log In and Select Your Application Log in to [Auth0](https://auth0.com/auth/login), go to the admin dashboard, select "Applications" in the sidebar, and then select the "Applications" menu option. Next, select your application from the list of applications. ![A screenshot showing where to find the web application in Auth0 Dashboard.](https://images.workoscdn.com/images/e4bb38d9-fa10-4caa-b097-05a8d83a4e2b.png?auto=format&fit=clip&q=50) --- ## (2) Obtain Identity Provider Metadata On the application's Settings page, scroll down to the bottom and expand the "Advanced Settings" section. Select the "Endpoints" tab and copy the SAML Metadata URL. You'll need this in the next step. ![A screenshot of the IdP Metadata XML URL in the Auth0 Dashboard.](https://images.workoscdn.com/images/6288c6a6-ab57-4608-8a1e-872bbd7eb2bd.png?auto=format&fit=clip&q=50) --- ## (3) Upload Metadata URL Finally, upload the SAML Metadata URL you saved earlier in your WorkOS Connection settings. Your Connection will then be linked and good to go! ![A screenshot showing where to place the Auth0 IdP Metadata URL in the WorkOS Dashboard.](https://images.workoscdn.com/images/f1cb1c5c-8554-48a5-89a1-31a42d356690.png?auto=format&fit=clip&q=50) ### Auth0 Enterprise Connection Learn how to use WorkOS with your existing Auth0 applications. > Looking to migrate from Auth0 to WorkOS? Check out the [full migration guide](/migrate/auth0). ## Introduction This guide outlines the steps to make WorkOS SSO connections available to Auth0 applications without requiring changes to your existing Auth0 application code. > The Auth0 Enterprise Connection integration is in feature preview. Reach out to [WorkOS support](mailto:support@workos.com?subject=WorkOS%20Support) if you want early access. --- ## (1) Configure Auth0 API Access WorkOS uses Auth0 credentials you provide to manage the Auth0 Enterprise Connection automatically. The first step is authorizing an application in Auth0 to access the Management API. In the Auth0 dashboard, navigate to **Applications** → **APIs** → **Auth0 Management API**: ![A screenshot showing the "Auth0 Management API" entry on the Auth0 APIs page.](https://images.workoscdn.com/images/e2baba2e-a442-4449-90db-d1be8db41ef2.png?auto=format&fit=clip&q=50) Click on the **Machine To Machine Applications** tab and expand the section for your Auth0 application. Then, toggle the **Authorized** switch to enable the API. Under **Permissions**, ensure the following scopes are granted to the application: - `create:connections` - `read:connections` - `update:connections` Your permissions configuration should match the following screenshot: ![A screenshot a correctly configured API application in the Auth0 dashboard.](https://images.workoscdn.com/images/13b5acb2-b5c6-4cd5-a032-0dd7afedc81a.png?auto=format&fit=clip&q=50) Next, navigate to **Applications** → **_Your App_** → **Settings**. You should see three fields under **Basic Information**: "Domain", "Client ID", and "Client Secret". ![A screenshot showing application credentials in the Auth0 dashboard.](https://images.workoscdn.com/images/c8303868-de12-40e5-a0cc-27bec508131c.png?auto=format&fit=clip&q=50) Record this information in a safe place, as you will provide it to the WorkOS dashboard in the next step. --- ## (2) Connect WorkOS to Auth0 In the WorkOS dashboard, navigate to **Configuration** → **Settings** and scroll to the **Auth0 Credentials** section. Click **Set Auth0 Credentials**: ![A screenshot showing the "Auth0 Credentials" section in the WorkOS dashboard.](https://images.workoscdn.com/images/16b3ea51-8564-4ced-86fb-f3ab9fad8d28.png?auto=format&fit=clip&q=50) In the modal, enter the credentials you obtained in the previous step: "API Domain", "Client ID", and "Client Secret". ![A screenshot showing the "Auth0 Credentials" form in the WorkOS dashboard.](https://images.workoscdn.com/images/3e915c68-97c0-4d1e-88e9-cda8bff7fd31.png?auto=format&fit=clip&q=50) Click **Save**. In the final step, you will head back to the Auth0 dashboard one last time to complete the configuration. --- ## (3) Enable the Enterprise Connection After saving your credentials, WorkOS will create an Enterprise Connection in your Auth0 environment. This connection is the entry point into WorkOS SSO from Auth0. The next step is to enable the connection for your Auth0 application. In the Auth0 dashboard, navigate to **Applications** → **_Your App_** → **Connections**. You should see a connection with a `workos-sso-` prefix in its name. Enable it for your application. ![A screenshot showing enabled connections for an application in the Auth0 dashboard.](https://images.workoscdn.com/images/4cd3dbec-7ccc-462a-a101-5f8fc29aa332.png?auto=format&fit=clip&q=50) --- ## (4) Enable "Identifier First" Login Flow In the Auth0 dashboard, navigate to **Authentication** → **Authentication Profile**. You should see three options for configuring login flow. Select **Identifier First**. ![A screenshot showing "Identifier First" selected in the Auth0 dashboard.](https://images.workoscdn.com/images/b30e3808-b978-4f86-9443-8e2e7d588a90.png?auto=format&fit=clip&q=80) This configures the Auth0 Universal Login page to begin by prompting the user for their email address. This is necessary as it allows Auth0 to select the WorkOS SSO Enterprise Connection if the user's email domain matches one of your WorkOS organizations. Non-enterprise users will still be prompted for their password. > [IdP-initiated SSO](/sso/login-flows/idp-initiated-sso) is currently not supported when using the Auth0 Enterprise Connection integration. --- ## Summary Your WorkOS SSO connections are now available to your Auth0 application! You are ready to use WorkOS features like [Admin Portal](admin-portal), allowing IT contacts to configure their SSO setup for your application directly. As you create [organizations](/reference/organization), WorkOS will keep the Auth0 Enterprise Connection's [Home Realm Discovery](https://auth0.com/docs/authenticate/login/auth0-universal-login/identifier-first#define-home-realm-discovery-identity-providers) list updated with the organization's domains – ensuring correct routing of enterprise users to WorkOS for authentication. When users enter their email address into the Auth0 Universal Login, which matches a domain associated with a WorkOS organization, Auth0 redirects users to their WorkOS-enabled IdP sign-in page for their organization. Once the authentication process is complete with the IdP, WorkOS redirects to your Auth0 app callback URL. > Since email domains are used to route users to the correct IdP when using Auth0, WorkOS will enforce that [organization domains](/reference/domain-verification) are unique, and therefore a domain cannot be assigned to more than one organization. ### Auth0 Directory Sync Learn how to use Directory Sync with your Auth0 applications. > Looking to migrate from Auth0 to WorkOS? Check out the [full migration guide](/migrate/auth0). ## Introduction This guide will walk you through the steps to enable WorkOS Directory Sync for your Auth0 applications. If you are new to automated user provisioning and deprovisioning, the [Directory Sync](/directory-sync) introduction is a good place to learn the basics. > The Auth0 Directory Sync integration is in feature preview. Reach out to [WorkOS support](mailto:support@workos.com?subject=Auth0%20Directory%20Sync%20Integration) if you want early access. ## (1) Configure Auth0 API access WorkOS uses Auth0 credentials you provide to automatically create and manage an Auth0 database connection. The first step is to authorize an application in Auth0 to access the Management API. In the Auth0 dashboard, navigate to **Applications** → **APIs** → **Auth0 Management API**: ![A screenshot showing the "Auth0 Management API" entry on the Auth0 APIs page.](https://images.workoscdn.com/images/e2baba2e-a442-4449-90db-d1be8db41ef2.png?auto=format&fit=clip&q=50) Click on the **Machine To Machine Applications** tab and expand the section for your Auth0 application. Then, toggle the **Authorized** switch to enable the API. Under **Permissions**, ensure the following scopes are granted to the application: - `create:connections` - `create:users` - `read:connections` - `read:users` - `update:connections` - `update:users` Your permissions configuration should match the following screenshot: ![A screenshot a correctly configured API application in the Auth0 dashboard.](https://images.workoscdn.com/images/13b5acb2-b5c6-4cd5-a032-0dd7afedc81a.png?auto=format&fit=clip&q=50) Next, navigate to **Applications** → **_Your App_** → **Settings**. You should see three fields under **Basic Information**: "Domain", "Client ID", and "Client Secret". ![A screenshot showing application credentials in the Auth0 dashboard.](https://images.workoscdn.com/images/c8303868-de12-40e5-a0cc-27bec508131c.png?auto=format&fit=clip&q=50) Record this information in a safe place, as you will provide it to the WorkOS dashboard in the next step. --- ## (2) Connect WorkOS to Auth0 In the WorkOS dashboard, navigate to **Configuration** → **Settings** and scroll to the **Auth0 Credentials** section. Click **Set Auth0 Credentials**: ![A screenshot showing the "Auth0 Credentials" section in the WorkOS dashboard.](https://images.workoscdn.com/images/16b3ea51-8564-4ced-86fb-f3ab9fad8d28.png?auto=format&fit=clip&q=50) In the modal, enter the credentials you obtained in the previous step: "API Domain", "Client ID", and "Client Secret". ![A screenshot showing the "Auth0 Credentials" form in the WorkOS dashboard.](https://images.workoscdn.com/images/3e915c68-97c0-4d1e-88e9-cda8bff7fd31.png?auto=format&fit=clip&q=50) Click **Save**. In the final step, you will head back to the Auth0 dashboard one last time to complete the configuration. --- ## (3) Enable the database connection After saving your credentials, WorkOS will create a database connection in your Auth0 environment. This connection will contain the users from directories in your WorkOS organizations. The next step is to enable the connection for your Auth0 application. In the Auth0 dashboard, navigate to **Applications** → **_Your App_** → **Connections**. You should see a connection with a `workos-dsync-` prefix in its name. Enable it for your application. ![A screenshot showing enabled connections for an application in the Auth0 dashboard.](https://images.workoscdn.com/images/73b12882-d286-49cd-ba58-a0527eab7f4f.png?auto=format&fit=clip&q=50) --- ## Summary Your WorkOS directories will now be synchronized with your new Auth0 database connection! You are ready to use WorkOS features like [Admin Portal](/admin-portal), allowing IT contacts to configure their directory provider for your application directly. New users provisioned into Auth0 are given a randomly generated password. They will need to reset their password before they can sign in. You can also use [WorkOS directory sync webhooks](/events/data-syncing/webhooks) to be notified when new users are provisioned, allowing you to tailor the onboarding experience for these new users, like sending a welcome email. Deprovisioned users will be deleted from the Auth0 database connection. If you need to perform additional cleanup in your application, you can receive WorkOS directory sync webhooks for delete events as well. ### Apple Learn how to set up "Sign in with Apple" ## Introduction The "Sign in with Apple" integration allows your users to authenticate using their Apple ID credentials. The configuration process involves obtaining credentials from your Apple Developer account and configuring them in the WorkOS Dashboard. You may also set up Private Email Relay for users who choose to hide their email addresses. --- ## Testing with default credentials in the staging environment WorkOS provides a default set of Apple credentials, which allow you to quickly enable and test Sign in with Apple. WorkOS will automatically use the default credentials until you add your own Apple Team ID, Apple Service ID, and Apple Private Key to the configuration in the [WorkOS dashboard](https://dashboard.workos.com). > The default credentials are only intended for testing and therefore only available in the Staging environment. For your production environment, please follow the steps below to create and specify your own Apple Team ID, Apple Service ID, and Apple Private Key. Please note that when you are using WorkOS default credentials, Apple's authentication flow will display the WorkOS name, logo, and other information to users. Once you register your own application and use its credentials for the authentication flow, you will have the opportunity to customize the app. --- ## What WorkOS provides When setting up "Sign in with Apple", WorkOS provides two key pieces of information that need to be configured in your Apple Developer account: - [Redirect URI](/glossary/redirect-uri): The endpoint where Apple will send authentication responses after successful login - **Outbound Email Domains**: Registered domains for Apple's Private Relay email service These are available in the [WorkOS Dashboard](https://dashboard.workos.com/). In the left navigation menu, select the **Authentication** tab and the **OAuth providers** sub-tab. Locate the **Sign in with Apple** section. ![Open the Sign in with Apple configuration dialog](https://images.workoscdn.com/images/b9abf389-f950-49b2-8cf3-2c47e9b810bf.png?auto=format&fit=clip&q=50) Click **Enable**. The **Sign in with Apple** configuration dialog will open. Locate the **Redirect URI** and **Outbound email domains**. ![Sign in with Apple Redirect URI in the WorkOS dashboard.](https://images.workoscdn.com/images/54680256-09bc-478f-ab0f-5889c1d846be.png?auto=format&fit=clip&q=50) The **Redirect URI** serves as the destination for authentication responses and must be configured in your Apple Developer account. **Outbound email domains** are registered with Apple's Private Relay email service to deliver email to users who choose to hide their email addresses. --- ## What you'll need You will need to obtain four pieces of information from your Apple Developer account: - **Apple Team ID**: Your organization's unique identifier in the Apple Developer program - **Apple Service ID**: Application identifier for "Sign in with Apple" - **Apple Private Key**: Authentication key file for secure communication - **Private Key ID**: Identifier for the private key The following sections will guide you through generating these credentials in your Apple Developer account. --- ## (1) Retrieve your Apple Team ID Sign in to the [certificates, identifiers, and profiles](https://developer.apple.com/account/resources/certificates/list) section of your Apple Developer account. The landing page will display your name, company name, and Team ID. Note the Team ID value as you'll need it later. ![Team ID in the Apple Developer dashboard.](https://images.workoscdn.com/images/2edd45b9-7e84-45fa-8da2-3c6dcd5607a1.png?auto=format&fit=clip&q=80) > The Team ID is sensitive and will only be used by the server to communicate with Apple. It should not be shared with the client. --- ## (2) Register an App ID > Skip this step if you already have an App ID. Click on **Identifiers** in the sidebar, then click the + button to create a new identifier. ![Identifiers page in the Apple Developer dashboard with Create Identifier plus button highlighted.](https://images.workoscdn.com/images/54be9c35-f7c9-4119-9765-64299d42ff23.png?auto=format&fit=clip&q=80) On the next page, select **App IDs** and click **Continue**. ![First step in the Identifier creation wizard with App IDs selected.](https://images.workoscdn.com/images/a028e2b5-9443-4208-aa0c-175056ac55b5.png?auto=format&fit=clip&q=80) Next, select **App** and click **Continue**. ![Second step in the Identifier creation wizard with App selected.](https://images.workoscdn.com/images/baff59f5-f060-4faf-9761-678321cc496a.png?auto=format&fit=clip&q=80) On the next page, fill in a description and a bundle ID. The bundle ID should be unique and in reverse domain notation, e.g., `com.example.myapp`. Also check the **Sign in with Apple** box in the Capabilities section. There is no need to update anything in the **Edit** modal. ![Third step in the Identifier creation wizard with placeholder Description and Bundle ID entered.](https://images.workoscdn.com/images/ef85061d-ff63-4d5a-8fad-a9cbefeb6786.png?auto=format&fit=clip&q=80) ![Third step in the Identifier creation wizard with Sign in with Apple checkbox checked.](https://images.workoscdn.com/images/9f184ccb-40d8-4410-9250-b8ab56600452.png?auto=format&fit=clip&q=80) Then click **Continue**. Review your selections and click **Register**. --- ## (3) Register a Service ID Next you need to create a linked Service ID. Click on **Identifiers** in the sidebar, then click the + button. ![Identifiers page in the Apple Developer dashboard with Create Identifier plus button highlighted.](https://images.workoscdn.com/images/4a129d31-33c8-4976-8340-d59fc6618b67.png?auto=format&fit=clip&q=80) On the next page, select **Services IDs** and click **Continue**. ![First step in the Identifier creation wizard with Services IDs selected.](https://images.workoscdn.com/images/2496cf53-f593-4eda-a2f9-14d6728b0c5d.png?auto=format&fit=clip&q=80) Enter a description and a Service ID. The Service ID should be unique and in reverse domain notation, e.g. `com.example.myapp`. ![Second step in the Identifier creation wizard with placeholder Description and Service ID entered.](https://images.workoscdn.com/images/dbf69235-951c-4f1d-97b2-3a1c6854c758.png?auto=format&fit=clip&q=80) Click **Continue**. Note the Service ID as you'll need it later, then click **Register** to create the service. Now you'll configure your new service for "Sign in with Apple". First select the new service from the list of Service IDs. ![Identifiers page in the Apple Developer dashboard with the newly created Service ID highlighted.](https://images.workoscdn.com/images/478f799f-298e-4dee-9b6d-ff75d02fd9f5.png?auto=format&fit=clip&q=80) Check the **Sign in with Apple** box and click **Configure**. ![Service ID Edit page with Sign in with Apple checkbox checked.](https://images.workoscdn.com/images/8c3e92fe-f5fc-403e-b7ee-fa215ad61ccf.png?auto=format&fit=clip&q=80) Ensure the App ID you created earlier is selected in the dropdown. Then enter `api.workos.com` in the **Domains and Subdomains** field and paste the **Redirect URI** from the WorkOS Dashboard in the **Return URLs** field. ![Service ID Sign in with Apple edit modal with placeholder values in the inputs.](https://images.workoscdn.com/images/574617e5-4e3c-41a9-8704-dfa47bf504e2.png?auto=format&fit=clip&q=80) Click **Done** and then **Continue**. Review your changes and click **Save**. --- ## (4) Register a private key Click on **Keys** in the sidebar, then click the + button to create a new key. ![Keys page in the Apple Developer dashboard with Create Key plus button highlighted.](https://images.workoscdn.com/images/ebeffde4-091d-4b2c-a9f9-fede59d6674a.png?auto=format&fit=clip&q=80) On the next page, enter a human-readable **Key Name**. Then check the **Sign in with Apple** box and click **Configure**. ![First step in the Key creation wizard.](https://images.workoscdn.com/images/264d1e39-ccae-4d32-80da-af2d5813723c.png?auto=format&fit=clip&q=80) In the **Configure** dialog, select the App ID you created earlier and click **Save**. ![Key Configure dialog with App ID from the previous step selected.](https://images.workoscdn.com/images/d1442a7c-47a3-412c-956b-415a11acda9b.png?auto=format&fit=clip&q=80) Click **Continue**. Review your changes and click **Register** to create your key. ![Download Your Key page.](https://images.workoscdn.com/images/eb032a3d-4d2a-44be-a2f5-292e901fae16.png?auto=format&fit=clip&q=80) Make sure to download your new private key and note the Key ID as you'll need both later. --- ## (5) Configure Apple credentials in WorkOS Now you have all the required credentials: - Apple Team ID - Apple Service ID - Private Key ID - The downloaded private key file Return to the [WorkOS Dashboard](https://dashboard.workos.com). In the **Sign in with Apple** configuration dialog, toggle **Enable** on. Select **Your app's credentials**. Paste the credentials from Apple that you generated in the previous steps into their respective fields. ![Sign in with Apple configuration modal in the WorkOS dashboard filled out with information from earlier steps.](https://images.workoscdn.com/images/cfedc298-8666-4f38-ab71-f6ed777b44c1.png?auto=format&fit=clip&q=80) --- ## (6) Set up Private Email Relay Sign in with Apple users can opt to hide their email address when signing in. In order for emails to be sent to those users, you need to configure Private Email Relay. Copy the **Outbound Email Domains** from the **Sign in with Apple** configuration modal in the WorkOS Dashboard. ![Sign in with Apple configuration modal in the WorkOS dashboard with outbound email domains control highlighted.](https://images.workoscdn.com/images/8c4ae9a5-1b27-49c7-90f7-31a3010ee2b5.png?auto=format&fit=clip&q=80) Open your Apple Developer account and click on **Services** in the sidebar. Then click on **Configure** under **Sign in with Apple for Email Communication**. ![Services page in the Apple Developer dashboard with Sign in with Apple Configure button highlighted.](https://images.workoscdn.com/images/cc81ae18-450d-417f-9e22-6392b335e437.png?auto=format&fit=clip&q=80) Click the + button next to **Email Sources** and enter the outbound email domains from the WorkOS Dashboard in the **Domains and Subdomains** text box. Then click **Next** and **Register**. ![Modal to register Email Sources with domains from the WorkOS dashboard in the Domains and Subdomains text box.](https://images.workoscdn.com/images/021882c4-e299-44b8-9a44-fcf22f3be150.png?auto=format&fit=clip&q=80) ![New domains with green check marks next to them.](https://images.workoscdn.com/images/fa3e78e6-688d-46a8-b4e7-1f6c788da4f6.png?auto=format&fit=clip&q=80) You are now ready to start authenticating with "Sign in with Apple". Your users will see the option to "Sign in with Apple" when visiting your [AuthKit](/authkit) domain. Alternatively if you're using the [standalone SSO API](/reference/sso/get-authorization-url), you can initiate "Sign in with Apple" by passing `AppleOAuth` as the `provider`. --- ## Frequently asked questions ### How is the WorkOS "Sign in with Apple" integration different from implementing regular Apple OAuth flow? It's the same Apple OAuth flow as you could build yourself, but it's encapsulated within WorkOS SSO. This means you don't need to build it yourself. In addition to "Sign in with Apple", you can use WorkOS SSO to support other identity providers, all with a single integration. ### What is the provider query parameter and how is it used in the Apple OAuth integration? You can use the `provider` query parameter in the [Get Authorization URL API endpoint](/reference/sso/get-authorization-url) to support global Apple OAuth for any domain. The `provider` query parameter should be set to `AppleOAuth`. ### Why do I need to configure Private Email Relay? "Sign in with Apple" allows users to hide their real email address from your app. When a user chooses this option, Apple generates a unique, random email address that forwards to their real email. To send emails to these users, you need to register your sending domains with Apple's Private Email Relay service. ### What happens if I don't set up Private Email Relay? If you don't configure Private Email Relay, you won't be able to send emails to users who choose to hide their email address. Those users will still be able to sign in, but any emails you attempt to send to their relay address will not be delivered. ### Can I use the same App ID for multiple services? Yes, you can use the same App ID for multiple Services IDs. This is useful if you have multiple applications or environments that need to use "Sign in with Apple". ### ADP OpenID Connect Learn how to configure a connection to ADP via OIDC. ## Introduction Each SSO Identity Provider requires specific information to create and configure a new [Connection](/glossary/connection). Often, the information required to create a connection will differ by Identity Provider. ADP is unique in that it authenticates using the Open ID Connect (OIDC) protocol instead of [SAML](/glossary/saml). This means that instead of providing an [ACS URL](/glossary/acs-url) and [SP Entity ID](/glossary/sp-entity-id) into the IdP, The IdP will provide a client ID and secret. ADP also provides an SSL Certificate and Private RSA Key file to authenticate. These four pieces of information will all need to be uploaded into the WorkOS dashboard in the steps below. --- ## (1) Create a New ADP OIDC Connection in WorkOS Navigate to the Organization in your WorkOS Dashboard under which you would like to set up this new SSO connection. Click on the "Manually Configure Connection" button. ![A screenshot showing where to find "Manually Configure Connection" in the WorkOS Dashboard.](https://images.workoscdn.com/images/b7370939-c547-4ad1-9b2d-cc8ed150b90b.png?auto=format&fit=clip&q=50) Select ADP OIDC as the Identity Provider and select "Create Connection". ![A screenshot showing "Create Connection" details in the WorkOS Dashboard.](https://images.workoscdn.com/images/e20c45f0-2842-45e0-9364-7878f493f0a4.png?auto=format&fit=clip&q=50) --- ## (2) Select or Create a Project in ADP Login to the [ADP Partner Self Service Portal](https://adpapps.adp.com/self-service/projects). From this page there are two environments to select from, Development and Production. Please use the environment that best suits your use-case for this SSO connection. In the selected environment select "Create New Project". ![A screenshot showing the Projects Overview page in the ADP Partner Self Service Portal.](https://images.workoscdn.com/images/39422d34-f4b8-42c2-af5a-b7c8b26dfe1f.png?auto=format&fit=clip&q=50&w=2048) Give the project a meaningful name to designate the SSO connection, there is no need to add a description. ![A screenshot showing the Create New Project details in the ADP Partner Self Service Portal.](https://images.workoscdn.com/images/614daf3e-afa8-4007-9aec-f087fb60a394.png?auto=format&fit=clip&q=50&w=2048) Make the selections "US Marketplace" and "ADP Workforce Now" respectively for the next selections and then click "Next". ![A screenshot showing selection options for the ADP Marketplace in the ADP Partner Self Service Portal.](https://images.workoscdn.com/images/e38e06a8-7c82-44d3-bb58-cc7cc875b8cc.png?auto=format&fit=clip&q=50&w=2048) Finally, select "Other" for the use case that best describes your application and click "Submit". ![A screenshot showing app description selection options in the ADP Partner Self Service Portal.](https://images.workoscdn.com/images/8de31a18-444c-4a48-b41a-fd3be86b4933.png?auto=format&fit=clip&q=50) --- ## (3) Upload the WorkOS Redirect URI in ADP After configuring the ADP project, the next step is to provide ADP with the redirect URI generated by WorkOS. ![A screenshot showing where to find the ACS URL and SP Entity ID in the WorkOS Dashboard.](https://images.workoscdn.com/images/5bc6cf1c-c327-4e81-9588-442fc61bf55d.png?auto=format&fit=clip&q=50) Now that a new project has been created browse to the "Development API Credentials" Tab within the project. Click on the "End-User/SSO sub-tab" from this view. Paste the [Redirect URI](/glossary/redirect-uri) into the App redirect URI field and click "Update Redirect". ![A screenshot showing where to place the WorkOS Single Sign-On URL and SP Entity ID in the ADP Partner Self Service Portal.](https://images.workoscdn.com/images/5ae15d57-82d5-4591-bc86-f6637a1588f7.png?auto=format&fit=clip&q=50) --- ## (4) Enter ADP OIDC Client Settings in your WorkOS Dashboard Now that the redirect URI has been provided, the next step is to gather the [Client ID](/glossary/client-id) and [Client Secret](/glossary/client-secret) from ADP and add it into the WorkOS Dashboard. Under the same tab used in the previous step, you'll provide the Client ID and Client Secret from ADP. Click to reveal the secret and copy and paste both the client ID and client secret into the WorkOS dashboard. ![A screenshot showing where to find the ADP Client Credentials in the ADP Partner Self Service Portal.](https://images.workoscdn.com/images/2c8b784a-88e5-4d63-9853-3f8eb6acd304.png?auto=format&fit=clip&q=50) ![A screenshot showing where to enter the ADP Client Credentials WorkOS Dashboard.](https://images.workoscdn.com/images/fc0444d4-9864-4c19-ab4a-327ab914417f.png?auto=format&fit=clip&q=50) --- ## (5) Upload the ADP SSL Cert and Private Key in your WorkOS Dashboard Now that the Client ID and Secret have been provided, the next step is to gather the SSL Certificate and Private Key from ADP and add it into the WorkOS Dashboard. ADP uses a two-fold certificate method with an SSL certificate and an SSL private key. The SSL private key is displayed only once when the certificate is generated. If the certificate has already been generated, the IT contact who generated it should also have received the private key; otherwise, generate a new certificate and key from the Certificates tab in the left-hand navigation. The SSL Certificate can be found in ADP by browsing to "Certificate" on the left hand nav bar. You can also create a new SSL Certificate and Private Key pair if necessary. ![A screenshot showing where to download the ADP SSL Certificate and Private Key in the ADP Partner Self Service Portal.](https://images.workoscdn.com/images/31e16dbd-3f08-41b4-9478-5a02b0c3a9f5.png?auto=format&fit=clip&q=50) Upload the two files into your WorkOS dashboard in their respective portals on the connection page and click "Update Connection". ![A screenshot showing where to upload the ADP SSL Certificate and Private Key in the WorkOS Dashboard](https://images.workoscdn.com/images/783a81be-f5c4-43ba-b2f2-25a9f1c18a8f.png?auto=format&fit=clip&q=50) --- ## (6) Verify Connection Status in WorkOS Navigate back to the connection in your WorkOS dashboard. After a minute or two you should see the connection become Active as indicated by the green badge next to the connection name. All that's left to do now is test out the connection. You can use your own application if it's connected to WorkOS already, or feel free to use one of our example applications like this [Python Flask SSO app](https://github.com/workos/python-flask-example-applications/tree/main/python-flask-sso-example) to get up and running with a PoC quickly ### Access People HR Learn about syncing your user list with Access People HR. ## Introduction This guide outlines how to synchronize your application's Access People HR directories. To synchronize an organization's users and groups provisioned for your application, you'll need the following information from the organization: - Access People HR API key > Note: The Access People HR integration isn't enabled by default in the WorkOS Dashboard or Admin Portal. Please reach out to [support@workos.com](mailto:support@workos.com) or via your team's WorkOS Slack channel if you would like Access People HR enabled. --- ## (1) Create an API Key The organization will need to create an API key for you. First, they'll need to log in to their Access People HR admin dashboard and select to the "Settings" page from the side bar menu. Then, select "API" from the Settings side bar menu. On the API Key Management page, select the plus sign to add a new API Key. ![A screenshot showing where to find the plus sign in the Access People HR Dashboard.](https://images.workoscdn.com/images/9cbff13f-9ea3-442a-90ae-7c135e14e07b.png?auto=format&fit=clip&q=50) In the API Key Generator, give the API Key a descriptive name. Under "Application", select "Employee". ![A screenshot showing where the "Employee" option is location in the Access People HR Dashboard.](https://images.workoscdn.com/images/02f54969-422c-4f17-9c34-559bd419cf3e.png?auto=format&fit=clip&q=50) On the Select Permissions page, check only "Get All Employee Detail" and then select "Save". ![A screenshot showing where to select the "Get All Employee Detail" permission is located in the Access People HR Dashboard.](https://images.workoscdn.com/images/7387653b-7d30-4733-96e4-033004396449.png?auto=format&fit=clip&q=50) On the API Key Generator page, select "Save". ![A screenshot showing the API Key Generator page in the Access People HR Dashboard.](https://images.workoscdn.com/images/c58ba765-8015-4776-8fe0-6260de530d52.png?auto=format&fit=clip&q=50) Copy and save the API key – this will be used in Step 3. ![A screenshot showing the copy icon in the Access People HR Dashboard.](https://images.workoscdn.com/images/a8248b85-173a-4f6b-812f-f58b9abfc9f1.png?auto=format&fit=clip&q=50) --- ## (2) Create your Directory Sync Connection Login to your WorkOS dashboard and select "Organizations" from the left hand Navigation bar Select the Organization you'd like to enable an Access People HR Directory Sync connection for. On the Organization's page click "Manually Configure Directory". ![A screenshot showing where to find "Manually Configure Directory" for an Organization in the WorkOS Dashboard.](https://images.workoscdn.com/images/ed383bc9-e626-4d2c-bbfd-78dbe8bbc5d4.png?auto=format&fit=clip&q=50) Select "Access People HR" as the Directory Provider, and then provide a descriptive name for the connection. Select "Create Directory". ![A screenshot showing Create Directory details in the WorkOS Dashboard.](https://images.workoscdn.com/images/cc5dde6b-4eda-4af7-bcb9-3ec958e6bc79.png?auto=format&fit=clip&q=50) --- ## (3) Setup your Directory Sync Connection In the directory details section, select "Update Directory". ![A screenshot showing where to find "Update Directory" in the WorkOS Dashboard.](https://images.workoscdn.com/images/b0b0e10f-59ab-43da-b348-52b5d53bd299.png?auto=format&fit=clip&q=50) Enter your API Key from Step 1, and select "Save Directory Details". ![A screenshot showing where to enter your API Key in the WorkOS Dashboard.](https://images.workoscdn.com/images/31881779-5153-4193-a5bd-316b9684650b.png?auto=format&fit=clip&q=50) --- ## (4) Sync Users and Groups to Your Application Now, you should see users and groups synced over from Access People HR. Departments from Access People HR are synced as groups in WorkOS. All users are synced, but only those marked as "ACTIVE" or "LEAVER\_MARKED" have a state of active. --- ## Frequently asked questions ### How often do Access People HR directories perform a sync? Access People HR directories poll every 30 minutes starting from the time of the initial sync. ## FGA {#fga} ### Fine-Grained Authorization (FGA) Scalable fine-grained authorization built for B2B SaaS. ## Introduction Fine-Grained Authorization (FGA) extends the existing WorkOS RBAC system to handle the complex, fast-changing authorization needs of modern B2B SaaS products. Most products start with simple, tenant-wide roles like Admin and Member. As adoption grows, the authorization model must account for new and changing app resources and requirements, like workspaces, projects, apps, pipelines, nested tenants, custom roles, group-based collaboration, and enterprise exceptions. What used to evolve over a decade can now change in 12–18 months. Teams patch RBAC with special cases, multiply role variants, and eventually face full rewrites. FGA is designed as the next step in that evolution. It keeps the mental model of RBAC—roles, permissions, assignments—while adding hierarchical, resource-scoped access control. It integrates natively with WorkOS products you're already using: RBAC, SSO, Directory Sync, AuthKit, and IdP role assignment. It can be adopted incrementally, with no data migration or confusing schema DSL. The goal is a single authorization foundation that adapts as your product and customer requirements change, without forcing conceptual rewrites. --- ## Core concepts FGA formalizes three building blocks: **Subjects** are the users, groups, devices, or agents that can be granted access. Today that's primarily organization memberships (users), with support for other subject types coming soon. **Resources** are the business entities in your product—organizations, workspaces, projects, apps—arranged in a hierarchy. Permissions flow down this hierarchy automatically. **Privileges** are the roles and permissions that define what subjects can do. Roles are scoped to resource types and can include permissions for child resource types, enabling powerful inheritance. The key shift from traditional tenant-wide RBAC is that resources and their hierarchy are first-class. Roles and permissions are scoped to specific resource types and can be assigned at any level of that hierarchy. --- ## Building blocks ### Resource types [Resource types](/fga/resource-types) define the schema of your authorization model. They describe what kinds of entities exist — workspaces, projects, apps — and how they relate to one another. You configure resource types in the WorkOS Dashboard, creating the blueprint for your application's entity hierarchy. ### Resources [Resources](/fga/resources) are instances of resource types created at runtime. When a user creates a workspace or project in your application, you register a corresponding resource in WorkOS with a type, an ID, and a parent. ### Roles and permissions [Roles and permissions](/fga/roles-and-permissions) are scoped to specific resource types. A role describes what someone can do within the scope of a particular resource. Permissions can apply to the same resource type or inherit up to parent resource types. ### Assignments [Assignments](/fga/assignments) bind an organization membership to a role on a specific resource. Support for other subject types like profiles, directory users, agents, and services is coming soon. When a role includes child-type permissions, those permissions propagate down the hierarchy automatically. ### Access checks [Access checks](/fga/access-checks) answer the question: "Can this user perform this action on this resource?" You can also ask "Which resources can this user access?" or "Who has access to this resource?" FGA considers all the ways a user might have access—roles assigned directly, roles inherited from parent resources, and organization-scoped roles. --- ## Hierarchical permission inheritance The defining feature of FGA is that permissions flow down the resource hierarchy automatically. A workspace admin can access all projects and apps within that workspace without needing separate assignments at each level. ![Example resource hierarchy with roles](https://images.workoscdn.com/images/74c1fad7-abe9-4c21-a244-8c2563f1313c.png?auto=format&fit=clip&q=50) In this example, users have roles at different levels of the hierarchy. An organization member can view everything beneath the organization. A project editor can edit a specific project and its apps. An app editor has access only to a single app. The hierarchy does the work of propagating permissions—you assign a role once, and access flows down to all children. This model reduces the number of role assignments you need to manage while giving you precise control when you need it. For a detailed walkthrough of how this works, see [Roles and Permissions](/fga/roles-and-permissions). --- ## Adoption path FGA works alongside the existing RBAC product. No migrations are required—existing roles and organization memberships continue working, and you can adopt FGA incrementally. A typical rollout looks like: 1. Keep using current RBAC for organization-level access 2. Define resource types in the Dashboard to mirror your product structure 3. Begin registering resource instances as entities are created 4. Introduce resource-scoped roles like `workspace-admin` or `project-editor` 5. Add Authorization API checks where you need resource-level control 6. Assign resource roles via API (IdP group mapping for resources coming soon) You don't need to convert everything at once. Start with one feature, prove the model works, then expand. --- ## AuthKit integration FGA integrates with [AuthKit](/fga/authkit-integration) to provide role-aware sessions. Organization-scoped roles and their permissions are embedded directly in access tokens, enabling instant checks for org-wide features without API calls. For resource-scoped permissions, the Authorization API evaluates against the full hierarchy. This two-layer approach—JWT for org-wide, API for resources—gives you fast checks where possible and precise control where needed. --- ## Enterprise identity mapping For enterprise customers, [IdP role assignment](/fga/idp-role-assignment) allows organizations to map identity provider groups to organization-scoped roles. When someone joins the "Engineering" group in Okta or Azure AD, they automatically get the corresponding role. Resource-scoped role assignments remain managed via API, giving you a clean separation: IT contacts control baseline organization access through their identity provider, while your application manages who has access to which specific resources. --- ## Performance and scalability FGA is designed for real-time authorization: - **Sub-50ms p95** access checks - **Strong consistency**—role changes take effect immediately - **High availability** for production workloads - **Warmed caches** to minimize cold starts - **Edge caches** for low-latency global access (coming soon) --- ## Coming soon We're continuing to expand FGA with new capabilities: **User groups and teams** – Assign a group of users to a resource or group of resources. Instead of individual assignments, grant access to an entire team at once. **IdP role assignment for sub-resources** – Map identity provider groups directly to resource-scoped roles, not just organization-scoped roles. Your customers' IT contacts will be able to control workspace and project access through their IdP. **Permission assignment** – Assign or exclude specific permissions for a user, enabling patterns like "grant access to all resources except this one" without creating custom roles. **Further performance enhancements** – Continued optimization of access check endpoints for even lower latency at scale. ### Standalone Integration Use FGA with your own authentication system by managing users, organizations, and memberships via API. ## Introduction FGA works with any authentication system. While [AuthKit](/fga/authkit-integration) provides built-in user management, you can integrate FGA standalone by managing users, organizations, and organization memberships through the API. Use standalone integration when you have an existing authentication system, are migrating from another identity provider, or need programmatic control over user provisioning. --- ## Core concepts FGA authorization is built on three entities: **Users** represent individuals in your application. Each has a unique ID, email, and profile information. **Organizations** represent your customers or tenants. They serve as the root of your resource hierarchy. **Organization memberships** connect users to organizations and assign an organization-scoped role. Every membership must have at least one role—this determines baseline permissions within the organization. The organization membership role is always scoped to the organization itself, not to specific resources. For resource-level access control, use [role assignments](/fga/assignments) on individual resources. If you want to grant access exclusively through resource-scoped roles, configure the default organization-scoped role to have no permissions. Users will start with no access and only gain permissions through explicit resource role assignments. > **Note:** Organization-scoped roles can be either environment-level roles (which apply across all organizations) or [custom roles](/rbac/custom-roles) (which are defined per-organization). Both types can serve as the membership role. --- ## Creating organizations Organizations are the tenants in your application. Create one for each customer: The `external_id` maps to your internal customer identifier—typically the primary key from your database. | Parameter | Description | | ------------- | ----------------------------------------------- | | `name` | Display name for the organization (required) | | `external_id` | Your internal identifier for this customer | | `domain_data` | Email domains associated with this organization | | `metadata` | Custom key-value pairs for your application | --- ## Creating users Create users in WorkOS to establish their identity for authorization: | Parameter | Description | | ---------------- | ------------------------------------------ | | `email` | User's email address (required) | | `first_name` | User's first name | | `last_name` | User's last name | | `email_verified` | Set to `true` if you've verified the email | | `external_id` | Your internal user identifier | | `password` | Password for email/password authentication | | `password_hash` | Pre-hashed password for migrations | | `metadata` | Custom key-value pairs | --- ## Creating organization memberships Organization memberships connect users to organizations and assign their organization-scoped role: The `role_slug` determines the user's organization-scoped permissions. If omitted, the user receives the default role configured in your environment. This role applies to the organization as a whole—for resource-specific access, use [role assignments](/fga/assignments). If you've enabled [multiple roles](/authkit/roles-and-permissions/multiple-roles), assign several roles at once with `role_slugs`: ```javascript const membership = await workos.userManagement.createOrganizationMembership({ userId: 'user_01HXYZ', organizationId: 'org_01HXYZ', roleSlugs: ['admin', 'billing'], }); ``` --- ## Using FGA with standalone users Once you've created users and memberships, FGA works as documented in other guides. The organization membership ID is the subject for all authorization operations. ### Creating resources Register resources as your application entities are created: ### Assigning resource roles Grant users roles on specific resources: ### Checking permissions Check whether a user can perform an action on a resource: --- ## User lifecycle Sync WorkOS records as users move through your application's lifecycle. Use the `external_id` field to map your internal IDs to WorkOS entities. ### When a user signs up Create the WorkOS user and organization membership when a user signs up in your application: ### When organization-scoped roles change Update the organization membership when a user's role changes: ### When resource access changes Create or remove role assignments when a user's access to specific resources changes: ### When a user is removed Delete the organization membership or user when they leave: ```javascript // Remove from one organization await workos.userManagement.deleteOrganizationMembership('om_01HXYZ'); // Or delete the user entirely (removes all memberships) await workos.userManagement.deleteUser('user_01HXYZ'); ``` --- ## Managing entities For complete API documentation on managing users, organizations, and memberships, see the API reference: - [Users](/reference/authkit/user) – create, update, list, and delete users - [Organizations](/reference/organization) – create, update, list, and delete organizations - [Organization Memberships](/reference/authkit/organization-membership) – create, update, deactivate, and delete memberships --- ## Viewing users in the dashboard Users created via API appear in the WorkOS Dashboard. Navigate to **Users** to see all users in your environment, or **Organizations** to view members of a specific organization. ![Dashboard showing users](https://images.workoscdn.com/images/54fa6e6c-4c6f-4959-9301-344aeb4eeac8.png?auto=format&fit=clip&q=80) View a user's resource-scoped role assignments by navigating to their organization membership. ![FGA role assignments](https://images.workoscdn.com/images/c9a27787-a97c-4e8b-ac86-05cba25374ae.png?auto=format&fit=clip&q=50) --- ## Migrating from another system To migrate from another identity provider, export your users and import them into WorkOS using the APIs described above. You can import password hashes so users keep their existing credentials, and use a dual-write strategy to handle new signups during migration. See the [migration guides](/migrate/other-services) for detailed steps, including provider-specific guides for [Auth0](/migrate/auth0), [Firebase](/migrate/firebase), [Clerk](/migrate/clerk), and [others](/migrate). ### Roles and Permissions Define what users can do within specific resource types. ## Introduction Once you've defined your resource types, the next step is deciding what users can actually do. Roles and permissions in FGA are always scoped to a specific resource type—a workspace role applies only to workspaces, a project role applies only to projects. This scoping makes permissions predictable. When you see `workspace-admin`, you know it grants workspace access. When a role includes permissions for child types, those permissions flow down automatically—a workspace admin can access all projects in that workspace without separate assignments. --- ## Understanding permissions A permission represents a specific action a user can perform on a resource type. Each permission has a name (like "Edit Workspace"), a slug used in code (`workspace:edit`), and the resource type it applies to. We recommend following a `{resource_type}:{action}` pattern for permission slugs. This makes permissions self-documenting—`project:delete` clearly means the ability to delete a project. Common patterns include: - `{type}:view` for read access - `{type}:edit` for modifying a resource - `{type}:create` for creating child resources - `{type}:delete` for removing a resource - `{type}:manage` for full administrative control - `{type}:invite` for adding collaborators Keep permissions granular. Instead of a broad `project:access` permission, create specific ones like `project:view`, `project:edit`, and `project:delete`. This gives you flexibility as your product's access requirements evolve. --- ## Understanding roles Roles are collections of permissions that describe what someone can do. Like permissions, each role is scoped to a resource type—you create a role for workspaces, another for projects, and so on. We recommend naming roles to indicate both the scope and the capability level. Following a `{resource-type}-{capability}` pattern makes roles self-explanatory: - `workspace-admin` – full control of a workspace - `workspace-member` – basic workspace access - `project-editor` – can modify a project - `project-viewer` – read-only project access When you assign `workspace-admin` to a user on a specific workspace, they get all the permissions bundled in that role for that workspace. --- ## Permission inheritance The key feature of FGA roles is that they can include permissions for child resource types. This is where the power of hierarchical authorization comes in. A `workspace-admin` role might include: - `workspace:view` and `workspace:edit` (same type) - `project:view` and `project:edit` (child type) - `app:view` and `app:deploy` (grandchild type) When you assign this role to someone on a workspace, they can view and edit that workspace, plus view, edit, and deploy all projects and apps within it. One assignment grants access across the entire sub-tree. This reduces "role explosion"—instead of creating separate roles for every resource combination, you define roles at appropriate levels and let inheritance handle the rest. A workspace admin naturally has access to everything in the workspace, which matches how people think about access. --- ## Seeing inheritance in action To understand how permission inheritance works in practice, consider a hierarchy where an organization contains projects, and projects contain apps: ```text Org └─ Project └─ App ``` Different users can have roles at different levels, and the access they receive depends on where their role is assigned and what permissions that role includes. ![Example resource hierarchy with roles](https://images.workoscdn.com/images/74c1fad7-abe9-4c21-a244-8c2563f1313c.png?auto=format&fit=clip&q=50) - User John has `Project read-only` on `Project:1` and can view only that project, not its apps - User Jane is `Org member` of `Org:1` with `org:read`, `project:read`, and `app:read` permissions. They can view the organization, all of its projects, and all apps under those projects. - Jane is also `Project editor` for `Project:2` and can read and edit `Project:2` and all of its apps. - Jane has `App editor` for `App:Finance` and can view and edit only that app instance. This pattern is powerful because it lets you express nuanced access with minimal assignments. A single organization-level membership provides baseline visibility, while targeted assignments grant elevated access where needed. The hierarchy does the work of propagating permissions, so you don't have to create individual assignments for every resource. --- ## How access is evaluated When your application checks whether a user can perform an action on a resource, FGA looks at all possible sources of access: 1. **Direct assignments** on the resource itself 2. **Inherited assignments** from parent resources 3. **Organization-scoped roles** that include the permission If any of these grant the permission, the user is authorized. For example, if Alice wants to deploy `App:Frontend`, FGA checks whether she has `app:deploy` directly on that app, or on its parent project, or on its parent workspace, or through an organization-scoped role. Her `workspace-admin` role on `Workspace: Engineering` includes `app:deploy`, so she's authorized—even without any direct assignment on the app. --- ## Managing roles in the Dashboard Configure roles and permissions in the [WorkOS Dashboard](https://dashboard.workos.com/) under **Authorization**. You'll need to have [resource types](/fga/resource-types) defined before you can create scoped roles and permissions. To create a new role, select the resource type it applies to and give it a descriptive name and slug. ![FGA create role set details](https://images.workoscdn.com/images/9e943b39-8c7f-448a-8568-2408402d2873.png?auto=format&fit=clip&q=50) Then choose which permissions to include from the same type and child types. ![FGA create role assign permissions](https://images.workoscdn.com/images/98c6a8b5-8814-49d9-a27f-9ba32525c214.png?auto=format&fit=clip&q=50) When you modify a role's permissions, changes apply immediately to everyone with that role. No re-assignment is needed—existing users automatically get the updated permissions. For organizations using [multiple roles](/authkit/roles-and-permissions/multiple-roles), users receive all permissions from all their assigned roles. Priority order only matters for [IdP role assignment](/fga/idp-role-assignment) when running in single-role mode. --- ## Custom resource-scoped roles While environment-level roles apply across all organizations, you can also create custom roles scoped to a specific organization and resource type. These roles let individual organizations define their own access patterns without affecting other organizations. Custom resource-scoped roles are useful when: - Different organizations need different role structures - You want to let organizations define their own roles - Specific organizations have unique access requirements that don't fit the environment-level roles ### Creating a custom resource-scoped role Navigate to an organization in the Dashboard, then select the **Roles** tab. Click **Create custom role** to start. First, enter the role details—a descriptive name and slug for the role. ![Create custom role details step](https://images.workoscdn.com/images/dc0fd548-2408-400b-8da8-2c5f278f9299.png?auto=format&fit=clip&q=50) Next, select the resource type the role applies to and choose which permissions to include. ![Create custom role permissions step](https://images.workoscdn.com/images/52447f46-8bd8-4fce-8deb-901c99cba459.png?auto=format&fit=clip&q=50) The permissions available depend on the selected resource type. You can include permissions from the selected type and any of its child types, just like environment-level roles. ### Assigning custom resource-scoped roles Once created, custom resource-scoped roles can be assigned to users on specific resources within the organization. The assignment process works the same as environment-level roles—you assign the role to a user on a resource instance, and they receive all permissions bundled in that role. --- ## Changing resource type scope A permission's or role's **resource type scope** can't be changed after it's created. Their **slugs** are also immutable. WorkOS doesn't allow changing a permission's scope in place because a scope change can have downstream effects throughout your authorization model. It may change the meaning of existing assignments, make some role-permission relationships invalid under your resource hierarchy, and introduce application-specific dependency issues that are hard to detect automatically. Keeping scope immutable makes these migrations explicit and rollout behavior more predictable. If you need to move a permission or role to a different scope, use this migration path instead: 1. **Create a new permission or role** at the correct resource type scope with a new slug. 2. **Update your roles and authorization model** to include the new permission or role. 3. **Roll your application over** to the new permission or role and verify all relevant paths are covered. 4. **Delete the old permission or role** once it is no longer in use. ### Resources Represent your application's entities in the FGA hierarchy. ## Introduction Resources are the runtime counterpart to resource types. While resource types define your schema, resources represent the actual instances users create and work with. When a user creates a workspace in your application, you register a corresponding resource in WorkOS. When they create a project inside that workspace, you register another resource as a child of the workspace. This builds the hierarchy that FGA uses to evaluate permissions. Each resource has a type, an external ID from your application, a parent (the organization or another resource), and a human-readable name. Together, these form the tree structure where access is assigned and inherited. --- ## Organization resources An organization resource is automatically created for every organization in WorkOS and serves as the root of your hierarchy. Organization resources cannot be edited or deleted—they exist for the lifetime of the organization. Every resource you create must have a parent. For top-level resources like workspaces, the parent is the organization resource. You can reference it using the organization's ID directly as the external ID. --- ## Creating resources Register resources as users create entities in your application. For top-level resources like workspaces, the parent is optional — when omitted, the resource defaults to the organization as its parent: ```bash curl https://api.workos.com/authorization/resources \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "resource_type_slug": "workspace", "external_id": "workspace_01H", "organization_id": "org_01HXYZ", "name": "Engineering" }' ``` For nested resources, specify the parent to establish the hierarchy. You can reference the parent by its internal WorkOS ID: ```bash curl https://api.workos.com/authorization/resources \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "resource_type_slug": "project", "external_id": "project_02H", "organization_id": "org_01HXYZ", "parent_resource_id": "authz_resource_01HXYZ", "name": "API Backend" }' ``` Or reference the parent by its external ID and type, which is often more convenient since you're already tracking your own entity IDs: ```bash curl https://api.workos.com/authorization/resources \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "resource_type_slug": "project", "external_id": "project_02H", "organization_id": "org_01HXYZ", "parent_resource_type_slug": "workspace", "parent_resource_external_id": "workspace_01H", "name": "API Backend" }' ``` See the [API reference](/reference) for full endpoint documentation. --- ## External IDs External IDs are your application's identifiers for resources—typically the primary key from your database. They provide a stable reference that maps directly to your records. External IDs must be unique within a resource type and organization. Two workspaces in the same organization can't share an external ID, but a workspace and a project can (since they're different types). Two workspaces in different organizations can also share an external ID. This uniqueness rule simplifies resource management for managed service providers and platforms that provision similar structures for each customer. Every customer might have a "main" workspace with external ID `main`—that's fine because they're in different organizations. Use your existing database IDs or UUIDs for external IDs. Keep them stable—don't change an ID after creation—and choose values that are meaningful for debugging and support. ### Managing resources by external ID Beyond using internal WorkOS resource IDs, you can manage resources directly using your external IDs: ```bash # Get a resource by external ID curl "https://api.workos.com/authorization/organizations/org_01HXYZ/resources/workspace/workspace_01H" \ -H "Authorization: Bearer sk_example_123456789" # Update a resource by external ID curl https://api.workos.com/authorization/organizations/org_01HXYZ/resources/workspace/workspace_01H \ -X PATCH \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "name": "Engineering Team" }' # Delete a resource by external ID curl https://api.workos.com/authorization/organizations/org_01HXYZ/resources/workspace/workspace_01H \ -X DELETE \ -H "Authorization: Bearer sk_example_123456789" ``` This is often more convenient than looking up internal resource IDs since you're already tracking your own entity IDs. --- ## Keeping resources in sync Resources should mirror your application's data. When entities are created, updated, or deleted in your app, the corresponding resources should change in WorkOS. **On creation**, register the resource immediately after saving the entity to your database. The resource needs to exist before you can assign roles to it. **On deletion**, remove the resource when the entity is deleted. By default, deleting a resource will fail if it has child resources or role assignments. Pass `cascade_delete=true` to delete the resource along with all its children and their role assignments. **On rename**, update the resource's name when the entity's name changes in your application. External IDs are immutable after creation. **On reparent**, update the resource's parent when the entity moves within your hierarchy. For example, if a user drags a project from one workspace to another, update the parent to keep WorkOS in sync. WorkOS automatically rebuilds ancestry for the resource and all its descendants. See [Updating and deleting](#updating-and-deleting) for the API call. --- ## What to model as resources FGA is optimized for low-cardinality, stable entities—the structural elements of your application where access boundaries matter. **Good candidates for FGA resources**: Workspaces, teams, accounts, projects, repositories, pipelines, dashboards, environments—entities where users have different access levels to different instances, and the count is typically in the hundreds to thousands per organization. **Keep in your database**: Documents, messages, tasks, files, comments, rows—high-volume content that changes frequently and typically inherits access from a parent. Modeling millions of documents as individual resources would overwhelm sync and provide no real benefit. As a rule of thumb, hundreds to thousands of resources per organization works well. Tens of thousands might work but consider whether they all need individual access control. Millions should stay in your database with references to their parent FGA resource. ## Parent references for high-volume data High-volume entities can participate in authorization without being modeled as FGA resources. Store a reference to the nearest FGA-managed parent in your database: ```json { "id": "doc_abc123", "content": "...", "project_id": "proj_456" // ← Reference to FGA resource } ``` When checking access, ask about the parent: ```bash # Can this user edit this document? # → Check: Does user have document:edit on Project proj_456? curl https://api.workos.com/authorization/organization_memberships/om_01HXYZ/check \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "permission_slug": "document:edit", "resource_type_slug": "project", "resource_external_id": "proj_456" }' ``` This approach keeps authorization fast (no sync lag), avoids reconciliation issues, scales to millions of documents, and uses the existing permission hierarchy. Users with `document:edit` on the project can edit all documents in it without syncing each document to WorkOS. --- ## Querying resources List resources with optional filters: ```bash curl "https://api.workos.com/authorization/resources?resource_type_slug=project&organization_id=org_01HXYZ" \ -H "Authorization: Bearer sk_example_123456789" ``` Get a specific resource: ```bash curl https://api.workos.com/authorization/resources/authz_resource_01HXYZ \ -H "Authorization: Bearer sk_example_123456789" ``` See the [API reference](/reference) for full query parameters. --- ## Updating and deleting Update a resource's name when the corresponding entity changes: ```bash curl https://api.workos.com/authorization/resources/authz_resource_01HXYZ \ -X PATCH \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "name": "Engineering Team" }' ``` Move a resource to a new parent by specifying the parent's internal ID: ```bash curl https://api.workos.com/authorization/resources/authz_resource_01HXYZ \ -X PATCH \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "parent_resource_id": "authz_resource_02HXYZ" }' ``` Or reference the new parent by its external ID and type: ```bash curl https://api.workos.com/authorization/resources/authz_resource_01HXYZ \ -X PATCH \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "parent_resource_type_slug": "workspace", "parent_resource_external_id": "workspace_02H" }' ``` The new parent must be in the same organization and its resource type must be a valid parent type for the resource being moved. WorkOS automatically rebuilds the ancestry chain for the resource and all its descendants, so inherited permissions immediately reflect the new position in the hierarchy. Delete a resource when the entity is deleted from your application. By default, the request will fail if the resource has child resources or role assignments. Pass `cascade_delete=true` to remove the resource along with all its children and their assignments: ```bash curl "https://api.workos.com/authorization/resources/authz_resource_01HXYZ?cascade_delete=true" \ -X DELETE \ -H "Authorization: Bearer sk_example_123456789" ``` ### Resource Types Define the schema of your application's resource hierarchy in the WorkOS Dashboard. ## Introduction Before your application can manage fine-grained access, you need to define what kinds of objects exist in your product. Resource types are that schema—they describe the categories of entities users interact with and how those entities relate to each other. Most B2B applications have a natural hierarchy. Users belong to organizations, organizations contain workspaces, workspaces contain projects, and projects contain apps. Resource types let you formalize this structure so FGA can evaluate permissions at any level. Resource types are configured in the [WorkOS Dashboard](https://dashboard.workos.com/) rather than through code, ensuring your authorization schema is intentionally designed and easy to update as your product evolves. --- ## What makes a resource type A resource type represents a category of business entity—something users create, access, and collaborate on. Common examples include workspaces, projects, applications, repositories, and dashboards. Each resource type has a few properties: **Name** is the display name users see in the Dashboard, like "Workspace" or "Project." **Slug** is the URL-safe identifier used in API calls, like `workspace` or `project`. Choose slugs that are lowercase, concise, and match your product terminology. **Description** is optional text explaining what this type represents in your application. **Parent types** define which resource types can be parents in the hierarchy. A project might have `workspace` as a parent type, while a workspace might have `organization` as its only parent. --- ## Designing your hierarchy Start by mapping your existing product structure. Think about the entities users create and how they're nested: ```text organization (implicit root) └─ workspace └─ project └─ app ``` Organizations are always the root—every hierarchy starts there. Below that, you define the types that make sense for your product. When deciding what to model as a resource type, ask whether users can have different access levels to different instances. If all projects in a workspace have the same access, you might not need `project` as a separate type. If users can be an admin on one project but only a viewer on another, that's a strong signal to model it. Keep your hierarchy shallow—aim for 2-4 levels. Deep hierarchies are harder to understand and manage, both for you and your customers. --- ## Examples for different products **Multi-tenant SaaS platform**: Organizations contain workspaces, workspaces contain projects, and projects contain apps and databases. Customers create workspaces for different teams, with projects organizing their actual work. ```text organization └─ workspace └─ project ├─ app └─ database ``` **Developer platform**: Organizations directly contain repositories, and repositories own branches and secrets. Access is granted at the repository level, with branches and secrets inheriting from their parent repository. ```text organization └─ repository ├─ branch └─ secret ``` **Analytics application**: Organizations contain accounts, and accounts contain multiple dashboards. Each dashboard might have different access levels for different stakeholders. ```text organization └─ account └─ dashboard ``` **AI agent platform**: Organizations contain workspaces, and workspaces contain AI agents, the tools those agents can invoke, and the datasets they access. Users need different levels of access to different agents, and agents themselves need scoped permissions to specific tools and datasets—an agent in one workspace might invoke a search tool and read customer data, while another agent is limited to internal documentation. What makes this hierarchy distinct is that agents are both resources and subjects. As resources, they live inside workspaces and users control who can configure or launch them. As subjects, agents receive role assignments on tools and datasets just like users do—an agent might have `invoker` on `tool:web-search` and `reader` on `dataset:customers`. When an agent acts on behalf of a user, it should only receive a subset of that user's access, never more. ```text organization └─ workspace ├─ agent ├─ tool └─ dataset ``` --- ## Hierarchy rules A few constraints help keep your authorization model predictable: **Maximum depth** is five levels, which covers even complex enterprise products. Most applications need only two or three. **Single parent** means each resource instance has exactly one parent. A project belongs to one workspace, not multiple. **Multiple parent types** let a resource type accept different parents. An `app` might be created directly under a workspace or nested under a project, so both would be valid parent types. A resource type can have up to 10 child types. **Resource types per environment** are limited to 50. This provides ample room for even complex authorization models while keeping the schema manageable. These constraints exist to keep permission evaluation fast and predictable. Single-parent hierarchies ensure that inherited permissions always flow through a clear path—there's no ambiguity about which parent's roles apply. The depth limit keeps traversal efficient and prevents authorization models from becoming unwieldy. That said, the five-level depth limit is a soft limit based on typical enterprise patterns, not a technical limitation. If your use case requires deeper hierarchies or more resource types, [reach out to us](https://workos.com/contact) to discuss your specific needs. --- ## Creating and managing resource types Resource types are managed exclusively through the [WorkOS Dashboard](https://dashboard.workos.com/)—they cannot be created, modified, or deleted via the public API. Resource types define your authorization schema, and changes to them can have far-reaching consequences: altering a parent relationship affects how permissions inherit, removing a type orphans all its resources and role assignments, and changing the hierarchy can break application logic that depends on it. By restricting resource type management to the Dashboard, we ensure these changes are made deliberately by someone reviewing the full impact, not accidentally by a script or misconfigured automation. ### Using the Dashboard Navigate to **Resources Types** under **Authorization** to configure resource types for your environment. The resource type editor provides: - **Visual hierarchy builder** to arrange parent-child relationships - **Type configuration** for names, slugs, and descriptions - **Relationship validation** that ensures hierarchy constraints are met before saving ![FGA resource types page](https://images.workoscdn.com/images/b38cad2f-8d61-42d3-aacf-577d24621b5c.png?auto=format&fit=clip&q=50) To create a new resource type, click **Edit resource types**, provide a name and slug, and configure which types can be parents. The Dashboard shows how the new type fits into your existing hierarchy. ![FGA edit resource types page](https://images.workoscdn.com/images/09c9c4d0-53a7-4857-91bb-fc347507de8d.png?auto=format&fit=clip&q=50) ### Modifying resource types Once a resource type exists, you can update its name and description freely—these are display values that don't affect API behavior. However, slugs cannot be changed after creation. They're used in API calls, and changing them would break existing integrations. If you need a different slug, create a new resource type and migrate your resources. You can also update a resource type's parent types after creation. This is useful when your hierarchy evolves—for example, adding a new container type or reorganizing how resources relate to each other. Before removing a parent type, ensure: 1. No resource instances of this type have a parent instance of the type being removed 2. No permissions scoped to this resource type are referenced by roles on ancestor types that would become unreachable ### Removing resource types Before removing a resource type: 1. Remove any roles and permissions scoped to that type (deleting a role automatically removes its assignments) 2. Ensure no child types depend on it—only leaf types can be deleted Once these dependencies are resolved, deleting the resource type from the Dashboard will automatically clean up all resource instances of that type. --- ## Adding types as you grow One of the goals of FGA is to make it easy to evolve your authorization model as your product grows. Unlike other systems where changing inheritance rules or adding new entity types requires rewriting complex policies, FGA lets you add new resource types without disrupting existing access patterns. When you ship a new feature that needs its own access control—say, deployments for your developer platform—you simply add a `deployment` resource type and define its parent relationship. Existing types, roles, and assignments continue working unchanged. ```text organization └─ workspace ├─ repository ├─ pipeline └─ deployment (new feature) ``` You don't need to predict every future resource type upfront. Start with the types you need today, and add more as you build new features. The hierarchy is designed to grow with your product. ### Resource Discovery Find which resources a user can access, or who has access to a resource. ## Overview Beyond permission checks, FGA provides endpoints to discover access relationships. These power common product features like member lists, a sharing dialog, and scoped navigation. --- ## List users for a resource Find all users with access to a resource: ```bash curl "https://api.workos.com/authorization/resources/authz_resource_01HXYZ/organization_memberships?permission_slug=project:edit" \ -H "Authorization: Bearer sk_example_123456789" ``` ### Direct vs. indirect assignments Use the `assignment` parameter to control whether results include only users with direct assignments or also those with inherited access: ```bash # Only users with a direct role assignment on this resource curl "https://api.workos.com/authorization/resources/resource_01HXYZ/organization_memberships?permission_slug=project:edit&assignment=direct" \ -H "Authorization: Bearer sk_example_123456789" # All users who can access this resource (direct + inherited) curl "https://api.workos.com/authorization/resources/resource_01HXYZ/organization_memberships?permission_slug=project:edit&assignment=indirect" \ -H "Authorization: Bearer sk_example_123456789" ``` **Direct assignments** (default) return only users with an explicit role on this specific resource. For example, users assigned as `project-editor` directly on this project. **Indirect assignments** return all users with access, including through parent resources. Users with `workspace-admin` on the parent workspace appear in results, as do users with organization-scoped roles that grant the permission. ### Real-world examples **Access audit** – An admin reviews who has been explicitly granted access to a sensitive project. Use `assignment=direct` to see only users with direct role assignments, excluding those with inherited access from workspace or organization-scoped roles. **Member list** – A project page displays all team members who can access the project. Use `assignment=indirect` to show everyone who can access it, whether through direct project membership, workspace membership, or organization-scoped roles. **Sharing confirmation** – Before inviting a collaborator to a project, verify who already has access. Query with `permission=project:view&assignment=indirect` to see all users who can view the project, including inherited access. **Compliance reporting** – Generate reports of users with admin access to critical resources. Use `permission_slug=workspace:admin&assignment=direct` to identify users explicitly assigned admin roles, separate from those with inherited organization-level admin access. --- ## List resources for a user Find all resources where a user has a specific permission: ```bash curl "https://api.workos.com/authorization/organization_memberships/om_01HXYZ/resources?permission_slug=project:edit&parent_resource_id=authz_resource_01HXYZ" \ -H "Authorization: Bearer sk_example_123456789" ``` This endpoint returns all child resources of a parent where the user has the specified permission, including through inheritance. For example, if a user's `workspace-admin` role includes `proj:edit`, all projects in that workspace appear when querying for `proj:edit`—even without direct project assignments. ### Real-world examples **Scoped navigation** – A project management app shows only the projects a user can access in their sidebar within a specific workspace. Query with `parent_resource_id` set to the workspace. **Sharing dialog** – When inviting a collaborator, filter the project picker to show only projects where the user has edit access within the current workspace. **"My Projects" view** – Display all projects under a workspace where a user can perform specific actions. The query includes projects accessible through higher-level roles. --- ## How inheritance affects results When listing users for a resource, the full permission hierarchy is considered. A user with `workspace-admin` on a workspace will appear in results for all projects in that workspace, even without direct project assignments. Use the `assignment` parameter to control whether inherited access is included. When listing resources for a user, only resources where the user has a direct role assignment on the parent resource or any child resources are returned. Indirect assignment lookups are not supported yet. ### Quick Start Build a complete authorization model from resource types to access checks in minutes. ## What you'll build This guide walks you through the entire FGA workflow using a real-world example: a project management application where organizations contain workspaces, and workspaces contain projects. By the end, you'll have: - A resource type hierarchy modeled in the Dashboard - Roles and permissions scoped to each resource type - Resources registered via the API - Role assignments granting users access - Access checks verifying permissions - Discovery queries listing accessible resources The guide follows the same order you'd use when integrating FGA into your product. --- ## 1. Configure resource types Resource types define the schema of your authorization model. Start by mapping your product's entity hierarchy in the [WorkOS Dashboard](https://dashboard.workos.com/). For our project management app, the hierarchy looks like: ```text organization (implicit root) └─ workspace └─ project ``` Navigate to **Authorization > Resource Types** and click **Model resource types**. ![FGA model resource types](https://images.workoscdn.com/images/131f0723-6185-4641-946d-e713eec118d1.png?auto=format&fit=clip&q=50) Create the `workspace` resource type first. Give it a name, a slug, and set its parent to `organization`. Then create `project` with its parent set to `workspace`. ![FGA project resource type](https://images.workoscdn.com/images/a4b3fc33-b6f6-4f0e-a0b7-0d5309ab32a9.png?auto=format&fit=clip&q=50) The Dashboard validates your hierarchy as you build it, ensuring constraints like single-parent relationships and maximum depth are respected. --- ## 2. Create roles and permissions With resource types defined, create the roles and permissions that describe what users can do. Navigate to **Authorization > Permissions** in the Dashboard. ### Define permissions Permissions represent specific actions on a resource type. We recommend a `{resource_type}:{action}` naming pattern. Navigate to **Authorization > Permissions** and click **Create permission**. Select the resource type the permission applies to, give it a name and slug, and save. ![FGA workspace viewer permission](https://images.workoscdn.com/images/2b656ec6-9391-4a0a-919e-7f31ffb6311a.png?auto=format&fit=clip&q=50) Create the following permissions for our example: | Permission | Resource Type | Description | | ---------------- | ------------- | ------------------------------ | | `workspace:view` | workspace | View a workspace | | `workspace:edit` | workspace | Edit workspace settings | | `project:view` | project | View a project | | `project:edit` | project | Edit a project | | `project:create` | project | Create projects in a workspace | | `project:delete` | project | Delete a project | ### Define roles Roles bundle permissions and are scoped to a resource type. The key feature is that roles can include permissions for child types, enabling inheritance. Create a `workspace-admin` role scoped to the `workspace` resource type. Include permissions for the workspace itself and its child types: ![FGA create role set details](https://images.workoscdn.com/images/9e943b39-8c7f-448a-8568-2408402d2873.png?auto=format&fit=clip&q=50) Select which permissions to include—both same-type and child-type permissions: ![FGA create role assign permissions](https://images.workoscdn.com/images/98c6a8b5-8814-49d9-a27f-9ba32525c214.png?auto=format&fit=clip&q=50) Here's a useful set of roles for our example: | Role | Scoped to | Permissions included | | ------------------ | --------- | ------------------------------------------------------------------------------------------------------ | | `workspace-admin` | workspace | `workspace:view`, `workspace:edit`, `project:view`, `project:edit`, `project:create`, `project:delete` | | `workspace-member` | workspace | `workspace:view`, `project:view` | | `project-editor` | project | `project:view`, `project:edit` | | `project-viewer` | project | `project:view` | A `workspace-admin` assignment on a single workspace grants access to all projects within it. A `project-editor` assignment grants access to only that specific project. This layered approach minimizes the number of assignments you need to manage. --- ## 3. Create resources Resources are runtime instances of your resource types. Register them via the API as users create entities in your application. ### Top-level resources When a user creates a workspace, register it as a resource. Top-level resources default to the organization as their parent: ```bash curl https://api.workos.com/authorization/resources \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "resource_type_slug": "workspace", "external_id": "workspace_01H", "organization_id": "org_01HXYZ", "name": "Engineering" }' ``` Response: ```json { "id": "authz_resource_01HABC", "resource_type_slug": "workspace", "external_id": "workspace_01H", "organization_id": "org_01HXYZ", "name": "Engineering", "parent_resource_id": null, "created_at": "2025-01-15T10:30:00Z", "updated_at": "2025-01-15T10:30:00Z" } ``` The `external_id` is your application's identifier for this entity—typically the primary key from your database. Use it to reference this resource in future API calls without needing to store the WorkOS resource ID. ### Child resources When a user creates a project inside a workspace, register it with a parent reference. You can reference the parent by its external ID and type: ```bash curl https://api.workos.com/authorization/resources \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "resource_type_slug": "project", "external_id": "project_02H", "organization_id": "org_01HXYZ", "parent_resource_type_slug": "workspace", "parent_resource_external_id": "workspace_01H", "name": "API Backend" }' ``` Or reference the parent by its internal WorkOS ID: ```bash curl https://api.workos.com/authorization/resources \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "resource_type_slug": "project", "external_id": "project_03H", "organization_id": "org_01HXYZ", "parent_resource_id": "authz_resource_01HABC", "name": "Mobile App" }' ``` Register resources immediately after saving the entity to your database. The resource needs to exist in WorkOS before you can assign roles or check permissions on it. --- ## 4. Assign roles Assignments connect a user (through their organization membership) to a role on a specific resource. This is what actually grants access. ### Assign a workspace role Give Alice (`om_01HXYZ`) the `workspace-admin` role on the Engineering workspace: ```bash curl https://api.workos.com/authorization/organization_memberships/om_01HXYZ/role_assignments \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "role_slug": "workspace-admin", "resource_type_slug": "workspace", "resource_external_id": "workspace_01H" }' ``` Because `workspace-admin` includes child-type permissions like `project:view` and `project:edit`, Alice now has access to all projects within the Engineering workspace—without needing separate assignments on each project. ### Assign a resource-specific role Give Bob the `project-editor` role on just the API Backend project: ```bash curl https://api.workos.com/authorization/organization_memberships/om_02HXYZ/role_assignments \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "role_slug": "project-editor", "resource_type_slug": "project", "resource_external_id": "project_02H" }' ``` Bob can view and edit the API Backend project, but has no access to other projects in the workspace unless separately assigned. ### View assignments in the Dashboard Navigate to an organization membership in the Dashboard to see all role assignments for that user: ![FGA assignments](https://images.workoscdn.com/images/c9a27787-a97c-4e8b-ac86-05cba25374ae.png?auto=format&fit=clip&q=50) --- ## 5. Check permissions Access checks answer: "Can this user perform this action on this resource?" FGA evaluates all possible sources of access—direct assignments, inherited permissions from parent resources, and organization-scoped roles. ### Check by resource external ID Check whether Alice (`om_01HXYZ`) can edit the API Backend project: ```bash curl https://api.workos.com/authorization/organization_memberships/om_01HXYZ/check \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "permission_slug": "project:edit", "resource_type_slug": "project", "resource_external_id": "project_02H" }' ``` Response: ```json { "authorized": true } ``` Alice is authorized because her `workspace-admin` role on the Engineering workspace includes `project:edit`, which flows down to all projects in that workspace. ### Check by resource ID You can also reference resources by their internal WorkOS ID: ```bash curl https://api.workos.com/authorization/organization_memberships/om_01HXYZ/check \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "permission_slug": "project:edit", "resource_id": "authz_resource_02HDEF" }' ``` ### Integrate into your application Here's how an access check looks in practice, protecting an API endpoint: ```javascript import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); app.patch('/projects/:projectId', async (req, res) => { const { organizationMembershipId } = req.user; const { projectId } = req.params; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:edit', resourceExternalId: projectId, resourceTypeSlug: 'project', }); if (!authorized) { return res.status(403).json({ error: 'Forbidden' }); } const project = await updateProject(projectId, req.body); return res.json(project); }); ``` Access checks are designed to be low-latency and reflect role changes immediately—without requiring cache invalidation or waiting for propagation delays. --- ## 6. Discover access FGA provides discovery endpoints that power common product features like filtered navigation, member lists, and sharing dialogs. ### List resources a user can access Find all projects Alice (`om_01HXYZ`) can edit within the Engineering workspace: ```bash curl "https://api.workos.com/authorization/organization_memberships/om_01HXYZ/resources?permission_slug=project:edit&parent_resource_type_slug=workspace&parent_resource_external_id=workspace_01H" \ -H "Authorization: Bearer sk_example_123456789" ``` This powers features like a sidebar that shows only the projects a user has access to, or a project picker filtered to resources the user can modify. ### List users with access to a resource Find all users who can edit a specific project: ```bash curl "https://api.workos.com/authorization/resources/authz_resource_02HDEF/organization_memberships?permission_slug=project:edit" \ -H "Authorization: Bearer sk_example_123456789" ``` By default, this returns users with direct role assignments on the resource. To include users with inherited access (from workspace or organization-scoped roles), use the `assignment` parameter: ```bash # All users who can edit this project (direct + inherited) curl "https://api.workos.com/authorization/resources/authz_resource_02HDEF/organization_memberships?permission_slug=project:edit&assignment=indirect" \ -H "Authorization: Bearer sk_example_123456789" ``` This powers sharing dialogs, member lists, and compliance audits. --- ## Choosing an access check endpoint FGA exposes four endpoints for answering authorization questions. Pick the one that matches the shape of the question. | Endpoint | Use when | | ---------------------------- | ------------------------------------------------------------------------------------------------------- | | `check` | A single permission on a single resource. Best for action handlers and route gates. | | `listEffectivePermissions` | Many permissions on a single resource. Best for detail pages that render multiple permission-gated components. | | `listResourcesForMembership` | A single permission across many resources. Best for list views, navigation, and pickers. | | `listMembershipsForResource` | All users who have a permission on a single resource. Best for share dialogs and member lists. | Use `check` for a single permission gate. As soon as a detail page needs more than two or three permissions, prefer `listEffectivePermissions`—it returns the full permission set in one call instead of fanning out to multiple `check` requests. When the question is "which resources can this user access," use `listResourcesForMembership` rather than calling `check` once per candidate resource. --- ## Putting it all together Here's the complete flow for our project management app: ```text 1. Resource type hierarchy → Define workspace and project resource types in the Dashboard 2. Privileges → Create roles (workspace-admin, project-editor) with scoped permissions 3. Resources → Register workspaces and projects via API as users create them 4. Access → Assign roles to users on specific resources 5. Enforce → Check permissions before allowing actions 6. Discover → Query which resources a user can access for navigation and UI ``` The hierarchy does the heavy lifting. A single `workspace-admin` assignment grants access to every project in that workspace. When new projects are created, the admin automatically has access—no additional assignments needed. --- ## Next steps - [Resource Types](/fga/resource-types) – Design your hierarchy for different product patterns - [Roles and Permissions](/fga/roles-and-permissions) – Understand permission inheritance in depth - [Resources](/fga/resources) – Learn about external IDs, sync strategies, and modeling guidance - [Access Checks](/fga/access-checks) – JWT vs. API checks and integration patterns - [AuthKit Integration](/fga/authkit-integration) – Embed permissions in access tokens ### Share Button Build a share dialog that lists current members of a resource and grants or revokes access. ## What you'll build This guide shows how to build a share dialog—the kind that appears behind a "Share" button on a project, document, or workspace. The dialog lists everyone who already has access, distinguishes direct collaborators from people who inherited access from a parent, and lets the owner add or remove members. The example uses two resource types: workspaces contain projects. The share dialog lives on the project, and the workspace is the source of inherited access for members who weren't added to the project directly. By the end, you'll have: - Resource types, permissions, and roles configured for shareable projects - A member list rendered with [`listMembershipsForResource`](/fga/resource-discovery) - Direct versus inherited member labels using the `assignment` parameter - Per-member role labels using [`listRoleAssignmentsForResource`](/reference/fga/role-assignment/list-for-resource) - Endpoints to add a member, change a member's role, and remove a member ```text organization (implicit root) └─ workspace └─ project ``` --- ## 1. Model the hierarchy Create two resource types in the [WorkOS Dashboard](https://dashboard.workos.com/) under **Authorization > Resource Types**. The workspace is the parent of the project—anyone with a workspace-scoped role automatically appears as an inherited member of every project in the workspace. | Name | Slug | Parent | | ----------- | ----------- | ------------ | | `Workspace` | `workspace` | Organization | | `Project` | `project` | Workspace | For the full Dashboard walkthrough, see the [Quick Start](/fga/quick-start) guide. --- ## 2. Define roles and permissions The share dialog needs to answer two questions: who has access to this project, and what role do they have. Define the permissions and roles that back those operations. | Permission | Resource type | Description | | -------------- | ------------- | ------------------------------------------ | | `project:view` | project | View a project | | `project:edit` | project | Edit the project, including membership | | Role | Scoped to | Permissions | | ---------------- | --------- | --------------------------------- | | `project-viewer` | project | `project:view` | | `project-editor` | project | `project:view`, `project:edit` | The share dialog assigns one of these two roles to each new collaborator. Gating the management endpoints on `project:edit` means project editors can change membership, while viewers cannot. Workspace-scoped roles produce the inherited members shown in the dialog. A `workspace-admin` role that includes `project:view` and `project:edit` as child-type permissions grants project access to every project in the workspace without any direct project assignment. Those users appear in the indirect membership list with no direct role on the project. For more on how inheritance affects access, see [Roles and permissions](/fga/roles-and-permissions). --- ## 3. List who has access The core of the share dialog is the list of members. `listMembershipsForResource` returns every organization membership that has a permission on the resource. Using `permission_slug=project:view` returns everyone who can see the project at all. The `assignment` parameter controls whether inherited access is included: - `direct` returns only users who have a role assigned directly on this project - `indirect` returns everyone who can access the project, including via workspace or organization-scoped roles The share dialog typically needs both. Direct assignments show who was explicitly added. Indirect assignments show everyone who can see the project, including users who inherited access through a parent. ```javascript import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); app.get('/projects/:projectId/members', async (req, res) => { const { organizationMembershipId } = req.user; const { projectId } = req.params; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:view', resourceTypeSlug: 'project', resourceExternalId: projectId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } const project = await db.projects.findUnique({ where: { id: projectId } }); if (!project) { return res.status(404).json({ error: 'Not found' }); } const [{ data: allMembers }, { data: directMembers }] = await Promise.all([ workos.authorization.listMembershipsForResource({ resourceId: project.authzResourceId, permissionSlug: 'project:view', assignment: 'indirect', }), workos.authorization.listMembershipsForResource({ resourceId: project.authzResourceId, permissionSlug: 'project:view', assignment: 'direct', }), ]); const directIds = new Set(directMembers.map((m) => m.id)); const members = allMembers.map((member) => ({ id: member.id, user: member.user, accessSource: directIds.has(member.id) ? 'direct' : 'inherited', })); return res.json(members); }); ``` The handler runs two calls in parallel and uses the direct list as a lookup to label each indirect entry. The response includes the user object for each membership, so the dialog can render names and avatars without a second round trip. Store the WorkOS `authz_resource_id` on the project row when it's created. The `listMembershipsForResource` endpoint takes the internal resource ID rather than an external ID. --- ## 4. Add role labels for direct members The membership endpoint returns who has access but not what role they were assigned. To show "Alice — Editor" in the dialog, fetch role assignments for the resource and merge them with the member list. ```javascript async function loadProjectMembers(projectId, authzResourceId) { const [allMembers, directMembers, roleAssignments] = await Promise.all([ workos.authorization.listMembershipsForResource({ resourceId: authzResourceId, permissionSlug: 'project:view', assignment: 'indirect', }), workos.authorization.listMembershipsForResource({ resourceId: authzResourceId, permissionSlug: 'project:view', assignment: 'direct', }), workos.authorization.listRoleAssignmentsForResource({ resourceId: authzResourceId, }), ]); const directIds = new Set(directMembers.data.map((m) => m.id)); const roleByMembershipId = new Map( roleAssignments.data.map((a) => [a.organizationMembershipId, a]), ); return allMembers.data.map((member) => { const organizationMembershipId = member.id; const isDirect = directIds.has(organizationMembershipId); const assignment = roleByMembershipId.get(organizationMembershipId); return { id: organizationMembershipId, user: member.user, accessSource: isDirect ? 'direct' : 'inherited', role: isDirect ? assignment?.role.slug : null, roleAssignmentId: isDirect ? assignment?.id : null, }; }); } ``` `listRoleAssignmentsForResource` only returns assignments granted on this resource, which matches the set of direct members. Inherited members don't have a role on the project itself—their access comes from a role on a parent—so the role label is omitted for them. The React component renders each row with the user's name, role, and an "Inherited" pill for members who picked up access from a parent. ```jsx function MemberList({ members, currentUserId, onRoleChange, onRemove }) { return (
    {members.map((member) => (
  • {member.user.email} {member.accessSource === 'direct' ? ( onRoleChange(member.roleAssignmentId, member.id, role) } /> ) : ( Inherited from workspace )} {member.accessSource === 'direct' && member.user.id !== currentUserId && ( )}
  • ))}
); } ``` Inherited members can't be removed from the project directly—their access is controlled by the parent role. The dialog should reflect that by hiding the Remove and Role controls for inherited rows. --- ## 5. Share with a new member Adding a member is a single `assignRole` call. The dialog typically takes an email or organization membership ID, then assigns the chosen role on the project. ```javascript app.post('/projects/:projectId/members', async (req, res) => { const { organizationMembershipId } = req.user; const { projectId } = req.params; const { membershipId, roleSlug } = req.body; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:edit', resourceTypeSlug: 'project', resourceExternalId: projectId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } const assignment = await workos.authorization.assignRole({ organizationMembershipId: membershipId, roleSlug, resourceTypeSlug: 'project', resourceExternalId: projectId, }); return res.json(assignment); }); ``` Gate the endpoint on `project:edit` so only users who can edit the project can manage its members. The new assignment takes effect immediately—the next `check` for that user will return the new permissions. If the user being added isn't already an organization member, create the membership through the standard user flow first. FGA only assigns roles to existing organization memberships. --- ## 6. Change a member's role Role assignments are immutable. To change a member's role, delete the existing assignment and create a new one with the updated role. ```javascript app.patch( '/projects/:projectId/members/:membershipId/:roleAssignmentId', async (req, res) => { const { organizationMembershipId } = req.user; const { projectId, membershipId, roleAssignmentId } = req.params; const { roleSlug } = req.body; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:edit', resourceTypeSlug: 'project', resourceExternalId: projectId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } await workos.authorization.removeRoleAssignment({ organizationMembershipId: membershipId, roleAssignmentId, }); const updated = await workos.authorization.assignRole({ organizationMembershipId: membershipId, roleSlug, resourceTypeSlug: 'project', resourceExternalId: projectId, }); return res.json(updated); }, ); ``` The role assignment ID and the member's organization membership ID both come from the member list returned in step 4. There is a brief window between removing and reassigning where the user has no role on the project—if that matters, perform the operation inside a transaction or queue, and treat any failure as a rollback. --- ## 7. Remove a member Removing a direct member is a single `removeRoleAssignment` call. Pass the assignment ID and the member's organization membership ID from the member list. ```javascript app.delete( '/projects/:projectId/members/:membershipId/:roleAssignmentId', async (req, res) => { const { organizationMembershipId } = req.user; const { projectId, membershipId, roleAssignmentId } = req.params; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:edit', resourceTypeSlug: 'project', resourceExternalId: projectId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } await workos.authorization.removeRoleAssignment({ organizationMembershipId: membershipId, roleAssignmentId, }); return res.status(204).end(); }, ); ``` Access is revoked immediately. The member may still appear in the indirect list if they inherit access from a parent role—the dialog should reflect that by relabeling the row from "Direct" to "Inherited" after the delete. To revoke inherited access, the user's role on the parent resource (workspace or organization) needs to change. The share dialog should not attempt this from a project-scoped view; surface a hint to manage workspace access elsewhere. --- The same pattern works for any resource type. To share a workspace, swap `project` for `workspace` and use workspace-scoped roles. The membership and assignment endpoints work identically regardless of resource type. ### Multi-level Inheritance Model authorization for nested resources and permission-gated UI components. ## What you'll build This guide extends the [Basic App](/fga/model-your-app-basic) to a multi-level hierarchy where users navigate down through nested resources. At each level, the list shows only the resources the user can access. At the leaf, a detail page renders many UI components, each gated on a different permission. The example is a deployment platform with three resource types: workspaces contain projects, and projects contain apps. By the end, you'll have: - A three-level resource type hierarchy - Navigation views that list workspaces, then projects within a workspace, then apps within a project - An app detail page that fetches the user's effective permissions in a single call and renders the appropriate components - An understanding of when to use `listEffectivePermissions` instead of repeated `check` calls ```text organization (implicit root) └─ workspace └─ project └─ app ``` --- ## 1. Model the hierarchy Create three resource types in the [WorkOS Dashboard](https://dashboard.workos.com/) under **Authorization > Resource Types**. Each one points to its parent. | Name | Slug | Parent | | ----------- | ----------- | ------------ | | `Workspace` | `workspace` | Organization | | `Project` | `project` | Workspace | | `App` | `app` | Project | Permissions assigned higher in the hierarchy flow down. A user with a workspace-scoped role automatically has the corresponding access on every project and app inside that workspace. See [Resource types](/fga/resource-types) for hierarchy constraints and validation rules. --- ## 2. Define roles and permissions Define permissions for each resource type, then create roles that bundle them. Roles can include permissions for child types, which is what enables inheritance across the hierarchy. | Permission | Resource type | Description | | -------------------- | ------------- | ---------------------------- | | `workspace:view` | workspace | View a workspace | | `workspace:manage` | workspace | Edit workspace settings | | `project:view` | project | View a project | | `project:edit` | project | Edit a project | | `project:create_app` | project | Create apps inside a project | | `app:view` | app | View an app | | `app:deploy` | app | Deploy an app | | `app:configure` | app | Edit app settings | | `app:view_logs` | app | Read deployment logs | | `app:delete` | app | Delete an app | Bundle these into roles scoped to each resource type. A role scoped to `workspace` can include permissions on `project` and `app` because those are descendant types. | Role | Scoped to | Permissions | | ------------------ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `workspace-admin` | workspace | `workspace:view`, `workspace:manage`, `project:view`, `project:edit`, `project:create_app`, `app:view`, `app:deploy`, `app:configure`, `app:view_logs`, `app:delete` | | `workspace-member` | workspace | `workspace:view`, `project:view`, `app:view` | | `project-editor` | project | `project:view`, `project:edit`, `project:create_app`, `app:view`, `app:deploy`, `app:configure`, `app:view_logs` | | `app-deployer` | app | `app:view`, `app:deploy`, `app:view_logs` | A `workspace-admin` assignment on a single workspace grants full control of every project and app in it without any per-resource assignment. A `project-editor` assignment grants access to one project and its apps. An `app-deployer` assignment grants access to one app only. See [Roles and permissions](/fga/roles-and-permissions) for more on inheritance. --- ## 3. Register resources as they are created Register the corresponding FGA resource each time a workspace, project, or app is created in the database. Use the database ID as the `external_id` and reference the parent by its external ID and type. ```javascript import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); app.post('/workspaces', async (req, res) => { const { organizationId, organizationMembershipId } = req.user; const { name } = req.body; const workspace = await db.workspaces.create({ data: { name, organizationId }, }); await workos.authorization.createResource({ organizationId, resourceTypeSlug: 'workspace', externalId: workspace.id, name: workspace.name, }); await workos.authorization.assignRole({ organizationMembershipId, roleSlug: 'workspace-admin', resourceTypeSlug: 'workspace', resourceExternalId: workspace.id, }); return res.json(workspace); }); app.post('/workspaces/:workspaceId/projects', async (req, res) => { const { organizationId } = req.user; const { workspaceId } = req.params; const { name } = req.body; const project = await db.projects.create({ data: { name, workspaceId, organizationId }, }); await workos.authorization.createResource({ organizationId, resourceTypeSlug: 'project', externalId: project.id, name: project.name, parentResourceTypeSlug: 'workspace', parentResourceExternalId: workspaceId, }); return res.json(project); }); ``` Apps follow the same pattern with `parentResourceTypeSlug: 'project'`. Note that the workspace creator gets `workspace-admin`, which already includes every project and app permission. There's no need to create per-project or per-app assignments for the creator—inheritance handles it. --- ## 4. Navigate the hierarchy At each level, the UI lists the resources the user can access. ### List workspaces ```javascript app.get('/workspaces', async (req, res) => { const { organizationMembershipId } = req.user; const { data } = await workos.authorization.listResourcesForMembership({ organizationMembershipId, permissionSlug: 'workspace:view', resourceTypeSlug: 'workspace', }); const workspaces = await db.workspaces.findMany({ where: { id: { in: data.map((r) => r.externalId) } }, }); return res.json(workspaces); }); ``` Use [`listResourcesForMembership`](/fga/resource-discovery) with the appropriate `parent_resource` filter to scope results to the current view. ### List projects inside a workspace ```javascript app.get('/workspaces/:workspaceId/projects', async (req, res) => { const { organizationMembershipId } = req.user; const { workspaceId } = req.params; const { data } = await workos.authorization.listResourcesForMembership({ organizationMembershipId, permissionSlug: 'project:view', resourceTypeSlug: 'project', parentResourceTypeSlug: 'workspace', parentResourceExternalId: workspaceId, }); const projects = await db.projects.findMany({ where: { id: { in: data.map((r) => r.externalId) } }, }); return res.json(projects); }); ``` A user with `workspace-admin` on the workspace lists every project for the workspace, because `project:view` is included in the role through inheritance. A user with `project-editor` on a single project only lists that project. A user with neither role sees nothing. The app list follows the same pattern with `permission_slug=app:view` and `parent_resource_type_slug=project`. --- ## 5. Power the detail page with effective permissions The app detail page renders multiple components, each gated on a different permission. Rather than calling `check` once per component, use [`listEffectivePermissions`](/reference/fga/access-check/list-effective-permissions) to fetch every permission the user has on the resource in a single call. Inherited permissions from workspace and project roles are included automatically. ```javascript app.get('/apps/:appId', async (req, res) => { const { organizationMembershipId } = req.user; const { appId } = req.params; const { data: permissions } = await workos.authorization.listEffectivePermissionsByExternalId({ organizationMembershipId, resourceTypeSlug: 'app', externalId: appId, }); const slugs = new Set(permissions.map((p) => p.slug)); if (!slugs.has('app:view')) { return res.status(404).json({ error: 'Not found' }); } const app = await db.apps.findUnique({ where: { id: appId } }); if (!app) { return res.status(404).json({ error: 'Not found' }); } return res.json({ app, permissions: { canDeploy: slugs.has('app:deploy'), canConfigure: slugs.has('app:configure'), canViewLogs: slugs.has('app:view_logs'), canDelete: slugs.has('app:delete'), }, }); }); ``` The returned permission list reflects the user's full access on this resource, including everything inherited from roles on parent resources. A workspace admin sees every `app:*` permission here, even though they don't have any direct assignment on the app itself. The React component renders one section per permission: ```jsx function AppDetail() { const { appId } = useParams(); const { data, isLoading } = useQuery(`/apps/${appId}`); if (isLoading) return ; if (!data) return ; const { app, permissions } = data; return (

{app.name}

{permissions.canViewLogs && } {permissions.canDeploy && } {permissions.canConfigure && } {permissions.canDelete && }
); } ``` Every component above the fold is rendered based on the same permission set, fetched once. There are no waterfall requests as the page hydrates, and adding a new permission-gated component is a one-line change. --- ## 6. When to use each access check endpoint FGA exposes four endpoints for answering authorization questions. Pick the one that matches the shape of the question. | Endpoint | Use when | | ----------------------------- | -------------------------------------------------------------------------------------------------------------- | | `check` | A single permission on a single resource. Best for action handlers and route gates. | | `listEffectivePermissions` | Many permissions on a single resource. Best for detail pages that render multiple permission-gated components. | | `listResourcesForMembership` | A single permission across many resources. Best for list views, navigation, and pickers. | | `listMembershipsForResource` | All users who have a permission on a single resource. Best for share dialogs and member lists. | The pattern from the [Basic App](/fga/model-your-app-basic) used `check` for a single permission gate. As soon as the detail page needs more than two or three permissions, prefer `listEffectivePermissions`. It returns the full permission set in one call instead of fanning out to multiple `check` requests. The same applies in the opposite direction. When the question is "which resources can this user access," use `listResourcesForMembership` rather than calling `check` once per candidate resource. --- Inheritance is what makes this scale. A single workspace-admin assignment grants access to every project and app under that workspace. The list endpoints surface inherited access automatically, and the detail page sees the full inherited permission set in one fetch. ### High-Cardinality Data Use FGA to authorize high-cardinality data like documents, files, and messages without syncing them as resources. ## What you'll build This guide shows how to authorize high-cardinality data—documents, files, messages, rows—without syncing every record into FGA. The pattern keeps the high-volume entity in your database, stores a reference to its nearest FGA-managed parent, and runs every access check against the parent. The example is a document editor with three layers. Workspaces and projects are modeled in FGA. Documents stay in the application database, with a `project_id` reference linking each document to the project it belongs to. ```text organization (implicit root) └─ workspace ← in FGA └─ project ← in FGA └─ document ← in your database ``` By the end, you'll have: - A workspace and project hierarchy in FGA - Document permissions defined on the project resource type - A document table in your database that references its FGA-managed parent - Read, list, and search handlers that gate on the parent project - A clear rule for deciding what belongs in FGA and what stays in the database This guide builds on the patterns in [High-cardinality entities](/fga/high-cardinality-entities). --- ## 1. Decide what goes into FGA FGA is designed for stable, low-cardinality entities where users hold distinct roles—workspaces, projects, environments. High-cardinality entities like individual documents are different. They are created frequently, exist in volumes of thousands to millions per organization, and access is almost always inherited from a parent container rather than granted individually. Keep high-cardinality entities in your database and use FGA to authorize their containers. The database stays the source of truth for the entity, FGA stays the source of truth for access. For the full reasoning, see [High-cardinality entities](/fga/high-cardinality-entities). | Entity | Where | Why | | --------- | -------------------- | -------------------------------------------------------------- | | Workspace | FGA | Long-lived, low cardinality, distinct roles per user | | Project | FGA | Same as workspace | | Document | Application database | High volume, frequently created, access inherited from project | --- ## 2. Model the hierarchy Create two resource types in the [WorkOS Dashboard](https://dashboard.workos.com/) under **Authorization > Resource Types**. Documents are not modeled as a resource type—they only exist in the database. | Name | Slug | Parent | | ----------- | ----------- | ------------ | | `Workspace` | `workspace` | Organization | | `Project` | `project` | Workspace | --- ## 3. Define document permissions on the project type Document permissions are conceptually about documents, but they're defined on the project resource type because that's the FGA-managed parent. Permission slugs can use any naming convention, so the `document:` prefix clearly signals intent. | Permission | Resource type | Description | | ----------------- | ------------- | -------------------- | | `document:view` | project | View documents | | `document:edit` | project | Edit documents | | `document:create` | project | Create new documents | | `document:delete` | project | Delete documents | Bundle these into project-scoped roles. A user with `project-editor` on a project can view, edit, create, and delete every document in that project. A user with `project-viewer` can only read them. | Role | Scoped to | Permissions | | ---------------- | --------- | ---------------------------------------------------------------------- | | `project-editor` | project | `document:view`, `document:edit`, `document:create`, `document:delete` | | `project-viewer` | project | `document:view` | Roles assigned higher in the hierarchy inherit these permissions. A `workspace-admin` role can include all four document permissions, granting access to every document in every project under the workspace. --- ## 4. Store the parent reference in your database Every document row needs a stable reference to the project it belongs to. Use the project's external ID—the same ID that was used when registering the project with FGA. ```text documents ├─ id # The document's primary key ├─ project_id # FK to the project (matches the FGA external ID) ├─ title ├─ content └─ ... ``` When a document is created, save it with the project ID: ```javascript app.post('/projects/:projectId/documents', async (req, res) => { const { organizationMembershipId } = req.user; const { projectId } = req.params; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'document:create', resourceTypeSlug: 'project', resourceExternalId: projectId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } const document = await db.documents.create({ data: { projectId, title: req.body.title, content: req.body.content, }, }); return res.json(document); }); ``` There's no `createResource` call for the document because the document is not in FGA. The project ID stored on the row is enough to authorize every subsequent access. --- ## 5. Read a document To read a document, look it up in the database, then check the user's permission on its parent project. ```javascript app.get('/documents/:documentId', async (req, res) => { const { organizationMembershipId } = req.user; const { documentId } = req.params; const document = await db.documents.findUnique({ where: { id: documentId }, }); if (!document) { return res.status(404).json({ error: 'Not found' }); } const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'document:view', resourceTypeSlug: 'project', resourceExternalId: document.projectId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } return res.json(document); }); ``` The check uses the project as the resource and the document permission as the slug. FGA evaluates the user's role on the project—plus any inherited roles on the workspace or organization—and returns whether the permission applies. Update and delete handlers follow the same shape with `document:edit` and `document:delete`. --- ## 6. List documents inside a project When the user is already on a project page, listing the project's documents is a database query gated by a single check on the project itself. ```javascript app.get('/projects/:projectId/documents', async (req, res) => { const { organizationMembershipId } = req.user; const { projectId } = req.params; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'document:view', resourceTypeSlug: 'project', resourceExternalId: projectId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } const documents = await db.documents.findMany({ where: { projectId }, }); return res.json(documents); }); ``` One check authorizes the entire list, no matter how many documents the project contains. There's no per-document call because every document inherits the same project-level access. --- ## 7. List documents across projects A global search or "all my documents" view spans many projects. The pattern here is the inverse: first ask FGA for every project the user can read, then run a database query scoped to those project IDs. ```javascript app.get('/documents', async (req, res) => { const { organizationMembershipId } = req.user; const { data: accessibleProjects } = await workos.authorization.listResourcesForMembership( { organizationMembershipId, permissionSlug: 'document:view', resourceTypeSlug: 'project', limit: 100, }, ); const projectIds = accessibleProjects.map((p) => p.externalId); const documents = await db.documents.findMany({ where: { projectId: { in: projectIds } }, orderBy: { updatedAt: 'desc' }, take: 50, }); return res.json(documents); }); ``` This is a single FGA call for the project IDs followed by a single database query. There is no per-document permission check. For very large project counts, page through `listResourcesForMembership` with the `after` cursor and stream results to the client. --- ## 8. Nested folders When documents are nested in folders, the folder hierarchy lives in the database. Walk up the folder chain until reaching the FGA-managed parent, then run the check there. ```javascript async function findProjectForDocument(documentId) { const document = await db.documents.findUnique({ where: { id: documentId } }); if (!document) return null; let currentFolderId = document.folderId; const visited = new Set(); while (currentFolderId) { if (visited.has(currentFolderId)) { return null; } visited.add(currentFolderId); const folder = await db.folders.findUnique({ where: { id: currentFolderId }, }); if (!folder) return null; if (folder.projectId) { return folder.projectId; } currentFolderId = folder.parentFolderId; } return null; } ``` Use the returned project ID as the resource in the `check` call. Cap the traversal depth to guard against cycles and runaway queries. Caching the project ID directly on each document or folder row eliminates the walk entirely. --- ## 9. Cache the parent ID for performance The walk in the previous step works, but it requires database round trips for each folder. A common optimization is to store the FGA-managed parent ID directly on every descendant row. ```text documents ├─ id ├─ project_id # Denormalized for fast access checks ├─ folder_id # For UI navigation └─ ... ``` When a document or folder is moved between projects, update the `project_id` on every descendant in the move. The trade-off is more write work on move operations in exchange for one-step authorization on every read. --- ## 10. Share individual documents Inherited access covers the common case, but sometimes a single document is shared directly with a user who has no role on its project. Modeling every document in FGA to support this would defeat the purpose—but the set of _individually shared_ documents is far smaller than the set of all documents, so it's cheap to model on its own. Create a `shared-document` resource type with its own permissions, and register a resource only when a document is shared outside its project. The permissions live on a different resource type, so they need a distinct slug—`shared-document:view` on `shared-document` rather than `document:view` on `project`. At runtime, a document is accessible if the user inherits access from the project **or** has been granted access to that specific document: ```javascript const [project, shared] = await Promise.all([ workos.authorization.check({ organizationMembershipId, permissionSlug: 'document:view', resourceTypeSlug: 'project', resourceExternalId: document.projectId, }), workos.authorization.check({ organizationMembershipId, permissionSlug: 'shared-document:view', resourceTypeSlug: 'shared-document', resourceExternalId: document.id, }), ]); const authorized = project.authorized || shared.authorized; ``` This adds a second check only on the paths where direct sharing is possible. Documents that are never shared still authorize with a single project check, and FGA only stores the small number of documents that have actually been shared. --- The pattern scales because document volume never touches FGA. A million documents cost nothing—they all inherit access from the same handful of project assignments. ### Basic App Model authorization for a project management app with list and detail pages. ## What you'll build This guide shows how to use FGA in the two most common UI patterns in a B2B application: a list view that shows the resources a user can access, and a detail view that gates a single resource on a per-user permission. The example is a small project management application. By the end, you'll have: - A `project` resource type and a pair of roles - A `/projects` page that lists only the projects the signed-in user can access - A `/projects/:id` page that returns 404 if the user can't view it - Empty state handling for users with no accessible projects The model uses a single resource type under the organization. Deeper hierarchies are covered in the [Multi-level Inheritance](/fga/model-your-app-multi-level-inheritance) guide. ```text organization (implicit root) └─ project ``` --- ## 1. Model the hierarchy A single resource type works well for list and detail apps where every resource is a peer. There are no parent workspaces or nested sub-projects—just projects that belong to an organization. In the [WorkOS Dashboard](https://dashboard.workos.com/), navigate to **Authorization > Resource Types** and create one resource type: | Name | Slug | Parent | | --------- | --------- | ------------ | | `Project` | `project` | Organization | For the full Dashboard walkthrough, see the [Quick Start](/fga/quick-start) guide. --- ## 2. Define roles and permissions The list and detail views need to answer two questions: can the user view this project, and can the user edit it? Create three permissions and two roles, all scoped to the `project` resource type. | Permission | Resource type | Description | | ---------------- | ------------- | ---------------- | | `project:view` | project | View a project | | `project:edit` | project | Edit a project | | `project:delete` | project | Delete a project | | Role | Scoped to | Permissions | | ---------------- | --------- | ------------------------------------------------ | | `project-viewer` | project | `project:view` | | `project-editor` | project | `project:view`, `project:edit`, `project:delete` | Because the roles are scoped to `project`, each assignment grants access to exactly one project. For step-by-step instructions, see the [Quick Start](/fga/quick-start) guide. --- ## 3. Register projects as resources Resources should be registered as users create entities in your application. When a project is created in your database, create a matching FGA resource using the project's database ID as the `external_id` in WorkOS. This allows your application to reference projects in WorkOS by their own primary key. ```javascript import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); app.post('/projects', async (req, res) => { const { organizationId, organizationMembershipId } = req.user; const { name } = req.body; const project = await db.projects.create({ data: { name, organizationId, createdBy: organizationMembershipId }, }); await workos.authorization.createResource({ organizationId, resourceTypeSlug: 'project', externalId: project.id, name: project.name, }); await workos.authorization.assignRole({ organizationMembershipId, roleSlug: 'project-editor', resourceTypeSlug: 'project', resourceExternalId: project.id, }); return res.json(project); }); ``` Two operations run on every project creation. The project is registered as an FGA resource so it can be referenced in access checks, and the creator is assigned `project-editor` on the new project so they can edit it immediately. --- ## 4. Grant access to other users To share a project with a teammate, assign the appropriate role on that specific project: ```javascript await workos.authorization.assignRole({ organizationMembershipId: 'om_02HXYZ', roleSlug: 'project-viewer', resourceTypeSlug: 'project', resourceExternalId: 'proj_01H', }); ``` A single resource-scoped assignment grants access to that project only. See [Role assignments](/fga/assignments) for more on assignment management. --- ## 5. Power the list view The list view needs the set of projects the signed-in user can see. Use the [list resources for a user](/fga/resource-discovery) endpoint, filtering by `project:view`: ```javascript app.get('/projects', async (req, res) => { const { organizationMembershipId } = req.user; const { data: accessibleResources } = await workos.authorization.listResourcesForMembership({ organizationMembershipId, permissionSlug: 'project:view', resourceTypeSlug: 'project', limit: 50, }); const externalIds = accessibleResources.map((r) => r.externalId); const projects = await db.projects.findMany({ where: { id: { in: externalIds } }, }); return res.json(projects); }); ``` This is a common pattern: ask FGA for the resource IDs the user can access, then load the row data from your database. _FGA is the source of truth for access, and the database is the source of truth for project content._ A React component for the list looks like this: ```jsx function ProjectList() { const { data: projects, isLoading } = useQuery('/projects'); if (isLoading) return ; if (projects.length === 0) { return ( Create project} /> ); } return (
    {projects.map((project) => (
  • {project.name}
  • ))}
); } ``` The empty state covers two cases: a new user who hasn't created anything yet, and a user who has no access to any projects. ### Pagination `listResourcesForMembership` returns up to 100 results per page. For longer lists, pass the `after` cursor from the response to the next call. Match the page size to the page size of the UI to avoid fetching IDs that won't be rendered. --- ## 6. Power the detail view The detail view gates the page on a single permission: `project:view`. Run the check before loading the project, and return 404 if the user isn't authorized. ```javascript app.get('/projects/:projectId', async (req, res) => { const { organizationMembershipId } = req.user; const { projectId } = req.params; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:view', resourceTypeSlug: 'project', resourceExternalId: projectId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } const project = await db.projects.findUnique({ where: { id: projectId } }); if (!project) { return res.status(404).json({ error: 'Not found' }); } return res.json(project); }); ``` The React component renders the project. The backend has already verified that the user is allowed to view it. ```jsx function ProjectDetail() { const { projectId } = useParams(); const { data: project, isLoading } = useQuery(`/projects/${projectId}`); if (isLoading) return ; if (!project) return ; return (

{project.name}

{project.description}

); } ``` Gating individual UI elements like an Edit button is covered in the [Multi-level Inheritance](/fga/model-your-app-multi-level-inheritance) guide. --- ## 7. Handle empty and forbidden states Two patterns need explicit handling. **Empty list.** A user with no accessible projects should see a clear call to action rather than an empty page. The list component above handles this with an empty state that suggests creating a new project. **Forbidden detail page.** When a user navigates to a project they can't view, return 404 instead of 403. A 403 response confirms that the project exists, which can leak information across organization boundaries. The detail handler returns 404 for both unauthorized requests and missing projects. The same pattern applies to write endpoints. An edit request for a project the user can't view should also return 404, since acknowledging that the project exists reveals information. --- This is the smallest end-to-end FGA integration for an application with list and detail views. The other "Model your app" guides extend this shape with deeper hierarchies, high-cardinality children, and richer sharing flows. ### Protecting API Endpoints Use the check endpoint to protect every CRUD operation in your REST API. ## What you'll build This guide shows how to use the [`check`](/fga/access-checks) endpoint to protect every CRUD operation in a REST API. The same call pattern works across create, read, update, and delete handlers. The example is a project management API with two resource types: workspaces contain projects. By the end, you'll have: - A consistent pattern for gating handlers on a single permission check - Protected `POST`, `GET`, `PATCH`, and `DELETE` endpoints for projects - A reusable middleware that handles checks in one place - Security guidance on returning 404 versus 403 ```text organization (implicit root) └─ workspace └─ project ``` This guide uses only the `check` endpoint. For list endpoints, see [`listResourcesForMembership`](/fga/resource-discovery). For detail pages that gate multiple UI components, see [`listEffectivePermissions`](/fga/model-your-app-multi-level-inheritance). --- ## 1. The check pattern Every protected endpoint follows the same shape: identify the user, identify the resource, run a single `check` for the relevant permission, and proceed only if the check passes. ```javascript import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); async function performAction(req, res) { const { organizationMembershipId } = req.user; const { projectId } = req.params; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:view', resourceTypeSlug: 'project', resourceExternalId: projectId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } // Perform the action } ``` The check resolves all sources of access in one call—direct assignments on the project, inherited roles on the parent workspace, and organization-scoped roles. The handler does not need to walk the hierarchy or merge results. The permissions used in this guide: | Permission | Resource type | Used by | | ---------------- | ------------- | ---------------- | | `project:view` | project | Read endpoints | | `project:edit` | project | Update endpoints | | `project:delete` | project | Delete endpoints | | `project:create` | workspace | Create endpoint | --- ## 2. Read a resource A read handler checks `project:view` on the project before returning it. ```javascript app.get('/projects/:projectId', async (req, res) => { const { organizationMembershipId } = req.user; const { projectId } = req.params; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:view', resourceTypeSlug: 'project', resourceExternalId: projectId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } const project = await db.projects.findUnique({ where: { id: projectId } }); if (!project) { return res.status(404).json({ error: 'Not found' }); } return res.json(project); }); ``` The check runs before the database lookup. Authorization should be evaluated independently of whether the row exists in the database. --- ## 3. Create a resource A create handler checks `project:create` on the parent workspace. The project itself does not exist yet, so the check applies to the resource the new project will belong to. ```javascript app.post('/workspaces/:workspaceId/projects', async (req, res) => { const { organizationId, organizationMembershipId } = req.user; const { workspaceId } = req.params; const { name } = req.body; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:create', resourceTypeSlug: 'workspace', resourceExternalId: workspaceId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } const project = await db.projects.create({ data: { name, workspaceId, organizationId }, }); await workos.authorization.createResource({ organizationId, resourceTypeSlug: 'project', externalId: project.id, name: project.name, parentResourceTypeSlug: 'workspace', parentResourceExternalId: workspaceId, }); return res.json(project); }); ``` `project:create` is defined on the project resource type but is included as a child-type permission in workspace-scoped roles like `workspace-admin`. Asking whether the user has `project:create` on the workspace returns true if any role assignment on the workspace bundles that permission. The same pattern works for top-level resources. To check whether a user can create a workspace, run `check` with `resourceTypeSlug: 'organization'` and the organization's ID as the external ID. --- ## 4. Update a resource An update handler checks `project:edit` on the project before applying the change. ```javascript app.patch('/projects/:projectId', async (req, res) => { const { organizationMembershipId } = req.user; const { projectId } = req.params; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:edit', resourceTypeSlug: 'project', resourceExternalId: projectId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } const project = await db.projects.update({ where: { id: projectId }, data: req.body, }); return res.json(project); }); ``` Run a separate check for any operation that requires a different permission. A `PATCH` that moves a project between workspaces, for example, should check both `project:edit` on the project and `project:create` on the destination workspace. --- ## 5. Delete a resource A delete handler checks `project:delete` on the project before removing it. ```javascript app.delete('/projects/:projectId', async (req, res) => { const { organizationMembershipId, organizationId } = req.user; const { projectId } = req.params; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:delete', resourceTypeSlug: 'project', resourceExternalId: projectId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } await db.projects.delete({ where: { id: projectId } }); await workos.authorization.deleteResourceByExternalId({ organizationId, resourceTypeSlug: 'project', externalId: projectId, }); return res.status(204).end(); }); ``` Delete the FGA resource after the database delete completes. This keeps the two systems in sync and removes any role assignments that were attached to the project. See [Resources](/fga/resources) for cascade behavior on resources with children. --- ## 6. A reusable check middleware Every handler above runs the same three steps: pull the membership and resource ID from the request, call `check`, return 404 if it fails. Lifting that into a middleware keeps the route handlers focused on business logic. ```javascript function requirePermission({ permissionSlug, resourceTypeSlug, paramName }) { return async (req, res, next) => { const { organizationMembershipId } = req.user; const externalId = req.params[paramName]; const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug, resourceTypeSlug, resourceExternalId: externalId, }); if (!authorized) { return res.status(404).json({ error: 'Not found' }); } return next(); }; } ``` The CRUD routes become declarative: ```javascript app.get( '/projects/:projectId', requirePermission({ permissionSlug: 'project:view', resourceTypeSlug: 'project', paramName: 'projectId', }), getProjectHandler, ); app.post( '/workspaces/:workspaceId/projects', requirePermission({ permissionSlug: 'project:create', resourceTypeSlug: 'workspace', paramName: 'workspaceId', }), createProjectHandler, ); app.patch( '/projects/:projectId', requirePermission({ permissionSlug: 'project:edit', resourceTypeSlug: 'project', paramName: 'projectId', }), updateProjectHandler, ); app.delete( '/projects/:projectId', requirePermission({ permissionSlug: 'project:delete', resourceTypeSlug: 'project', paramName: 'projectId', }), deleteProjectHandler, ); ``` The check now lives in one place. New routes opt in by adding the middleware with the right permission and resource type. --- ## 7. Return 404 instead of 403 Every example in this guide returns 404 when the check fails, not 403. A 403 confirms that the resource exists, which can leak information across organization boundaries. A user who guesses a project ID belonging to another organization should not be able to tell whether the project exists. There is one exception: when authorization fails on the parent resource for a create operation, returning 403 is acceptable because the parent resource is already in a URL the user is allowed to know about (the workspace they just opened). For example, `POST /workspaces/:workspaceId/projects` can return 403 if the user has `workspace:view` but not `project:create`, because the user already knows the workspace exists. A practical rule: - If the user cannot see the resource at all, return 404 - If the user can see the resource but cannot perform this action, return 403 For most CRUD endpoints, the simpler choice is 404 for everything. --- `check` is enough for every CRUD endpoint because it resolves the full hierarchy in one call. There is no need to look up parent resources, walk roles, or merge permission sets in the application. ### Migrate from SpiceDB Map your SpiceDB schema to WorkOS FGA resource types, roles, and permissions. ## Overview This guide helps you migrate from SpiceDB (AuthZed) to WorkOS FGA. SpiceDB implements Google's Zanzibar paper with a `.zed` schema DSL, explicit relationship storage, and permission computation. WorkOS FGA takes a different approach: hierarchical role-based access control with automatic permission inheritance. --- ## Key differences | SpiceDB Concept | WorkOS FGA Equivalent | | ---------------------------------- | ----------------------------------- | | `definition` | Resource Type | | `relation` | Role assignment relationship | | `permission` | Permission on a role | | Relationships | Role Assignments | | Subject relations (`group#member`) | Organization Memberships | | `->` (arrow) | Native hierarchical inheritance | | Caveats | Check conditions in app code | | `-` (exclusion) | Permission exclusions (coming soon) | ### Architecture shift SpiceDB requires writing schema in `.zed` files and explicitly storing relationships. WorkOS FGA simplifies this: 1. **Permissions flow down automatically** — A role at a parent level grants access to all children without additional relationships 2. **Roles are scoped to resource types** — Each resource type has its own set of roles 3. **Single parent per resource instance** — Each resource instance has exactly one parent, creating predictable traversal paths 4. **No schema DSL** — Configure resource types, roles, and permissions in the Dashboard 5. **Native WorkOS integration** — Works seamlessly with AuthKit, SSO, Directory Sync, and IdP role assignment ### WorkOS product integration Unlike standalone authorization systems, WorkOS FGA integrates natively with the WorkOS identity platform (although it [can be used standalone](/fga/standalone-integration)): - **AuthKit Integration** — Organization-scoped roles and permissions are embedded in access tokens for instant JWT-based checks - **IdP Role Assignment** — Map identity provider groups (Okta, Azure AD, Google Workspace) directly to organization-scoped roles - **Directory Sync** — Automatically provision and deprovision users with appropriate role assignments when group memberships change - **SSO** — Enterprise SSO users get role assignments based on IdP group membership during authentication --- ## SpiceDB syntax reference Key operators in SpiceDB: - `+` (union) — subject has either relation - `&` (intersection) — subject must have both relations - `-` (exclusion) — subject has left but not right - `->` (arrow) — traverse to parent's permission --- ## Step 1: Map definitions to resource types Extract `definition` blocks from your SpiceDB schema. These become resource types in WorkOS FGA. **Create resource types for:** - Business containers: organizations, workspaces, projects, environments - Shareable entities: apps, pipelines, repositories, dashboards **Exclude:** - `definition user {}` — Use Organization Memberships as subjects ### Example ```text # SpiceDB definition user {} definition workspace {} definition project {} # WorkOS FGA Resource Types organization (built-in) └── workspace └── project ``` Navigate to **Authorization > Resource Types** in the [Dashboard](/fga/resource-types/creating-and-managing-resource-types/using-the-dashboard) to create your hierarchy. --- ## Step 2: Establish hierarchy Map SpiceDB parent relations to WorkOS FGA parent-child resource type relationships. ### SpiceDB pattern ```text definition project { relation parent: workspace permission read = reader + parent->read } ``` ### WorkOS FGA equivalent Create a `workspace` resource type with `organization` as its parent. Create a `project` resource type with `workspace` as its parent. The parent relationship is defined at the resource type level. When you register individual project resources instances via the API, you specify the parent workspace. Permissions flow down this hierarchy without explicit operations. --- ## Step 3: Convert relations to roles SpiceDB relations that grant access become roles in WorkOS FGA. SpiceDB permissions guide which permissions to include in each role. ### SpiceDB pattern ```text definition project { relation reader: user relation writer: user relation owner: user permission view = reader + writer + owner permission edit = writer + owner permission manage = owner } ``` ### WorkOS FGA equivalent Create roles on the `project` resource type: | Role | Permissions | | ------ | ------------------------------------------------ | | reader | `project:view` | | writer | `project:view`, `project:edit` | | owner | `project:view`, `project:edit`, `project:manage` | The `+` unions in SpiceDB become permissions bundled into roles. > **Permission slug convention:** Permission slugs are arbitrary text, but we recommend the pattern `{resource-type}:{action}` for clarity. Each permission must be explicitly scoped to a resource type in the Dashboard—[see more about permissions](/fga/roles-and-permissions). When a role includes permissions scoped to child resource types (like `project:view` on a workspace role), it grants that permission on all child resources of that type. --- ## Step 4: Handle arrow operations SpiceDB arrows (`->`) traverse to a parent's permission. WorkOS FGA handles this through native hierarchical inheritance. ### SpiceDB pattern ```text definition workspace { relation viewer: user permission view = viewer } definition project { relation parent: workspace relation viewer: user permission view = viewer + parent->view } ``` ### WorkOS FGA equivalent Create a `workspace` resource type with a role that includes child-type permissions: | Role (on workspace) | Permissions | | ------------------- | -------------------------------- | | viewer | `workspace:view`, `project:view` | When you assign `workspace:viewer` to a user, they automatically get `project:view` on all projects within that workspace. The arrow traversal is replaced by native inheritance. --- ## Step 5: Map permission operators | SpiceDB Operator | WorkOS FGA Equivalent | | ------------------ | ----------------------------------- | | `+` (union) | Multiple permissions in a role | | `&` (intersection) | Check both conditions in app code | | `-` (exclusion) | Permission exclusions (coming soon) | | `->` (arrow) | Native hierarchical inheritance | ### Intersection example ```javascript // SpiceDB: permission admin = writer & reader // WorkOS FGA: Check both conditions in your app const canRead = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:read', resourceExternalId: projectId, resourceTypeSlug: 'project', }); const canWrite = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:write', resourceExternalId: projectId, resourceTypeSlug: 'project', }); const isAdmin = canRead.authorized && canWrite.authorized; ``` ### Caveats SpiceDB caveats allow conditional access based on runtime context. Implement these checks in your application instead. This keeps the check interface simple and puts conditional logic next to the data it depends on. ```javascript // Check IP allowlist before FGA call const clientIp = req.headers['x-forwarded-for']; const allowedCidrs = await getAllowedCidrs(resourceId); if (!isIpInCidrs(clientIp, allowedCidrs)) { return { authorized: false }; } // Then check FGA permissions const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:view', resourceExternalId: resourceId, resourceTypeSlug: 'project', }); ``` --- ## High-cardinality entities Not everything belongs in FGA. We recommend using FGA for lower-cardinality resources (organizations, workspaces, projects) and handling high-cardinality entities (files, messages, comments) in your application. Syncing millions of entities into FGA creates reconciliation overhead, race conditions, and consistency challenges. Instead, check access at the parent container level and filter entities in your application. This pattern also replaces SpiceDB's caveats for many use cases — instead of conditional relationships stored in SpiceDB, you handle the conditions in your app before the FGA check. For detailed guidance on this pattern, see [High-Cardinality Entities](/fga/high-cardinality-entities). --- ## Migration steps 1. **Analyze `.zed` schema** — Identify definitions, relations, and permissions 2. **Define resource types** in the WorkOS Dashboard matching your definitions 3. **Define permissions** for each type (e.g., `view`, `edit`, `manage`) 4. **Create roles** that bundle permissions, including child-type permissions for inheritance 5. **Register resources** via API when entities are created 6. **Migrate relationships** to role assignments 7. **Replace SpiceDB checks** with WorkOS FGA `check` API calls ### API migration **SpiceDB CheckPermission (JavaScript):** ```javascript const { authorized } = await client.checkPermission( v1.CheckPermissionRequest.create({ resource: v1.ObjectReference.create({ objectType: 'project', objectId: 'proj_123', }), permission: 'view', subject: v1.SubjectReference.create({ object: v1.ObjectReference.create({ objectType: 'user', objectId: 'user_456', }), }), }), ); ``` **WorkOS FGA Check (JavaScript):** ```javascript const { authorized } = await workos.authorization.check({ organizationMembershipId: 'om_01HXYZ', // available in a session token or via the API permissionSlug: 'project:view', resourceTypeSlug: 'project', resourceExternalId: 'proj_123', }); ``` --- ## Example migration ### SpiceDB schema ```text definition user {} definition organization { relation admin: user relation member: user permission manage = admin permission access = admin + member } definition workspace { relation org: organization relation viewer: user relation editor: user permission view = org->access + viewer + editor permission edit = org->admin + editor } definition project { relation workspace: workspace relation contributor: user permission view = workspace->view + contributor permission edit = workspace->edit + contributor } ``` ### WorkOS FGA equivalent **Resource type hierarchy:** ```text organization (built-in) └── workspace └── project ``` **Roles for `organization`:** | Role | Permissions | | ------ | -------------------------------------------------------------------------------- | | member | `organization:access`, `workspace:view`, `project:view` | | admin | All member permissions + `organization:manage`, `workspace:edit`, `project:edit` | **Roles for `workspace`:** | Role | Permissions | | ------ | ------------------------------------------------------------------ | | viewer | `workspace:view`, `project:view` | | editor | `workspace:view`, `workspace:edit`, `project:view`, `project:edit` | **Roles for `project`:** | Role | Permissions | | ----------- | ------------------------------ | | contributor | `project:view`, `project:edit` | **Key insights:** - `org->access` arrow — Replaced by org member role including workspace/project view - `workspace->edit` arrow — Replaced by workspace editor role including project edit - No explicit traversals needed — Inheritance happens automatically --- ## Next steps - [Resource Types](/fga/resource-types) — Design your hierarchy - [Roles and Permissions](/fga/roles-and-permissions) — Configure inheritance patterns - [AuthKit Integration](/fga/authkit-integration) — Embed permissions in access tokens - [IdP Role Assignment](/fga/idp-role-assignment) — Map IdP groups to roles - [Assignments](/fga/assignments) — Migrate your relationships to role assignments - [Access Checks](/fga/access-checks) — Replace SpiceDB check calls ### Migrate from Oso Cloud Map your Oso Cloud Polar policies to WorkOS FGA resource types, roles, and permissions. ## Overview This guide helps you migrate from Oso Cloud to WorkOS FGA. Oso Cloud uses the Polar language to define authorization policies with explicit fact storage. WorkOS FGA takes a different approach: hierarchical role-based access control with automatic permission inheritance configured through a Dashboard. --- ## Key differences | Oso Cloud Concept | WorkOS FGA Equivalent | | -------------------- | --------------------------------- | | `resource` blocks | Resource Types | | `roles` array | Roles | | `permissions` array | Permissions | | `relations` | Parent-child hierarchy | | `has_role` facts | Role Assignments | | `has_relation` facts | Resource registration with parent | | `actor User {}` | Organization Memberships | | Local Authorization | App-side traversal (see below) | | Polar DSL | Dashboard configuration | ### Architecture shift Oso Cloud requires you to write Polar policies and manage facts. WorkOS FGA simplifies this: 1. **Permissions flow down automatically** — A role at a parent level grants access to all children without additional facts 2. **Roles are scoped to resource types** — Each resource type has its own set of roles 3. **Single parent per resource instance** — Each resource instance has exactly one parent, creating predictable traversal paths 4. **No policy DSL** — Configure resource types, roles, and permissions in the Dashboard 5. **Native WorkOS integration** — Works seamlessly with AuthKit, SSO, Directory Sync, and IdP role assignment ### WorkOS product integration Unlike standalone authorization systems, WorkOS FGA integrates natively with the WorkOS identity platform (although it [can be used standalone](/fga/standalone-integration)): - **AuthKit Integration** — Organization-scoped roles and permissions are embedded in access tokens for instant JWT-based checks - **IdP Role Assignment** — Map identity provider groups (Okta, Azure AD, Google Workspace) directly to organization-scoped roles - **Directory Sync** — Automatically provision and deprovision users with appropriate role assignments when group memberships change - **SSO** — Enterprise SSO users get role assignments based on IdP group membership during authentication --- ## Polar syntax reference Key patterns in Oso Polar: - `roles = [...]` — Define available roles on a resource - `permissions = [...]` — Define available permissions - `relations = {...}` — Define relationships to other resources - `"permission" if "role"` — Grant permission to role - `"role" if "role"` — Role inheritance - `role if role on "relation"` — Inherit roles from related resource --- ## Step 1: Map resources to resource types Extract `resource` blocks from your Polar policy. These become resource types in WorkOS FGA. **Create resource types for:** - Business containers: organizations, workspaces, projects, environments - Shareable entities: apps, pipelines, repositories, dashboards **Exclude:** - `actor User {}` — Use Organization Memberships as subjects instead - `actor Group {}` — User groups are coming soon; for now, assign roles directly to users ### Example ```text # Oso Cloud actor User {} resource Organization {} resource Workspace {} resource Project {} # WorkOS FGA Resource Types organization (built-in) └── workspace └── project ``` Navigate to **Authorization > Resource Types** in the [Dashboard](/fga/resource-types/creating-and-managing-resource-types/using-the-dashboard) to create your hierarchy. --- ## Step 2: Establish hierarchy Map Oso `relations` to WorkOS FGA parent-child resource type relationships. ### Oso Cloud pattern ```text resource Project { relations = { workspace: Workspace }; } ``` ### WorkOS FGA equivalent Create a `workspace` resource type with `organization` as its parent. Create a `project` resource type with `workspace` as its parent. The parent relationship is defined at the resource type level. When you register individual project resources instances via the API, you specify the parent workspace. Permissions flow down this hierarchy without explicit facts. --- ## Step 3: Convert roles and permissions Oso `roles` and `permissions` arrays map directly to WorkOS FGA roles and permissions. ### Oso Cloud pattern ```text resource Project { roles = ["viewer", "editor", "admin"]; permissions = ["read", "write", "manage"]; "read" if "viewer"; "write" if "editor"; "manage" if "admin"; "viewer" if "editor"; "editor" if "admin"; } ``` ### WorkOS FGA equivalent Create roles on the `project` resource type: | Role | Permissions | | ------ | ------------------------------------------------- | | viewer | `project:read` | | editor | `project:read`, `project:write` | | admin | `project:read`, `project:write`, `project:manage` | The role inheritance (`"viewer" if "editor"`) becomes permissions bundled into roles. Higher-privilege roles include all permissions from lower-privilege roles. > **Permission slug convention:** Permission slugs are arbitrary text, but we recommend the pattern `{resource-type}:{action}` for clarity. Each permission must be explicitly scoped to a resource type in the Dashboard—[see more about permissions](/fga/roles-and-permissions). When a role includes permissions scoped to child resource types (like `project:read` on a workspace role), it grants that permission on all child resources of that type. --- ## Step 4: Handle role inheritance via relations Oso's `role if role on "relation"` pattern is replaced by native hierarchical inheritance. ### Oso Cloud pattern ```text resource Workspace { roles = ["viewer", "editor"]; } resource Project { permissions = ["read", "write"]; relations = { workspace: Workspace }; role if role on "workspace"; } ``` ### WorkOS FGA equivalent Create a `workspace` resource type with roles that include child-type permissions: | Role (on workspace) | Permissions | | ------------------- | -------------------------------------------------------------------- | | viewer | `workspace:read`, `project:read` | | editor | `workspace:read`, `workspace:write`, `project:read`, `project:write` | When you assign `workspace:viewer` to a user, they automatically get `project:read` on all projects within that workspace. No explicit per-project facts needed. --- ## Step 5: Map permission patterns | Oso Cloud Pattern | WorkOS FGA Equivalent | | -------------------------------------- | --------------------------------------------- | | `"permission" if "role"` | Permission included in role | | `"role" if "role"` | Higher role includes lower role's permissions | | `role if role on "relation"` | Native inheritance (automatic) | | `"permission" if "role" on "relation"` | Include permission in parent role | | Custom Polar rules | Check conditions in app code | | `and` expressions | Check multiple conditions in app code | | `not` expressions | Permission exclusions (coming soon) | --- ## Replacing Local Authorization Oso's Local Authorization generates SQL queries that you run against your database. WorkOS FGA takes a different approach: keep high-cardinality data in your database and traverse to FGA-managed resources in your application code. ### Why this approach? - **Simpler architecture** — No SQL generation or policy-database mapping configuration - **Clearer boundaries** — FGA handles coarse-grained access, your app handles fine-grained filtering - **Better performance** — Single parent traversal path, no complex joins - **No config drift** — Authorization logic lives in your code, not a separate YAML file ### Example: file access via parent project Instead of configuring Local Authorization mappings, look up the parent resource and check access there: ```typescript async function canUserAccessFile( organizationMembershipId: string, fileId: string, ): Promise { // 1. Look up the file to find its parent project const file = await db.files.findUnique({ where: { id: fileId } }); if (!file) return false; // 2. Check access at the project level (FGA-managed) const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:view', resourceTypeSlug: 'project', resourceExternalId: file.projectId, }); return authorized; } ``` This replaces Oso's Local Authorization YAML configuration: ```yaml # Oso Local Authorization config (no longer needed) facts: has_relation(File:_, parent, Project:_): query: SELECT id, project_id FROM files has_role(User:_, String:_, Project:_): query: SELECT user_id, role, project_id FROM project_memberships sql_types: File: UUID Project: UUID ``` With this approach, traversal logic lives in your application code where it's easier to test, debug, and version alongside your business logic. --- ## High-cardinality entities Not everything belongs in FGA. We recommend using FGA for lower-cardinality resources (organizations, workspaces, projects) and handling high-cardinality entities (files, messages, comments) in your application. Syncing millions of entities into FGA creates reconciliation overhead, race conditions, and consistency challenges. Instead, check access at the parent container level and filter entities in your application. For detailed guidance on this pattern, see [High-Cardinality Entities](/fga/high-cardinality-entities). --- ## Migration steps 1. **Analyze Polar policy** — Identify resource blocks, roles, permissions, and relations 2. **Define resource types** in the WorkOS Dashboard matching your resources 3. **Define permissions** for each type (e.g., `read`, `write`, `manage`) 4. **Create roles** that bundle permissions, including child-type permissions for inheritance 5. **Register resources** via API when entities are created in your app 6. **Migrate facts** — Convert `has_role` to role assignments, `has_relation` to resource registration 7. **Replace Oso checks** with WorkOS FGA `check` API calls 8. **Replace Local Authorization** with app-side traversal for high-cardinality entities ### API migration **Oso Cloud authorize (JavaScript):** ```javascript const authorized = await oso.authorize({ type: 'User', id: 'alice' }, 'read', { type: 'Project', id: 'proj_123', }); ``` **WorkOS FGA Check (JavaScript):** ```javascript const { authorized } = await workos.authorization.check({ organizationMembershipId: 'om_01HXYZ', // available in a session token or via the API permissionSlug: 'project:read', resourceTypeSlug: 'project', resourceExternalId: 'proj_123', }); ``` --- ## Example migration ### Oso Cloud policy ```text actor User {} resource Organization { roles = ["admin", "member"]; permissions = ["manage", "read"]; "read" if "member"; "manage" if "admin"; "member" if "admin"; } resource Workspace { roles = ["viewer", "editor"]; permissions = ["read", "write"]; relations = { organization: Organization }; role if role on "organization"; "viewer" if "member" on "organization"; "editor" if "admin" on "organization"; "read" if "viewer"; "write" if "editor"; } resource Project { relations = { workspace: Workspace }; "read" if "viewer" on "workspace"; "write" if "editor" on "workspace"; } ``` ### WorkOS FGA equivalent **Resource type hierarchy:** ```text organization (built-in) └── workspace └── project ``` **Roles for `organization`:** | Role | Permissions | | ------ | ---------------------------------------------------------------------------------- | | member | `organization:read`, `workspace:read`, `project:read` | | admin | All member permissions + `organization:manage`, `workspace:write`, `project:write` | **Roles for `workspace`:** | Role | Permissions | | ------ | -------------------------------------------------------------------- | | viewer | `workspace:read`, `project:read` | | editor | `workspace:read`, `workspace:write`, `project:read`, `project:write` | **Key insights:** - `role if role on "organization"` — Replaced by org roles including workspace/project permissions - `"viewer" if "member" on "organization"` — Org member role includes workspace:read - No explicit Polar rules needed — Inheritance happens automatically --- ## Next steps - [Resource Types](/fga/resource-types) — Design your hierarchy - [Roles and Permissions](/fga/roles-and-permissions) — Configure inheritance patterns - [AuthKit Integration](/fga/authkit-integration) — Embed permissions in access tokens - [IdP Role Assignment](/fga/idp-role-assignment) — Map IdP groups to roles - [Assignments](/fga/assignments) — Migrate your facts to role assignments - [Access Checks](/fga/access-checks) — Replace Oso authorize calls ### Migrate from OpenFGA Map your OpenFGA authorization model to WorkOS FGA resource types, roles, and permissions. ## Overview This guide helps you migrate from OpenFGA to WorkOS FGA. While both systems are inspired by Google's Zanzibar paper, they take different approaches. OpenFGA uses relation-based access control (ReBAC) with explicit tuple storage, while WorkOS FGA uses hierarchical role-based access control (RBAC) with automatic permission inheritance. --- ## Key differences | OpenFGA Concept | WorkOS FGA Equivalent | | --------------------------- | ----------------------------------- | | Types | Resource Types | | Relations | Roles + Permissions | | Tuples | Role Assignments | | User sets | Organization Memberships | | Computed relations (`from`) | Native hierarchical inheritance | | Contextual tuples | Check conditions in app code | | `but not` exclusions | Permission exclusions (coming soon) | ### Architecture shift OpenFGA requires a schema DSL and explicit tuples for every relationship. WorkOS FGA simplifies this: 1. **Permissions flow down automatically** — A role at a parent level grants access to all children without additional tuples 2. **Roles are scoped to resource types** — Each resource type has its own set of roles 3. **Single parent per resource instance** — Each resource instance has exactly one parent, creating predictable traversal paths 4. **No schema DSL** — Configure resource types, roles, and permissions in the Dashboard 5. **Native WorkOS integration** — Works seamlessly with AuthKit, SSO, Directory Sync, and IdP role assignment ### WorkOS product integration Unlike standalone authorization systems, WorkOS FGA integrates natively with the WorkOS identity platform (although it [can be used standalone](/fga/standalone-integration)): - **AuthKit Integration** — Organization-scoped roles and permissions are embedded in access tokens for instant JWT-based checks - **IdP Role Assignment** — Map identity provider groups (Okta, Azure AD, Google Workspace) directly to organization-scoped roles - **Directory Sync** — Automatically provision and deprovision users with appropriate role assignments when group memberships change - **SSO** — Enterprise SSO users get role assignments based on IdP group membership during authentication --- ## Step 1: Map types to resource types Extract domain objects from your OpenFGA `type` definitions. These become resource types in WorkOS FGA. **Create resource types for:** - Business containers: organizations, workspaces, projects, environments - Shareable entities: apps, pipelines, repositories, dashboards **Exclude:** - `type user` — Use Organization Memberships as subjects instead - `type group` — User groups are coming soon; for now, assign roles directly to users ### Example ```text # OpenFGA type user type organization type workspace type project # WorkOS FGA Resource Types organization (built-in) └── workspace └── project ``` Navigate to **Authorization > Resource Types** in the [Dashboard](/fga/resource-types/creating-and-managing-resource-types/using-the-dashboard) to create your hierarchy. --- ## Step 2: Establish hierarchy Map OpenFGA parent relations to WorkOS FGA parent-child resource type relationships. ### OpenFGA pattern ```text type workspace relations define viewer: [user] type project relations define parent: [workspace] define viewer: viewer from parent ``` ### WorkOS FGA equivalent Create a `project` resource type with `workspace` as its parent. The parent relationship is defined at the resource type level. When you register individual project resources instances via the API, they automatically inherit from their workspace. Permissions flow down this hierarchy without explicit tuples. --- ## Step 3: Translate relations to roles OpenFGA relations like `viewer`, `editor`, and `admin` become roles scoped to resource types. ### OpenFGA pattern ```text type project relations define viewer: [user] define editor: [user] or viewer define owner: [user] or editor ``` ### WorkOS FGA equivalent Create roles on the `project` resource type: | Role | Permissions | | ------ | ------------------------------------------------ | | viewer | `project:view` | | editor | `project:view`, `project:edit` | | owner | `project:view`, `project:edit`, `project:manage` | The `or` unions in OpenFGA become multiple permissions bundled into a single role. > **Permission slug convention:** Permission slugs are arbitrary text, but we recommend the pattern `{resource-type}:{action}` for clarity. Each permission must be explicitly scoped to a resource type in the Dashboard—[see more about permissions](/fga/roles-and-permissions). When a role includes permissions scoped to child resource types (like `project:view` on a workspace role), it grants that permission on all child resources of that type. --- ## Step 4: Handle computed relations OpenFGA computed relations using the `from` keyword are replaced by native hierarchical inheritance. ### OpenFGA pattern ```text type workspace relations define viewer: [user] type project relations define parent: [workspace] define viewer: viewer from parent ``` ### WorkOS FGA equivalent Create a `workspace` resource type with a role that includes child-type permissions: | Role (on workspace) | Permissions | | ------------------- | -------------------------------- | | viewer | `workspace:view`, `project:view` | When you assign `workspace:viewer` to a user, they automatically get `project:view` on all projects within that workspace. No explicit per-project tuples needed. --- ## Step 5: Map grant patterns | OpenFGA Pattern | WorkOS FGA Equivalent | | -------------------------- | ------------------------------------------------ | | Direct user tuple | Role assignment on resource | | `[type#relation]` usersets | Role includes child-type permissions (automatic) | | `or` unions | Multiple permissions in a role | | `and` intersections | Check both conditions in app code | | `but not` exclusions | Permission exclusions (coming soon) | ### Contextual tuples OpenFGA contextual tuples allow passing runtime context with permission checks. With WorkOS FGA, handle these checks in your application code instead. This keeps the check interface simple and puts conditional logic next to the data it depends on. ```javascript // Check time-based access in your app const now = new Date(); const accessWindow = await getAccessWindow(resourceId); if (now < accessWindow.start || now > accessWindow.end) { return { authorized: false }; } // Then check FGA permissions const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:view', resourceExternalId: resourceId, resourceTypeSlug: 'project', }); ``` --- ## High-cardinality entities Not everything belongs in FGA. We recommend using FGA for lower-cardinality resources (organizations, workspaces, projects) and handling high-cardinality entities (files, messages, comments) in your application. Syncing millions of entities into FGA creates reconciliation overhead, race conditions, and consistency challenges. Instead, check access at the parent container level and filter entities in your application. For detailed guidance on this pattern, including interceptor examples for nested entities, see [High-Cardinality Entities](/fga/high-cardinality-entities). --- ## Migration steps 1. **Define resource types** in the WorkOS Dashboard matching your OpenFGA types 2. **Define permissions** for each type (e.g., `view`, `edit`, `manage`) 3. **Create roles** that bundle permissions, including child-type permissions for inheritance 4. **Register resources** via API when entities are created in your app 5. **Migrate tuples** to role assignments on specific resources 6. **Replace OpenFGA checks** with WorkOS FGA `check` API calls ### API migration **OpenFGA Check:** ```javascript const { allowed } = await fga.check({ user: 'user:alice', relation: 'viewer', object: 'project:budget', }); ``` **WorkOS FGA Check:** ```javascript const { authorized } = await workos.authorization.check({ organizationMembershipId: 'om_01HXYZ', // available in a session token or via the API permissionSlug: 'project:view', resourceTypeSlug: 'project', resourceExternalId: 'budget', }); ``` --- ## Example migration ### OpenFGA schema ```text type user type organization relations define admin: [user] define member: [user] or admin type workspace relations define parent_org: [organization] define viewer: [user] or member from parent_org define editor: [user] or viewer define admin: [user] or admin from parent_org type project relations define parent_workspace: [workspace] define viewer: [user] or viewer from parent_workspace define editor: [user] or editor from parent_workspace ``` ### WorkOS FGA equivalent **Resource type hierarchy:** ```text organization (built-in) └── workspace └── project ``` **Roles for `workspace`:** | Role | Permissions | | ------ | ------------------------------------------------------------------ | | viewer | `workspace:view`, `project:view` | | editor | `workspace:view`, `workspace:edit`, `project:view`, `project:edit` | | admin | All workspace and project permissions | **Roles for `project`:** | Role | Permissions | | ------ | ------------------------------ | | viewer | `project:view` | | editor | `project:view`, `project:edit` | Organization members get `workspace:viewer` through an organization-scoped role. Workspace editors automatically get `project:edit` on all child projects through inheritance. --- ## Next steps - [Resource Types](/fga/resource-types) — Design your hierarchy - [Roles and Permissions](/fga/roles-and-permissions) — Configure inheritance patterns - [AuthKit Integration](/fga/authkit-integration) — Embed permissions in access tokens - [IdP Role Assignment](/fga/idp-role-assignment) — Map IdP groups to roles - [Assignments](/fga/assignments) — Migrate your tuples to role assignments - [Access Checks](/fga/access-checks) — Replace OpenFGA check calls ### IdP Role Assignment Map identity provider groups to organization-scoped roles while preserving resource-scoped access. ## Introduction IdP role assignment lets you map identity provider groups to organization-scoped roles. When an IT contact adds someone to the "Engineering" group in Okta or Azure AD, they automatically get the corresponding role in your application. Today, IdP role assignment supports organization-scoped roles only. Resource-scoped roles are managed through the API. A user can have both—their assigned organization-scoped role from the IdP, plus granular resource roles assigned by your application. > Support for mapping IdP groups to resource-scoped roles is coming soon. --- ## How it works **Organization layer (IdP-managed)** – Users get baseline access based on IdP groups. Everyone in "Engineering" might get `org-member`. **Resource layer (API-managed)** – Users get specific access to workspaces and projects via API assignments. When IdP groups change, only organization-scoped roles update. Resource-scoped assignments stay intact. ```text Alice's roles: ├─ org-member (from IdP group: "Engineering") ├─ workspace-admin on Workspace: Platform (API assignment) └─ project-editor on Project: API Backend (API assignment) ``` --- ## Setting up IdP role assignment Role mappings are configured in the [WorkOS Dashboard](https://dashboard.workos.com/) or through the Admin Portal. ![Role assignment in Admin Portal dialog](https://images.workoscdn.com/images/fe19e3ac-6370-404e-9590-cdb06b3de127.png?auto=format&fit=clip&q=50) For setup instructions, see [Directory Sync role assignment](/directory-sync/identity-provider-role-assignment) for real-time updates via SCIM, or [SSO role assignment](/sso/identity-provider-role-assignment) for authentication-time assignment. --- ## Directory Sync vs. SSO **Directory Sync (recommended)** – Role changes happen in real-time via SCIM. Access can be revoked immediately when someone leaves a group. **SSO only** – Role assignments are evaluated at authentication time. Changes take effect on the next sign-in. --- ## Combining with FGA Use IdP groups for baseline organization access, and API assignments for elevated resource access: ```text From IdP: └─ org-member (baseline access to view workspaces and projects) From API: ├─ workspace-admin on Workspace: Platform (team leads) └─ project-viewer on Project: Client Portal (contractors) ``` ### High-Cardinality Entities Learn when to use FGA for authorization and when to handle access control in your application. ## Overview We recommend using FGA for lower-cardinality resources and handling high-cardinality entities in your application. This guide explains why and shows you how. --- ## Why FGA works well for lower-cardinality resources Lower-cardinality resources like workspaces, projects, and environments are natural boundaries for role assignments: - **Users need explicit roles** — You assign someone as a project editor or workspace admin - **Sharing matters** — You grant external collaborators access to specific resources - **Permissions vary by resource** — Different teams have different access to different projects - **Long-lived and stable** — These resources are created infrequently and change slowly, so keeping them in FGA is straightforward High-cardinality entities like rows, artifacts, and messages rarely need this. You don't typically assign someone as a "row editor" or "message viewer" — they inherit access from the container they're in. Defining roles and permissions for millions of individual messages would be operationally complex without adding value. --- ## Why keep high-cardinality entities out of FGA Some authorization systems encourage storing entities such as individual files, messages, and rows as relationships in FGA. After working with many customers on authorization design, we've found this creates more problems than it solves. High-cardinality entities are created frequently, change often, and exist in volumes that make keeping two systems in sync impractical. Your database is already the source of truth for these entities, and access is almost always inherited from a parent container rather than granted individually. --- ## What to sync vs. keep local **Sync to FGA (lower cardinality):** - Organizations, workspaces, projects - Environments, pipelines, apps - Repositories, dashboards, teams **Keep in your application (high cardinality):** - Individual files, messages, comments - Row-level data within tables - Logs, events, audit records - Anything with millions of instances per organization --- ## The pattern: nearest FGA-managed parent To check access to high-cardinality entities, your application should traverse up to the nearest FGA-managed parent before making the authorization check: ```typescript async function canUserAccessFile( organizationMembershipId: string, fileId: string, ): Promise { // 1. Look up the file to find its parent project const file = await db.files.findUnique({ where: { id: fileId } }); if (!file) return false; // 2. Check access at the project level (FGA-managed) const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:view', resourceTypeSlug: 'project', resourceExternalId: file.projectId, }); return authorized; } ``` --- ## Nested folder example For deeply nested structures, walk up the hierarchy to find the FGA-managed parent: ```typescript async function canUserAccessFolder( organizationMembershipId: string, folderId: string, ): Promise { const MAX_DEPTH = 25; const visited = new Set(); let currentFolderId = folderId; // Walk up the folder hierarchy while (visited.size < MAX_DEPTH) { if (visited.has(currentFolderId)) { // Cycle detected return false; } visited.add(currentFolderId); const folder = await db.folders.findUnique({ where: { id: currentFolderId }, }); if (!folder) return false; // Found the FGA-managed parent if (folder.projectId) { const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'project:view', resourceTypeSlug: 'project', resourceExternalId: folder.projectId, }); return authorized; } // Continue up the hierarchy if (!folder.parentFolderId) return false; currentFolderId = folder.parentFolderId; } // Exceeded max depth return false; } ``` --- ## Fast path with JWT claims For organization-level permissions, you can skip the FGA API call entirely by checking JWT claims: ```typescript async function canUserAccessFile( session: Session, fileId: string, ): Promise { // Fast path: check org-level permission from JWT if (session.permissions?.includes('project:view')) { return true; } // Slow path: check resource-level permission via FGA const file = await db.files.findUnique({ where: { id: fileId } }); if (!file) return false; const { authorized } = await workos.authorization.check({ organizationMembershipId: session.organizationMembershipId, permissionSlug: 'project:view', resourceTypeSlug: 'project', resourceExternalId: file.projectId, }); return authorized; } ``` --- ## Benefits of this approach - **No sync overhead** — High-cardinality entities stay in your database, not FGA - **Single source of truth** — Your database owns the entity data - **Fast path available** — JWT claims can skip API calls for org-level permissions - **Flexible traversal** — Your app controls how entities map to FGA resources --- ## Next steps - [Resources](/fga/resources) — Register and manage FGA resources - [Access Checks](/fga/access-checks) — Perform authorization checks - [AuthKit Integration](/fga/authkit-integration) — Embed permissions in access tokens ### AuthKit Integration Use FGA with AuthKit for role-aware sessions and seamless authorization. ## Introduction FGA integrates with [AuthKit](/authkit) to provide two layers of authorization. Organization-scoped roles and permissions are embedded directly in the session token for instant checks. Resource-scoped permissions are checked through the [Authorization API](/fga/access-checks). --- ## What's in the session token When a user authenticates, their session token includes organization-scoped role information: ```json { sub: "user_01HXYZ..." org_id: "org_01HXYZ..." role: "org_member" permissions: ["org:view", "workspace:view", "project:view"] } ``` Your application can check these permissions directly from the token without making API calls. ### Why only organization-scoped roles? Resource-scoped roles are intentionally excluded from the JWT: - **Token size** – Users might have roles on hundreds of resources, bloating the JWT beyond practical limits - **Freshness** – Resource assignments change frequently; stale tokens would cause mismatches - **Performance** – Larger tokens mean slower requests and verification For resource-level permissions, use the [Authorization API](/fga/access-checks)—it's fast and always current. --- ## FGA and organization memberships FGA role assignments are scoped to organization memberships, not users directly. When you assign a role on a resource, the subject is the organization membership ID (`om_...`), which represents a user's relationship to a specific organization. This means FGA access checks require the organization membership ID rather than the user ID. You can include this ID in your JWT using [JWT Templates](/authkit/jwt-templates): ```json { "organization_membership_id": "{{ organization_membership.id }}" } ``` This produces a token with the membership ID alongside the default claims: ```json { "sub": "user_01HXYZ...", "org_id": "org_01HXYZ...", "role": "org_member", "permissions": ["org:view", "workspace:view"], ... "organization_membership_id": "om_01HXYZ..." } ``` Your application can then extract the membership ID from the JWT and pass it to FGA access checks without needing an additional API call. --- ## Two layers of authorization **Organization layer (JWT)** – Check the token directly for org-wide features like navigation and settings. Instant, no API call needed. **Resource layer (API)** – Call the Authorization API for specific resource access. Checks the full permission hierarchy including inheritance. ```text Can this user edit this project? 1. Quick check: Does the JWT include project:edit for all projects? → If yes, authorized (no API call) 2. Otherwise: Call the API for this specific project → Checks direct assignments and inheritance ``` --- ## Groups and group role assignments [Groups](/authkit/groups) let you assign resource-scoped roles to a set of users at once. Instead of creating individual role assignments for each organization membership on a resource, assign the role to a group and let WorkOS propagate it to all members. ### Assigning a resource-scoped role to a group ```bash curl https://api.workos.com/authorization/groups/group_01HXYZ/role_assignments \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "role_slug": "workspace-admin", "resource_type_slug": "workspace", "resource_external_id": "ws-engineering" }' ``` Every member of the group gains the `workspace-admin` role on the Engineering workspace. Permissions propagate through the resource hierarchy just like direct assignments, so members also get inherited access to child resources (projects, apps, etc.). ### How it integrates with access checks Resource-scoped roles from group role assignments are checked through the [Authorization API](/fga/access-checks) the same way as direct assignments. The access check evaluates all role sources for the organization membership, including group-sourced roles: ```text Alice's effective roles: ├─ org-member (direct assignment) ├─ workspace-admin on Workspace: Engineering (from "Engineering" group) └─ project-viewer on Project: Sensitive (direct assignment) ``` A single `check` call returns the combined result across all sources. Your application does not need to distinguish between direct and group-sourced roles. ### Dynamic membership and assignments Roles update when group membership or group role assignments change: - **Add member** — the member gains all resource-scoped roles from the group's assignments - **Remove member** — the member loses resource-scoped roles that came from that group - **Add group role assignment** — all current members of the group gain the role on the specified resource - **Remove group role assignment** — all members lose the role that came from that assignment This makes groups ideal for managing team-level access. When an engineer joins the platform team, adding them to the "Platform" group grants access to all the team's workspaces and projects without individual assignments. ### Example: team-based resource access Consider a project management application where you want all engineers to have the `editor` role on a shared workspace: 1. [Create a group](/reference/groups/create) named "Engineering" in the organization 2. [Add members](/reference/groups/add-member) to the group for each engineer's organization membership 3. [Assign the role](/reference/groups/role-assignment/create) `editor` on the workspace resource to the group ```bash # 1. Create the group curl https://api.workos.com/organizations/org_01HXYZ/groups \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{"name": "Engineering"}' # 2. Add a member curl https://api.workos.com/organizations/org_01HXYZ/groups/group_01HXYZ/organization-memberships \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{"organization_membership_id": "om_01HXYZ"}' # 3. Assign the role to the group curl https://api.workos.com/authorization/groups/group_01HXYZ/role_assignments \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "role_slug": "editor", "resource_type_slug": "workspace", "resource_external_id": "ws-engineering" }' ``` Every member of the "Engineering" group now has the `editor` role on the Engineering workspace. When a new engineer joins, adding them to the group grants the role automatically. For full details, see [Group role assignments](/authkit/group-role-assignments). --- ## When roles change **API checks** reflect changes immediately. **JWT permissions** require a session refresh since the token was issued at sign-in. Resource roles aren't in the JWT, so API checks always return current data. ### Role Assignments Grant users access to specific resources through role assignments. ## Introduction Assignments are where authorization becomes concrete. An assignment connects a user (through their organization membership) to a role on a specific resource. This determines what actions the user can take on that resource and, through inheritance, its children. --- ## Creating assignments Assign a role to a user on a resource: ```bash curl https://api.workos.com/authorization/organization_memberships/om_01HXYZ/role_assignments \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "role_slug": "workspace-admin", "resource_id": "authz_resource_01HXYZ" }' ``` The assignment takes effect immediately—the next access check will include it. ## How assignments work When you assign a role to a user on a resource: 1. The user gains all permissions included in that role on that resource 2. If the role includes child-type permissions, those propagate down to child resources 3. The assignment takes effect immediately For example, a `workspace-admin` role might include `workspace:edit`, `proj:read`, `proj:edit`, `app:read`, and `app:edit`. If you assign Alice this role on Workspace: Engineering, she can edit the workspace, view and edit all projects within it, and read and edit all apps in those projects. One assignment, broad access. --- ## Direct vs. inherited access Users can gain access through two paths: direct assignment on a resource, or inheritance from a parent. **Direct assignment** means the role is assigned specifically on that resource. Alice has `project-editor` on Project: API Backend—she can edit that project because you explicitly granted it. **Inherited access** comes from a role on a parent resource that includes child-type permissions. Alice has `workspace-admin` on Workspace: Engineering, which includes `project:edit`. That means she can edit Project: API Backend (which is in the Engineering workspace) even without a direct assignment on the project. When deciding where to assign roles, consider the scope of access needed. If someone needs access to everything in a workspace, assign a workspace role. If they need access to just one project, assign a project role directly. Both approaches are valid—the right choice depends on what access you're trying to grant. --- ## Multiple roles Users can always have multiple resource-scoped roles — there's no setting to control this. A user can be a `workspace-admin` on one workspace and a `project-viewer` on a project in a different workspace simultaneously. For organization-scoped roles, multiple roles must be [explicitly enabled](/authkit/roles-and-permissions/multiple-roles). When enabled, the permissions from all organization-scoped roles combine additively. A user might have `project-editor` and `project-reviewer` on the same project, giving them permissions from both roles. Or they might have `workspace-admin` on one workspace and `project-viewer` on a project in a different workspace—each assignment grants access to its respective resource tree. ```text Alice's assignments: ├─ org-member on Organization: Acme ├─ workspace-admin on Workspace: Engineering └─ project-viewer on Project: Sensitive (in different workspace) ``` In this example, Alice has baseline org access, full control of the Engineering workspace and everything in it, plus read-only access to a sensitive project in another part of the organization. --- ## Managing assignments List assignments for a user: ```bash curl "https://api.workos.com/authorization/organization_memberships/om_01HXYZ/role_assignments" \ -H "Authorization: Bearer sk_example_123456789" ``` Remove an assignment: ```bash curl https://api.workos.com/authorization/organization_memberships/om_01HXYZ/role_assignments/role_assignment_01HXYZ \ -X DELETE \ -H "Authorization: Bearer sk_example_123456789" ``` Access is revoked immediately. Removing an assignment also removes any permissions that were inherited by child resources through that assignment. However, any direct assignments on child resources remain intact. You can view assignments in the [WorkOS Dashboard](https://dashboard.workos.com/). Navigate to an organization membership to see all role assignments for that user. ![FGA assignments](https://images.workoscdn.com/images/c9a27787-a97c-4e8b-ac86-05cba25374ae.png?auto=format&fit=clip&q=50) --- ## Cascading events Several operations affect assignments automatically: **When a resource is deleted**, all role assignments on that resource and its children are removed. Users lose access without any manual cleanup. **When an organization membership is removed**, all of that user's role assignments within the organization are removed. They can no longer access any resources in that organization. **When a role's permissions change**, everyone with that role immediately sees the updated permissions. You don't need to re-assign roles—existing assignments use the new permission set. --- ## Combining with IdP role assignment For enterprise customers using identity providers, you can use [IdP role assignment](/fga/idp-role-assignment) for organization-scoped roles while managing resource-scoped roles through the API. ```text From IdP: └─ org-member (baseline organization access) From API: ├─ workspace-admin on Workspace: Engineering └─ project-editor on Project: Mobile ``` This gives IT contacts control over who belongs to the organization and what baseline access they get, while your application manages the specifics of who can do what on which resources. ### Access Checks Ask whether a user can perform an action on a resource. ## Overview Access checks answer: "Can this user do this action on this resource?" FGA looks at all the ways the user might have access—a role assigned directly on the resource, a role on a parent resource that grants inherited permissions, or an organization-scoped role. If any grant the permission, the user is authorized. --- ## A quick example Alice wants to deploy an app. Here's her access: ```text Org: Acme (Alice: org-member) └─ Workspace: Engineering (Alice: workspace_admin) └─ Project: Web └─ App: Frontend ``` **Can Alice deploy App: Frontend?** Yes—her `workspace-admin` role includes `app:deploy`, which flows down to all apps in that workspace. --- ## Checking permissions **JWT (fast)** – For org-wide permissions, check the token directly. No API call needed. Good for navigation and feature flags. **API (precise)** – For resource-specific permissions, call the authorization API: ```bash curl https://api.workos.com/authorization/organization_memberships/om_01HXYZ/check \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "permission_slug": "project:edit", "resource_id": "authz_resource_01HXYZ" }' ``` Response: ```json { "authorized": true } ``` For best performance, check the JWT first for org-wide permissions, then fall back to the API for resource-specific checks. --- ## Integrating access checks in your application Here's how you might protect an API endpoint that updates a project. Before performing the operation, check whether the user has the `proj:edit` permission on the specific project they're trying to modify: ```javascript import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); app.patch('/projects/:projectId', async (req, res) => { const { organizationMembershipId } = req.user; const { projectId } = req.params; // Check if the user can edit this project const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'proj:edit', resourceExternalId: projectId, resourceTypeSlug: 'project', }); if (!authorized) { return res.status(403).json({ error: 'Forbidden' }); } // User is authorized — proceed with the update const project = await updateProject(projectId, req.body); return res.json(project); }); ``` The `check()` method evaluates all possible sources of access — direct assignments on the project, inherited permissions from a parent workspace, and organization-scoped roles. You don't need to check each level yourself. --- ## Choosing an access check endpoint FGA exposes four endpoints for answering authorization questions. Pick the one that matches the shape of the question. | Endpoint | Use when | | ---------------------------- | ------------------------------------------------------------------------------------------------------- | | `check` | A single permission on a single resource. Best for action handlers and route gates. | | `listEffectivePermissions` | Many permissions on a single resource. Best for detail pages that render multiple permission-gated components. | | `listResourcesForMembership` | A single permission across many resources. Best for list views, navigation, and pickers. | | `listMembershipsForResource` | All users who have a permission on a single resource. Best for share dialogs and member lists. | Use `check` for a single permission gate. As soon as a detail page needs more than two or three permissions, prefer `listEffectivePermissions`—it returns the full permission set in one call instead of fanning out to multiple `check` requests. When the question is "which resources can this user access," use `listResourcesForMembership` rather than calling `check` once per candidate resource. --- ## Common use cases **Protecting actions** – Before a user performs an action, check if they're allowed. Return 403 if not. **Showing or hiding UI** – Check permissions before rendering to show edit buttons, delete options, or admin settings only to authorized users. **Filtering lists** – Only show resources the user can access in navigation and search results. --- ## Performance - **Sub-50ms** response times (p95) - **Strong consistency**—role changes take effect immediately - **High availability** for production workloads ## Feature Flags {#feature-flags} ### Feature Flags Manage rollout of new features for specific users and organizations with Feature Flags. ## Overview Feature flags are a tool that allows teams to control the rollout of features in real time. They enable businesses to separate feature delivery from code deployment, creating a more agile and risk-managed approach to launching and managing product experiences. WorkOS Feature Flags provides a developer-friendly solution that integrates seamlessly with your existing authentication flow. Create and manage flags through the dashboard then access them through a user's access token. Feature flags can target organizations or individual users. This approach lets you safely roll out new functionality, enable beta programs for select customers, and manage premium feature access without deploying code changes. ## Use cases - **Targeted rollouts:** Enable features for specific organizations before a general release - **Beta programs:** Allow early access to new features for select customers - **Premium features:** Restrict advanced functionality to organizations on higher-tier plans ## Before getting started To get the most out of these guides, you'll need: - A [WorkOS account](https://dashboard.workos.com/) - An existing organization in your WorkOS Dashboard ![WorkOS Dashboard UI showing organization creation](https://images.workoscdn.com/images/1c69fd98-01be-491d-9255-58363bc6a983.png?auto=format&fit=clip&q=50) ## API object definitions [Organization](/reference/organization) : Describes an organization whose users sign in with a SSO Connection, or whose users are synced with a Directory Sync Connection. [User](/reference/authkit/user) : Describes a user who can be targeted with feature flags. ## (1) Create a feature flag from the WorkOS dashboard - Sign in to your [WorkOS dashboard](https://dashboard.workos.com/) account and navigate to the Feature Flags page. - Click the `Create feature flag` button and enter a name, slug, and description. ![A screenshot showing the WorkOS dashboard feature flags page.](https://images.workoscdn.com/images/9be5d8f6-8956-47fc-aca6-66478bb37881.png?auto=format&fit=clip&q=80) Feature flags are created across all environments, allowing you to test your feature flag in a sandbox environment before enabling it in production. --- ## (2) Set the users and organizations that should have access To edit which set of users and organizations should have the feature flag enabled, click `Edit` on the rule for the environment you want to edit. Next, select your desired rule setting between `None`, `Some`, and `All`. Selecting `Some` will allow you select specific users and organizations. To edit a feature flag's rules in other environments, click the `Edit in X` button which will update your active dashboard environment to the selected environment, allowing you to update rules in the chosen environment. ![A screenshot showing the configuration of a feature flag organization rule.](https://images.workoscdn.com/images/bf958da9-1288-464c-b087-b54f60f03171.png?auto=format&fit=clip&q=80) ![A screenshot showing the configuration of a feature flag user rule.](https://images.workoscdn.com/images/32f8b6da-d357-4ac7-b9b3-96c9cf3ef60f.png?auto=format&fit=clip&q=80) --- ## (3) Enable the feature flag Once you're ready to enable the feature for the configured set of organizations and users, toggle the flag on to start including it in a user's access token when they authenticate for a configured organization or when the user is individually targeted. ![A screenshot showing the enabling of a feature flag.](https://images.workoscdn.com/images/f526ab53-0ec5-4261-abe5-24f05e92cdd8.png?auto=format&fit=clip&q=80) --- ## (4) Use the feature flags in your application The access token includes the `feature_flags` claim, containing the user's entitlements. You can use this information to gate access to features in your application. Feature flags will show up in the access token the next time the user logs in or the session is refreshed. You can manually [refresh the session](/reference/authkit/authentication/refresh-token) after granting the organization access in the dashboard. ### Slack Notifications Get notifications about feature flag changes in your Slack workspace. ## Introduction Feature flags give teams precise control over feature releases. The WorkOS app for Slack sends real-time notifications throughout your feature flags' lifecycle, from creation and enabling to deletion. This keeps all stakeholders informed about critical changes, such as when a feature flag is enabled for specific customers or organizations. --- ## Configure your Slack connection To set up Slack notifications, navigate to [_Feature Flags_](https://dashboard.workos.com/environment/flags) and click _Enable Slack notifications_. ![A screenshot showing the WorkOS Dashboard Feature Flags page](https://images.workoscdn.com/images/840a7450-12bf-4d8d-ba12-b30da70912d7.png?auto=format&fit=clip&q=50) Next, click _Connect to Slack_ to go to the Slack Installation page. ![A screenshot showing the WorkOS Dashboard Slack notifications dialog when no connection exists](https://images.workoscdn.com/images/7b873377-4847-43ae-a7ba-bf50b25d9f5e.png?auto=format&fit=clip&q=50) Finally, select the channel that you'd like to get your notifications in. By default, notifications are sent for all production environments in your WorkOS account. ![A screenshot showing the Slack installation page](https://images.workoscdn.com/images/83ed7c7f-1e27-4b52-b20e-6439cec854a9.png?auto=format&fit=clip&q=50) --- ## Slack notifications Once your Slack notifications are enabled, you'll start to receive messages in the configured channel for all feature flag events. ### Flag lifecycle events - A flag is created - A flag's details are updated (name, description, tags) - A flag is deleted ![Sample message of a flag created event](https://images.workoscdn.com/images/1bc973f6-f879-4c71-8f0a-fd3eece4f252.png?auto=format&fit=clip&q=50) ### Rule updates and targeting changes - A flag is enabled or disabled - Targeting is changed between All, Some, or None - Specific users or organizations are added or removed ![Sample message of a flag enabled for some event](https://images.workoscdn.com/images/9613033e-f313-449d-bbd3-9bcff85af2c2.png?auto=format&fit=clip&q=50) --- ## Disconnect an existing connection To disable notifications or to change your configured Slack channel, you must disconnect the existing connection. To start, navigate to [_Feature Flags_](https://dashboard.workos.com/environment/flags) and click _Connected to Slack_. ![A screenshot showing the WorkOS Dashboard Slack notifications dialog for an existing connection](https://images.workoscdn.com/images/1c2e2fad-af7a-48a4-8b93-75b93653ed2b.png?auto=format&fit=clip&q=50) Next, click _Disconnect_ and confirm to disable Slack notifications to the listed channel. ### SDK Integration Evaluate feature flags in your server-side Node.js application using the WorkOS runtime client. ## Choose your integration approach There are two ways to use feature flags in your application: ### (A) Using the `feature_flags` access token claim Use the [quick start guide](/feature-flags) when you want to gate authenticated application behavior based on the user's session. This is a good fit when feature flag updates can take effect the next time the user's session is refreshed. If you're using [`@workos-inc/authkit-nextjs`](/sdks/authkit-nextjs), you can read the claim from the current session with `withAuth()`. This is convenient for small flag sets, but the claim is stored in the access token. If your application has many feature flags, removing the `feature_flags` claim and using the runtime client can help keep AuthKit session cookies smaller. ### (B) Using the Node runtime client Use the runtime client when you need server-side evaluation that stays in sync independently of user authentication, such as in backend services, jobs, webhooks, or other long-lived server processes. This is also the recommended approach for applications with many feature flags because it avoids storing every active flag in the user's access token and session cookie. ## Overview The WorkOS Node SDK includes a runtime client for evaluating feature flags in server-side applications. The client maintains internal flag state, allowing it to serve feature flags without remote requests. Flag configurations stay in sync with the dashboard automatically. Before the first successful sync, evaluations use bootstrap data if provided. Otherwise, they fall back to the flag's `default_value`, or `false` for unknown flags. Create a single, shared runtime client instance when your application starts. Do not create a new client per request — the client handles synchronization and evaluation for the lifetime of the process. --- ## (1) Install the SDK Install the WorkOS Node SDK using your preferred package manager. ```bash npm install @workos-inc/node ``` --- ## (2) Set secrets To make calls to WorkOS, provide your API key. Store it as a managed secret, such as `WORKOS_API_KEY`, and pass it to the SDK through your application's environment. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' ``` > This runtime client is for trusted server-side environments only. Never expose your WorkOS API key in client-side code. --- ## (3) Basic setup Initialize the WorkOS client, create a runtime client, and evaluate flags once the client is ready. ```js import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); const client = workos.featureFlags.createRuntimeClient(); try { await client.waitUntilReady({ timeoutMs: 5000 }); const isEnabled = client.isEnabled('advanced-analytics', { organizationId: 'org_01EHQMYV6MBK39QC5PZXHY59C3', }); console.log('Feature enabled:', isEnabled); } catch (error) { console.error('Runtime client failed to initialize:', error); } ``` The `isEnabled` method returns `true` or `false` based on the flag's configuration and any targeting rules that match the provided context. If you're using `@workos-inc/authkit-nextjs`, use `getFeatureFlagsRuntimeClient()` instead of creating the runtime client directly. The helper returns one shared runtime client for the server process, so repeated calls across routes or server components do not create extra polling clients. ```tsx import { getFeatureFlagsRuntimeClient, withAuth, } from '@workos-inc/authkit-nextjs'; const featureFlags = getFeatureFlagsRuntimeClient(); export default async function DashboardPage() { const { user, organizationId } = await withAuth({ ensureSignedIn: true }); try { await featureFlags.waitUntilReady({ timeoutMs: 5000 }); } catch (error) { console.error('Feature flags client failed to initialize:', error); } const isEnabled = featureFlags.isEnabled('advanced-analytics', { userId: user.id, organizationId, }); return isEnabled ? : ; } ``` You can also listen for the `ready` event instead of using `waitUntilReady()`: --- ## (4) Context-based evaluation Pass an `organizationId`, `userId`, or both to evaluate flags against the targeting rules configured in the dashboard. If no context is provided, `isEnabled` returns the flag's `default_value`. If the flag does not exist, it returns `false` — you can override this by passing a third argument as the default return value. When both `userId` and `organizationId` are provided, user targeting takes precedence over organization targeting. --- ## (5) Graceful shutdown Call `close()` to stop background synchronization and clean up resources when your server shuts down. --- ## Event handling The runtime client emits events to signal state changes during its lifecycle. | Event | Description | | -------- | ------------------------------------------------------------------------------------------------------ | | `ready` | Fires once when flag data is first available, either from bootstrap or the first successful sync. | | `change` | Fires when a flag's configuration changes after initialization. Receives `{ key, previous, current }`. | | `error` | Fires when a sync request fails. The client retries automatically with exponential backoff. | | `failed` | Fires on 401 Unauthorized. The client stops syncing automatically. | --- ## Common issues - If all flags return their default values, the client may not be ready yet, the flag key may be incorrect, or no targeting rules may match the evaluation context. - If the client emits `failed`, your API key is invalid or unauthorized and synchronization stops until the client is recreated with valid credentials. - If the client emits `error`, a sync request failed temporarily. The client continues retrying automatically in the background. - If dashboard changes do not appear immediately, remember that the runtime client refreshes on the configured polling interval. --- ## Bootstrap configuration Pre-populate the client with flag data so evaluations are available immediately, before the first sync completes. Bootstrap data is replaced with live data after the first successful sync. --- ## Configuration options Pass options to `createRuntimeClient()` to customize client behavior. | Option | Type | Default | Description | | ------------------- | ------------------------------- | ----------- | -------------------------------------------------------------------- | | `pollingIntervalMs` | `number` | `30000` | How often to sync flag changes, in milliseconds. Minimum `5000` | | `requestTimeoutMs` | `number` | `10000` | Timeout for each sync request, in milliseconds | | `bootstrapFlags` | `Record` | `undefined` | Pre-populated flag data for instant evaluation before the first sync | | `logger` | `RuntimeClientLogger` | `undefined` | Custom logger with `debug`, `info`, `warn`, and `error` methods | --- ## TypeScript types If you're using TypeScript, the `@workos-inc/node` package includes built-in type definitions. To learn more about the specific configuration options and types available for the runtime client, read the [`@workos-inc/node` package docs](https://www.npmjs.com/package/@workos-inc/node). Key exports include `RuntimeClientOptions`, `EvaluationContext`, `FeatureFlagsRuntimeClient`, and `RuntimeClientStats`. ## Events {#events} ### Events Respond to activity that occurs within WorkOS and third-party providers. Events represent activity that has occurred within WorkOS or within third-party identity and directory providers. Your app can [sync the data](/events/data-syncing) via either the events API or webhooks. #### Event object All event objects share a similar structure. | Attribute | Description | | ------------ | -------------------------------------------------------------------------- | | `event` | A string that distinguishes the event type. | | `id` | Unique identifier for the event. | | `data` | Event payload. Payloads match the corresponding [API objects](/reference). | | `created_at` | Timestamp of when the event occurred. | | `context` | An optional object of extra information relevant to the event. | ## Agent registration events Events emitted during the agent registration lifecycle, including creation, claim attempts, claim completion, credential issuance, and organization switching. ## API key events Events emitted when [API keys](/authkit/api-keys) are created, updated, or revoked. ## Authentication events Each step in the [authentication](/reference/authkit/authentication) flow emits an authentication event. Authentication success events are emitted even when additional steps, such as MFA, are required to complete the process. ## Connection events Events emitted when Single Sign-On connections are activated, deactivated, or deleted. Also emitted when a SAML certificate is renewed for the connection. ## Directory Sync events Events emitted when directory-related resources are changed. To learn what exactly each of these events represents, see the [in-depth Directory Sync events guide](/directory-sync/understanding-events). ## Email verification events Events emitted when a user is required to verify their email. ## Feature flag events Events emitted when WorkOS feature flags are created, updated, deleted, or their rules are updated. ## Group events Events emitted when [groups](/authkit/groups) are created, updated, deleted, or their members change. ## Invitation events Events emitted when an [AuthKit user](/reference/authkit/user) is invited to join an organization. ## Magic Auth events Events emitted when a user requests a Magic Auth code. ## Organization events Events emitted when WorkOS organizations are created, updated, or deleted. ## Organization domain events Events emitted when organization domains are created, updated, deleted, or their verification status changes. ## Organization membership events Events emitted when an [AuthKit user](/reference/authkit/user) joins or leaves an organization. ## Custom role events Events emitted when [custom roles](/reference/roles/custom-role) are created, updated, or deleted. ## Password reset events Events emitted when a user requests to reset their password. ## Permission events Events emitted when [permissions](/reference/roles/permission) are created, updated, or deleted. ## Pipes events Events emitted when a [Pipes](/pipes) connected account is connected, disconnected, or requires reauthorization. ## Role events Events emitted when [environment roles](/reference/roles/role) are created, updated, or deleted. ## Session events Events emitted when AuthKit sessions are created. ## User events Events emitted when [AuthKit users](/reference/authkit/user) are created, updated, or deleted. ## Vault events Events emitted when [Vault](/vault) data, keys, or metadata are accessed or modified. ### Stream events to Datadog Stream and analyze WorkOS activity in Datadog. ![WorkOS Datadog dashboard showing various metrics and graphs describing authentication events and user activity](https://images.workoscdn.com/images/9ec8c9ce-e087-4967-8b66-9311aaf13902.png?auto=format&fit=clip&q=50) WorkOS supports real-time streaming of events to Datadog. By analyzing WorkOS activity directly in Datadog, you are able to: - View trends in user sign-ins, user growth, new SSO connections and more. - Debug customer issues related to sign-in, email verification, password resets and more. - Generate reports of user activity per customer organization. - Set alerts for unexpected activity, such as sudden spike in failed password attempts. See all of the WorkOS events that stream to Datadog in the [event types](/events) documentation. --- ## Introduction Setting up real-time streaming of WorkOS events to Datadog only takes a few minutes and can be done in three simple steps. --- ## (1) Create a Datadog API key First, create a new Datadog API key to give WorkOS permission to send event activity as logs to your Datadog account. While you can use an existing API key, WorkOS recommends creating a new key that will only be used for WorkOS event streaming. 1. Sign in to your [Datadog account](https://app.datadoghq.com/). 2. Navigate to the [Organization Settings → API Keys](https://app.datadoghq.com/organization-settings/api-keys) page. 3. Choose the **New Key** button 4. Enter a name for your new API key. 5. Choose the **Create Key** button. ![A screenshot showing how to create an API key in the Datadog dashboard.](https://images.workoscdn.com/images/d69f49e9-6e8b-444a-8736-0cc2db98cf72.png?auto=format&fit=clip&q=50) --- ## (2) Configure event streaming in WorkOS The next step is to configure event streaming in the [WorkOS Dashboard](https://dashboard.workos.com/) using the Datadog API key that was created in the previous step. 1. Sign in to the [WorkOS Dashboard](https://dashboard.workos.com/). 2. Navigate to the **Events** page. 3. Choose the **Stream to Datadog** button. ![A screenshot showing how setup streaming events to Datadog in the WorkOS Dashboard.](https://images.workoscdn.com/images/0259f8e3-6fb2-4b3a-819a-f98d128c1c79.png?auto=format&fit=clip&q=50) 4. Enter the Datadog API key. 5. Select your Datadog region. 6. Choose the **Save Log Stream Details** button. ![A screenshot showing how to enter a Datadog API key in WorkOS Dashboard.](https://images.workoscdn.com/images/e1d4d7bb-e076-492f-971f-e116ffe2de0e.png?auto=format&fit=clip&q=50) With event streaming configured, when new events occur, WorkOS will send the events to Datadog with the source `workos`. --- ## (3) Add the WorkOS Datadog dashboard The final step is to add the WorkOS Datadog dashboard to your Datadog account. 1. Sign in to your [Datadog account](https://app.datadoghq.com/). 2. Navigate to the [Dashboard List](https://app.datadoghq.com/dashboard/lists) page. 3. Choose the **+ New Dashboard** button. ![A screenshot showing how to create a new dashboard in Datadog.](https://images.workoscdn.com/images/feee6689-2477-4711-bf0e-10c917cc02f7.png?auto=format&fit=clip&q=50) 4. Enter a dashboard name. 5. Choose the **New Dashboard** button. 6. In the new dashboard, choose the **Configure** button. 7. Download the [WorkOS Datadog dashboard JSON file](/docs/assets/workos-datadog-dashboard.json) 8. Scroll down in the context menu and choose **Import dashboard JSON**. 9. Upload the WorkOS Datadog dashboard JSON file downloaded in the previous step. ![A screenshot showing how to import a JSON definition of a Dashboard into Datadog.](https://images.workoscdn.com/images/3dc7f949-67ff-470e-84f1-8a5a8880114d.png?auto=format&fit=clip&q=50) ### Data syncing Keep your app in sync with WorkOS. ## Introduction Syncing your app data with WorkOS is done using events. Events represent activity that has occurred within WorkOS or within third-party identity and directory providers that interact with WorkOS. When important activity occurs, we record an event. For example, a new SSO connection being activated is an event. A user being created, assigned membership to an organization, or successfully signing in are all events as well. Events are activity that your application might be interested in for the purposes of syncing data or extending your application's business logic. Your app can consume events from WorkOS via either the events API or webhooks. ```json language="json" title="A sample event" { "object": "event", "id": "event_07FKJ843CVE8F7BXQSPFH0M53V", "event": "dsync.user.updated", "data": { "id": "directory_user_01E1X1B89NH8Z3SDFJR4H7RGX7", "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", "idp_id": "8931", "first_name": "Lela", "last_name": "Block", "name": "Lela Block", "email": "lela.block@example.com", "state": "active", "created_at": "2021-06-25T19:07:33.155Z", "updated_at": "2021-06-25T19:07:33.155Z", "custom_attributes": { "department": "Engineering", "job_title": "Software Engineer" }, "role": { "slug": "member" } }, "created_at": "2023-04-28 20:05:31.093" } ``` --- ## Sync using the events API With the events API, your application retrieves events from WorkOS. The events API offers a more robust data synchronization solution compared to webhooks, ensuring seamless synchronization of your system state with WorkOS. To sync data using the events API, continue to the [events API guide](/events/data-syncing/events-api). --- ## Sync using webhooks With webhooks, WorkOS automatically notifies your app when an event occurs by invoking an endpoint hosted within your application. To sync data using webhooks, continue to the [webhooks guide](/events/data-syncing/webhooks). --- ## API vs. webhooks We recommend using the Events API instead of webhooks to keep your data in sync—especially for [user](/events/user) and [directory](/events/directory-sync) events. With the Events API, you control how often and how much data you ingest. Webhooks, on the other hand, require your endpoint to handle unpredictable spikes in event volume, which can make them harder to manage at scale. That said, webhooks may still be the better fit depending on your use case. Here's how the two compare: | Aspect | Events API | Webhooks | | -------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | Timing | Controlled by your app. Your server can process events at its own pace. | Real-time. Webhooks trigger as soon as an event occurs. | | Order | A consistent order is guaranteed. | No guarantee of order on receipt. Events contain timestamps to determine order. | | Reconciliation | Replayable. Can go back to a specific point in time and reprocess events. | Failed requests are retried with exponential back-off for up to 3 days. | | Security | Authentication, confidentiality, and integrity protection by default. | You must expose a public endpoint and validate webhook signatures. | ### Sync data with webhooks A step-by-step guide on how to start syncing data using webhooks. ## What you'll build In this guide, we will walk you through what you will need to set up webhooks: - Create your endpoint to receive webhook events - Register your endpoint with WorkOS - Process the events received from WorkOS - Test your endpoint --- ## (1) Set up your webhook endpoint Create a public endpoint that WorkOS can send events to. This endpoint should use HTTPS and should accept POST requests with the `workos-signature` header. > WorkOS sends the header as `WorkOS-Signature`, but many web servers normalize HTTP request headers to their lowercase variants. --- ## (2) Register your endpoint Set and save the webhook URL in the [WorkOS Dashboard](https://dashboard.workos.com/), so WorkOS knows where to deliver the events. Your webhook endpoints should only be configured to receive the ones required by your integration. Receiving all event types can put undue strain on your servers and is not recommended. ![WorkOS Dashboard Webhooks UI](https://images.workoscdn.com/images/a6bebfe6-d5db-475c-bf34-a5bdf35433e0.png?auto=format&fit=clip&q=90) --- ## (3) Process the events In order to avoid unnecessary retry requests hitting your webhook handler, we recommend using two concurrent processes for handling events: one for receiving the event, and the other for processing it. ### Respond with HTTP 200 OK On receiving an event, you should respond with an `HTTP 200 OK` to signal to WorkOS that the event was successfully delivered. Otherwise, WorkOS will consider the event delivery a failure and retry up to 6 times, with exponential backoff over 3 days. You do not need to signal to WorkOS whether or not the event was processed successfully. ### (A) Validate the requests using the SDK Before processing the request payload, verify the request was sent by WorkOS and not an unknown party. WorkOS includes a unique signature in each webhook request that it sends, allowing you to verify the authenticity of the request. In order to verify this signature, you must obtain the secret that is generated for you when you set up your webhook endpoint in the WorkOS dashboard. Ensure that this secret is stored securely on your webhook endpoint server as an environment variable. The SDKs provide a method to validate the timestamp and signature of a webhook. Examples using these methods are included below. The parameters are the payload (raw request body), the request header, and the webhook secret. There is an optional parameter, tolerance, that sets the time validation for the webhook in seconds. The SDK methods have default values for tolerance, usually 3–5 minutes. ### (B) Validate the requests manually If implementing webhook validation yourself, you'll need to use the following steps: First, extract the timestamp and signature from the header. There are two values to parse from the `WorkOS-Signature` header, delimited by a `,` character. | Key | Value | | ------------------ | ----------------------------------------------------------------------------------------------- | | `issued_timestamp` | The number of milliseconds since the epoch time at which the event was issued, prefixed by `t=` | | `signature_hash` | The HMAC SHA256 hashed signature for the request, prefixed by `v1=` | To avoid replay attacks, we suggest validating that the `issued_timestamp` does not differ too much from the current time. Next, 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. Finally, compare signatures to make sure the webhook request is valid. Once you've determined the event request is validly signed, it's safe to use the event payload in your application's business logic. ### Create an IP allowlist WorkOS sends webhooks from a fixed set of IP addresses. It's recommended to restrict access to your webhook endpoint to only these IP addresses: ```plain title="WorkOS IP addresses" 3.217.146.166 23.21.184.92 34.204.154.149 44.213.245.178 44.215.236.82 50.16.203.9 52.1.251.34 52.21.49.187 174.129.36.47 ``` --- ## (4) Test your endpoint From the dashboard, you can send test webhook events after configuring an endpoint. Go to the webhook endpoint detail page and click the **Send test event** button. The types of events that you have configured for your endpoint are available for you to send sample payloads. ![A screenshot showing how to send a test webhook in the WorkOS dashboard.](https://images.workoscdn.com/images/bda8fdc7-becb-494e-a9b6-f8295e5998a4.png?auto=format&fit=clip&q=90) If you would like to test against your local development environment, we recommend using a tool like [ngrok](https://ngrok.com) to create a secure tunnel to your local machine, and sending test webhooks to the public endpoint generated with ngrok. See our [blog post](https://workos.com/blog/test-workos-webhooks-locally-ngrok) to get more details on how you may want to test webhooks locally with ngrok. --- ## Best practices ### Respond to events immediately To avoid webhook requests potentially stressing your system, WorkOS strongly recommends that you respond to a webhook request with a 200 OK response as quickly as possible once received. If you process the event before responding, your system may not be able to handle a spike of requests. This may cause requests to timeout and result in missing important updates. A common pattern is to store the request payload on a message queue, respond with a 200 OK response, and use a background worker to process the messages in the queue. ### Recover from failed events If your endpoint fails to respond to a webhook request with a `2xx` response, WorkOS will automatically retry the event with exponential back-off for up to 3 days in production environments. If for some reason your endpoint is still unable to respond successfully to events during that period, the event will be considered failed, and we will no longer retry sending it. You can reconcile your data using our [Directory Sync endpoints](/reference/directory-sync) to update your data. > In staging environments, WorkOS only retries failed webhooks for several minutes before giving up. You can, however, manually retry webhooks using the WorkOS Dashboard for these environments. ### Handle out-of-sequence events WorkOS does not guarantee that events are delivered in the same sequence that they are generated. For example, when syncing a directory you may receive: - `dsync.group.created` - `dsync.user.created` - `dsync.group.user_added` Your endpoint should handle cases when these events are delivered out of order. Each event includes the full payload of the objects involved, so you can perform an upsert using the payload data. It is also possible that event data can be stale due to a retry of an older event being delivered after a newer event for the same object. Therefore, we recommend checking the timestamp of the incoming webhook data against the timestamp of the data in your system to ensure you do not overwrite your data with stale data. Each object in the payload includes a `created_at` field and an `updated_at` field. ### Ignore duplicate events It is possible to receive the same event more than once. WorkOS recommends that you handle webhook events using idempotent operations. One way of doing this is logging the ID of webhook events that you have processed and ignoring subsequent requests with the same ID. ### Obfuscate your endpoint URL A small security measure you can incorporate is to make your webhook endpoint difficult to guess. Including a token comprised of series of random numbers and letters to your endpoint URL can prevent malicious actors from easily guessing your endpoint. For example: `https://api.example.com/webhooks/n0dbga5x…` is much more difficult to guess than `https://api.example.com/webhooks` ### Sync data using the events API A step-by-step guide on how to start syncing data using the API. ## What you'll build In this guide, we will walk you through what you will need to integrate with the [events API](/reference/events): - Create a _cursor_ for use with the events API - Update your cursor - Choose a cursor if you lose yours - Handle event replay in your app ## Before getting started To get the most out of this guide, you'll need: - A [WorkOS account](https://dashboard.workos.com/) - An [SSO](/sso/1-add-sso-to-your-app) or [directory](/directory-sync/quick-start/1-create-a-new-directory-connection) connection configured in order to generate events --- ## (1) Integrate the events API SDK WorkOS offers native SDKs in several popular programming languages. Choose a language below to see instructions in your app's language. ### Set secrets To make calls to WorkOS, provide the API key and, in some cases, the client ID. Store these values as managed secrets, such as `WORKOS_API_KEY` and `WORKOS_CLIENT_ID`, and pass them to the SDKs either as environment variables or directly in your app's configuration based on your preferences. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' ``` > The code examples use your staging API keys when [signed in](https://dashboard.workos.com) --- ## (2) Start consuming events Your app can start consuming events once it integrates the WorkOS SDK. The first thing to do is to pick a starting place in the data set. ### Keep a cursor A _cursor_ is a bookmark to track your app's position in the events list. The very first call to the events API won't have a cursor. Subsequent requests to WorkOS should include the updated cursor using the `after` parameter. You will need to update and store your cursor after processing an event. ### Avoid overwriting newer data To avoid repeating an update, store the `updated_at` timestamp provided by WorkOS for each object. Extract this tag from the data object in the event. If the `updated_at` timestamp in the event is newer, update the local state with the latest event data. Otherwise, you can skip processing that event. --- ## (3) Select event types Determine the [event types](/events) you want to consume. Choose the relevant event types that align with your app's functionality and integration with WorkOS. Retrieve events from the API using cursor pagination. To fetch the next set of events, provide the ID of the latest processed event in the `after` parameter. --- ## (4) Handle event replay In some cases, it may be necessary to go back in time and "replay" the events. When designing your app logic to handle events replay it is important to design your event handling logic in a way that can safely accommodate it without undesired effects. To achieve this, focus on separating your app's data handlers from transactional business logic like sending emails, communicating to 3rd party APIs, etc. By implementing separate data handling, you can replay events without side effects. WorkOS recommends processing events synchronously, handling them in the order they occurred. > The events API returns events up to 90 days old. You can query for up to 30 days of events per request. ### If your app stops processing events When resuming event processing, you have two options to pick up where you left off: - **Using the latest known cursor:** Retrieve the most recent cursor that was successfully processed and use it as the starting point for event resumption. - **Using a timestamp:** Alternatively, you can make an API call with the `range_start` parameter and then use the cursor. Utilize the `updated_at` timestamp to prevent overwrites. --- ## Scaling recommendations ### Single consumer WorkOS recommends that your app starts with a single worker. Process events in a separate thread or process from your app's main execution thread. Deploying a single worker responsible for handling events simplifies and streamlines event consumption. This approach ensures serial event processing. After completing the processing of events on the current page, request the next page of events to maintain progress. ### Parallel processing For onboarding large organizations, divide events into independent queues for parallel processing when calling the events API from a single worker. Concurrently processing events from different organizations is safe, but for consistency and integrity, it is recommended to sequentially process events within a single organization. --- ## Migrating from webhooks You can migrate to the events API if you already use webhooks. To migrate, start querying the events API using the `range_start` parameter that corresponds to the time you'd want to start syncing from. The event IDs passed in webhook bodies are the same as those returned by the events API. ### Data reconciliation Keep your app in sync with WorkOS. ## Introduction While the events API makes it easier to keep your app in sync with WorkOS, there may still be cases where your app gets out of sync. For example, your app may have a bug in its event processing logic or in rarer cases, may experience some data loss. Data reconciliation refers to the process of comparing and aligning the state of objects between WorkOS and your app to ensure consistency. Depending on the scope of the issue, you can reconcile your app state by either replaying events from the [events API](/reference/events) or by using the WorkOS [state API](/reference). ## Definitions **Data reconciliation** : Refers to the process of comparing and aligning data from different sources or systems to ensure consistency and accuracy. The goal of data reconciliation is to ensure that all relevant data sources are synchronized and reflect the same information. **Event replay** : Is the act of reprocessing recorded events in an app. It is used to recreate past event sequences for debugging, testing, auditing, or ensuring data consistency. **Side effects** : These are secondary consequences that arise from data modifications in an app. They can alter related data, trigger additional processes, update external systems, or affect the app's overall state. e.g., Sending an email on a user's profile change. **Periodic reconciliation** : Is the regular process of comparing and synchronizing data between systems to ensure accuracy and consistency. It involves scheduled checks to identify and resolve discrepancies in data integrity. ## Reconciling via the events API In general, reconciling state changes between WorkOS and your app using the events API is simplest. Pick your cursor, which is usually the last known cursor you have processed, and paginate through events using the `after` parameter. For special cases such as webhook migration or event replay, you can specify a starting time for event consumption using the `range_start` parameter. ### Handling side effects in the case of event replay Side effects, such as sending emails, updating 3rd party APIs, or performing other actions specific to your app, present challenges during event replay. Separating data handling from business logic allows you to exercise control over what actions you want your app to make. This allows your app to replay events to sync data but bypass transactional logic e.g., not sending out the same email twice. ## Reconciling via the WorkOS state API Your app may perform data reconciliation by syncing state via the WorkOS [state APIs](/reference) e.g., in disaster recovery scenarios. Data reconciliation using state APIs requires performing diffs to identify deletions to ensure the correct state is maintained. This introduces additional complexity, making it essential to carefully design and test the reconciliation process. The general approach for reconciling data via the state API is as follows: 1. Pull state from WorkOS API for the objects your app is interested in. 2. Update based on `updated_at`. If the timestamp is out of date, update the object. 3. Identify deactivated objects or deletions and sync that state. If you need to force all objects to update state, perform a complete resynchronization of the affected data instead of relying solely on the `updated_at` timestamp. Update all objects regardless of the individual `updated_at` timestamp. ### Considerations for periodic reconciliation In some cases, you may want to run periodic reconciliation jobs to proactively check and reconcile the state between WorkOS and your app. When implementing such jobs, it is important to account for potential race conditions for concurrent updates. Additionally, consider the specific characteristics of your app to determine the frequency and scope of periodic reconciliation. ## Domain Verification {#domain-verification} ### Domain Verification Self-serve domain verification # Introduction Domain Verification allows your customers to claim ownership of a domain. Once they have claimed ownership, features that require a higher level of trust and security can be activated. WorkOS Domain Verification provides a self-serve flow through the Admin Portal in which IT contacts can prove ownership through the creation of DNS TXT records. ## Before getting started You'll need a [WorkOS account](https://dashboard.workos.com/). ### API object definitions [Organization](/reference/organization) : Describes an organization whose users sign in with a SSO Connection, or whose users are synced with a Directory Sync Connection. [Organization Domain](/reference/domain-verification) : Describes a domain associated to an organization, verified or unverified. [Portal Link](/reference/admin-portal/portal-link) : A temporary link to initiate an Admin Portal session. Valid for 5 minutes. All domains belong to an [Organization](/reference/organization). In order to create and verify a domain through the Admin Portal, an Organization must first be [created](/reference/organization/create). ## (A) Setup link from the WorkOS dashboard - Sign in to your [WorkOS dashboard](https://dashboard.workos.com/) account and create or locate an Organization. - Click the "Invite Admin" button, select **Domain Verification** then click "Next." Enter the emails of the IT contacts for the organization to automatically send them a setup link, or click "Copy setup link". If you chose to copy the setup link you can share it over email, Slack or direct message. We also recommend including details on what the link does and how long the link is active. ![A screenshot showing the workOS dashboard admin invite.](https://images.workoscdn.com/images/c9196bbf-3860-4a9a-be8c-83b503ae4e3d.png?auto=format&fit=clip&q=80) ## (B) Integrate with your app Admin Portal links can also be programmatically generated for the domain verification flow. This can be used to provide a link to the Admin Portal flow directly in your application. You'll have to generate the link with the `domain_verification` intent: Please refer to the [Admin Portal Integration Guide](/admin-portal/b-integrate-with-your-app) for additional integration details. --- ## Admin Portal domain verification After receiving the invitation and clicking on the setup link, the organization's IT contacts are prompted to enter the domain they wish to verify. ![A screenshot show the Admin portal domain entry form.](https://images.workoscdn.com/images/e7e719d6-579b-4567-8c80-772bc2f77563.png?auto=format&fit=clip&q=80) If the domain is valid, we identify the DNS service provider and offer custom setup instructions. The admin will find instruction to add a DNS TXT record with a token generated by our system. ![A screenshot showing the Admin Portal domain DNS instructions.](https://images.workoscdn.com/images/9ab7e2a4-8b11-4a03-8203-d95d1c1abb07.png?auto=format&fit=clip&q=80) When we detect and verify the DNS record, we will mark the domain as `verified` and dispatch a [domain verification event](/events) to inform your application. ### API Programmatic domain verification Instead of leveraging the Admin Portal, the Domain Verification API can be used to verify domains programmatically. Integrating with the API goes as follows: 1. Create an organization domain for an organization 2. Share the token and setup instructions with the organization owner (IT contact) 3. Wait for the verification to complete ## Create a new organization domain All domains belong to an [organization](/reference/organization). In order to create and verify a domain, an organization must first be [created](/reference/organization/create). The `verification_token` returned can then be set as the value of a TXT record that WorkOS will periodically check until the record is found. The TXT record for the above response example would be: - Name: `domain-to-verify.com` - Value: `verification_token=3CVZxo4HgvSiYRKlV4RdOWwWl` ## Get a domain Fetch an existing domain and it's current verification status. This endpoint can be polled once verification has been initiated to determine if verification has been successful. Possible `state` values: - `pending`: domain verification has been initiated and not yet completed - `verified`: domain has been verified - `failed`: domain was not able to be verified Possible `verification_strategy` values: - `dns`: domain is verified with the DNS flow - `manual`: domain is verified by a person or a system, without running the DNS flow ## Initiate verification for existing domain If a domain has not successfully verified within thirty days and moves to the `failed` state, verification can be restarted manually. ## Directory Sync {#directory-sync} ### Directory Sync Build frictionless onboarding for organizations with real‑time user provisioning and deprovisioning. ## Introduction Organizations use company directories and HRIS systems to manage users and enforce their access to organization resources. Directories enable IT contacts to activate and deactivate accounts, create groups that inform access rules, accelerate adoption of new tools, and more. ## Definitions **ULM** : User Lifecycle Management (or ULM) is the process of managing a user's access to an app. This occurs from app onboarding until they are removed from an app. ULM is also commonly referred to as identity provisioning. **SCIM** : System for Cross-domain Identity Management (or SCIM) is an open standard for managing automated user and group provisioning. It's a standard that many directory providers interface with. **HRIS** : A Human Resources Information System (or HRIS) is software designed to maintain, manage, and process detailed employee information and human resources-related policies. Examples include: Workday, HiBob, BambooHR, etc. **User Provisioning** : Provisioning is the process of creating a user and setting attributes for them – inside of an app. **User Deprovisioning** : Deprovisioning is the process of removing a user from an app. ## What is Directory Sync? Directory Sync is a set of developer-friendly APIs and IT admin tools that allows you to implement enterprise-grade User Lifecycle Management (ULM) into your existing app. ULM allows IT contacts to centrally provision and deprovision users from their directory provider. A directory provider is the source of truth for your enterprise customer's user and group lists. Directory Sync sends automatic updates to your app for changes to directories, groups, users, or access rules. Common directory providers include: [Microsoft Active Directory](/integrations/microsoft-ad-fs-saml), [Okta](/integrations/okta-scim), [Workday](/integrations/workday), and [Google Workspace](/integrations/google-directory-sync). See the full list of supported directory providers on the [integrations](/integrations) page. ## Why use Directory Sync? ULM increases the security of your app and makes it easier for your customers to use your app. ULM is most often implemented using [SCIM](/glossary/scim). SCIM requests are sent between directory providers and your app to inform you of changes to a user's identity. Changes can include: - Provisioning an identity for a user (account creation) - When a user's attribute has changed (account update) - Deprovisioning a user from your app (account deletion) Each directory provider implements SCIM differently. Implementing SCIM is often a challenging process and can introduce security vulnerabilities into your app. Directory Sync hides this complexity, so you can focus on building core product features in your app. ## What your customer experiences Let's take a look at two different user provisioning scenarios. ### (N) Your app doesn't use Directory Sync Without ULM, your customers have to manually add, update, and remove users from your app. Imagine a scenario where your customer has purchased your software and onboards a new employee to your app. Your customer would have to do the following: 1. The IT contact provisions the employee in their directory provider (_if they use one_) and manually in your app. 2. All employee information has to be set manually in both the directory provider and your app. 3. The IT contact has to manually provision a login method for the employee; through either SSO (_if they use an identity provider_) or a self-registration page. 4. The IT contact sends the invite link to their employee. Often initiating a back and forth via either email, messaging app, or IT helpdesk ticket. 5. The employee has to proceed with the registration method and can then use your app. All future changes to this employee's data and access are manually entered by IT contacts. This is error-prone and can lead to security vulnerabilities where users get unauthorized access to resources. As your customers adopt more cloud software, these manual processes do not scale well. Manual input error can lead to the source of truth (directory) drifting from your app's state. As a result, ULM has become a table stakes product requirement for enterprises. ### (Y) Your app uses Directory Sync If your app supports ULM via Directory Sync, the IT contact can provision this employee from one place: 1. Add the employee to their directory provider. 2. Assign the employee to your app with the appropriate role once; via the directory provider admin page. 3. **Optional.** Have the employee go through a password setup if they are not using an identity provider (SSO). Directory Sync makes this integration easy by providing APIs your app interfaces with. All updates for this directory will automatically be sent to your app from WorkOS. --- ## API overview [Directory](/reference/directory-sync/directory), [directory group](/reference/directory-sync/directory-group), and [directory user](/reference/directory-sync/directory-user) are the main components your app interfaces with. ### Directory A directory is the source of truth for your customer's user and group lists. WorkOS supports dozens of integrations including SCIM. Directory updates can be delivered to you via webhooks or retrieved using the [Events API](/reference/events). Your app stores a mapping between your customer and their directory. This allows you to maintain your app in sync with the directory provider used by your customer. You can enable self-service Directory Sync setup for your customers using the [Admin Portal](/admin-portal). ### Directory group A directory group is a collection of users within an organization who have been provisioned with access to your app. Directory groups are mapped from directory provider groups. Directory groups are most often used to categorize a collection of users based on shared traits. i.e. Grouping software developers at a company under an "Engineering" group. ### Directory user A directory user is a person or entity within an organization who has been provisioned with access to your app. Users can belong to multiple directory groups. Users have [attributes](/directory-sync/attributes) associated with them. These attributes can be configured for your app's needs. ### Understanding the Events Lifecycle Understand the lifecycle of the events that occur in Directory Sync. ## Introduction Directory Sync events represent actions performed within directory providers. For example, an action could mean an IT contact assigning a user to your app or modifying a user group assigned to your app. These actions form the basis of user lifecycle management (ULM). WorkOS provides information about these actions through a set of structured events. This reference guide will cover the events Directory Sync produces and what they mean. To learn about how to handle these events on your side, see the [data syncing guide](/events/data-syncing). --- ## Directory events ### `dsync.activated` This event occurs when you or your customer have successfully created a connection between WorkOS and your customer's directory provider. - | Lifecycle - | Payload `dsync.activated` is triggered if you manually create the directory connection in the [Developer Dashboard](https://dashboard.workos.com/), or your customer sets the connection up using the [Admin Portal](/admin-portal). The directory ID identifies a connection with the directory of a particular customer. Your app should save it and associate the directory ID with the corresponding organization ID. ### `dsync.deleted` This event occurs when a Directory Sync connection is deleted in WorkOS, thus tearing down the link between your customer's directory provider and your app. - | Lifecycle - | Payload A connection can be deleted through the [Admin Portal](/admin-portal), [Developer Dashboard](https://dashboard.workos.com), or [WorkOS API](/reference/directory-sync/directory/delete). At this point your app should remove the association between the corresponding organization and its directory, as it no longer exists. Directories, users, and groups are typically deleted if your app offboards a customer altogether. When receiving a `dsync.deleted` event, you can ignore the connection's `state` attribute, since it indicates the state before the deletion occurs. When a directory is deleted in WorkOS, a sole `dsync.deleted` event is sent. When a `dsync.deleted` event is received, it indicates that the users and groups in that directory have been deleted in WorkOS. You can process the `dsync.deleted` event accordingly in your application, removing the organization's groups and its users from your application or marking them as deleted. `dsync.user.deleted` and `dsync.group.deleted` events will not be sent for the deleted directory. --- ## Directory user events ### `dsync.user.created` This event occurs when an IT contact creates a user using their directory provider. It is standard to create and provision the user in your app when you receive this event. - | Lifecycle - | Payload You can add this user to your users table in your app and associate them with the directory ID and organization ID. You can begin to engage with the user at this point, e.g., send the user a "Getting Started" email. During the initial sync of any directory, you will receive a `dsync.user.created` event for each existing user in the directory. ### `dsync.user.updated` This event occurs when users' attributes change. These attributes may be [standard attributes](/directory-sync/attributes/standard-attributes), [auto-mapped attributes](/directory-sync/attributes/predefined-attributes), or [custom-mapped attributes](/directory-sync/attributes/custom-attributes). - | Lifecycle - | Payload The payload for `dsync.user.updated` event shows changes between directory group snapshots in the `previous_attributes` property. The changes in the object are shallow differences for root properties and `custom_attributes`. If the current snapshot has a new attribute that did not exist previously, then the value for the attribute will be indicated as `null`. ### `dsync.user.deleted` This event occurs when a user is hard-deleted from a directory. Typically, you would remove the user from your app in this case. - | Lifecycle - | Payload When users are removed from a directory, most providers will use a form of soft user deletion. In these cases, rather than receiving a `dsync.user.deleted` event, you will receive a `dsync.user.updated` event with the user's `state` marked as `inactive`. > After Oct. 19, 2023, all new environments will delete Directory Users that get moved to the "inactive" state. If you would like to retain these users, please reach out to support. You can find [more details here](/directory-sync/handle-inactive-users). --- ## Directory group events ### `dsync.group.created` This event occurs when creating a directory group in the directory provider. WorkOS also sends this event when a directory connection is established. - | Lifecycle - | Payload When WorkOS ingests this event, it first processes the users in the group. So, in most cases, you would receive `dsync.user.created`, then `dsync.group.created`, and finally, `dsync.group.user_added`. For more information on best practices for out-of-sequence events, see the [data syncing guide](/events/data-syncing). ### `dsync.group.updated` This event is sent when an attribute of a directory group has changed. - | Lifecycle - | Payload The payload for `dsync.group.updated` events shows changes between directory group snapshots in the `previous_attributes` property. The changes in the object are shallow differences for root properties and `custom_attributes`. If the current snapshot has a new attribute that did not exist previously, then the value for the attribute will be indicated as `null`. ### `dsync.group.deleted` This event occurs when deleting a directory group in the directory provider. When a `dsync.group.deleted` event is received, it indicates that the members in that group have been deleted in WorkOS. You can process the `dsync.group.deleted` event accordingly in your application, removing the group's members from your application or marking them as deleted. `dsync.group.user_removed` events will not be sent for the members in the deleted group. - | Lifecycle - | Payload If your app relies on groups to sync users or map roles, you should remove access for the users who belonged to the deleted group. ### `dsync.group.user_added` This event occurs when adding a directory user to a directory group. - | Lifecycle - | Payload If you map roles using groups, you should assign the group's role to the newly added user. ### `dsync.group.user_removed` This event occurs when removing a directory user from a directory group. - | Lifecycle - | Payload If you map roles using groups, you should remove the group's role from the user who belonged to the group. --- ## Data reconciliation techniques ### With the WorkOS state API The WorkOS API allows for data reconciliation for your app. You can use the WorkOS API to pull the latest data to reconcile any data discrepancies between WorkOS and your app. A standard method apps use for data reconciliation is to set up a cron job that pulls from the WorkOS API on a consistent interval, e.g., every 1 to 6 hours, depending on your app's user provisioning volume. > **Known issue:** Keeping track of WorkOS updated timestamps is of limited use right now because group membership changes for users do not alter the WorkOS `updated_at` timestamp. We're actively working on this issue. The general approach for performing a full sync of Directory Sync objects goes as follows: 1. Traverse all directory groups and update all local objects. 2. Traverse all directory users and update all local objects. 3. Extract group membership information from each user. Compare with local membership state. Add and remove memberships accordingly. 4. Compare the list of local users to all users seen in WorkOS traversal. Deactivate any users that exist locally but not on WorkOS. 5. Compare the list of local groups to all groups seen on WorkOS traversal. Deactivate any groups that exist locally but not on WorkOS. ### With the events API You can also reconcile directory data using the events API. See our [data syncing guide](/events/data-syncing/data-reconciliation) to learn more. ### Quick Start Set up a directory, install the SDK, and integrate Directory Sync. ## What you'll build 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. This guide will show you how to: 1. Create a new directory in the WorkOS Dashboard 2. Add Directory Sync to your app and fetch directory resources 3. Use events to keep your app in sync with the directory changes ## Before getting started To get the most out of this guide, you'll need: - A [WorkOS account](https://dashboard.workos.com/) - A directory from a directory provider that WorkOS supports ## API object definitions [Directory](/reference/directory-sync/directory) : Stores info about an organization's user management system (i.e. directory provider). [Directory user](/reference/directory-sync/directory-user) : Represents an organization user that is active in an organization's directory provider. [Directory group](/reference/directory-sync/directory-group) : A collection of organization users within a directory, e.g. IT, database admins, HR. > The WorkOS Directory Sync API exclusively uses read-only operations. We never mutate end-user directories. --- ## (1) Create a new directory connection The first step to connecting with a directory is creating an organization in the [WorkOS Dashboard](https://dashboard.workos.com/). You will then be able to create a new [connection](/glossary/connection) to the organization's directory. Let's start by creating one for development in your sandbox environment Get provider-specific instructions by selecting the directory provider you want to test: > You can view and copy the unique identifier for the directory connection on the directory page, once it has been set up. The id takes the form `directory_*`. --- ## (2) Add Directory Sync to your app Let's integrate the Directory Sync API into your app to enable fetching directory resources programmatically. ### Install the WorkOS SDK WorkOS offers native SDKs in several popular programming languages. Choose a language below to see instructions in your application's language. ### Set secrets To make calls to WorkOS, provide the API key and, in some cases, the client ID. Store these values as managed secrets, such as `WORKOS_API_KEY` and `WORKOS_CLIENT_ID`, and pass them to the SDKs either as environment variables or directly in your app's configuration based on your preferences. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' ``` > The code examples use your staging API keys when [signed in](https://dashboard.workos.com). ### Fetch directory resources Get the details of an existing directory user. Example use case: pre-populate user attributes for new user accounts. #### List directory users Get directory users for a given directory or directory group. Example use case: Build an onboarding experience that allows an admin to select who to invite and create accounts for. > Use the optional `limit`, `before`, and `after` parameters to paginate through results. See the [API Reference](/reference/pagination) for details. #### Get directory group Get the details of an existing directory group. Example use case: Pre-populate team attributes for new organizations. #### List directory groups Get directory groups for a given directory or directory user. Example use case: Build an onboarding experience that allows an admin to select which groups of employees to invite and create accounts for. > Use the optional `limit`, `before`, and `after` parameters to paginate through results. See the [API Reference](/reference/pagination) for details. ### Fetch user or group memberships To fetch the relationship between a specific user and group, scope the list endpoints with a filter parameter. This pattern keeps response payloads bounded by the size of a single user or group, and is the recommended replacement for the deprecated `groups` field on the directory user object. To list users that belong to a specific group, pass the `group` parameter to List directory users: To list groups a specific user belongs to, pass the `user` parameter to List directory groups: --- ## (3) Handle directory events Actions performed in a WorkOS environment are represented by events. These can occur as a result of user-related actions, manually via the WorkOS dashboard, or via API calls. To keep your app in sync with the latest directory data, follow the corresponding guides: - We recommend using our [events API](/events/data-syncing/events-api) to sync data to your application. To learn more about other ways to sync data, see the [data syncing guide](/events/data-syncing). - Learn about the different types of events that you can receive. See [event types](/events). - Understand how directory events work. See the [understanding events guide](/directory-sync/understanding-events). - Optionally, stream events to Datadog. See the [observability guide](/events/observability/datadog). ### Identity Provider Role Assignment Learn how to map role data from identity providers to roles in your app with Directory Sync. ## Introduction A role represents a logical grouping of permissions, defining access control levels for users within your application. Roles are identified by a unique, immutable slug and are assigned to Directory Sync [users](/directory-sync/api-overview/directory-user) through their group memberships. These role assignments can be configured on the WorkOS dashboard. To utilize Identity Provider (IdP) role assignment, you must first [configure roles](/rbac/configuration). ## Directory group role assignment Users are assigned to groups via the identity provider. Groups usually correspond to roles in your app. Therefore, IT contacts will often map a group one-to-one to a role. This can be defined within the WorkOS dashboard or Admin Portal for your application to receive automatic role updates. > Only supported in directories using SCIM-based or Google Workspace providers. ### Sample scenario Consider the fictional SaaS company _HireOS_. _HireOS_ has integrated Directory Sync and supports group-based role assignment. For example, a _HireOS_ customer would like to assign their engineering team to it. The customer's IT contact would take the following steps: 1. Create a group "Engineering" using their identity provider. 2. Push the group to _HireOS_ via the identity provider. This is configured in the identity provider admin console. The developer on the WorkOS dashboard can then assign users of that group to the role "Developer". 1. Navigate to the directory page on the WorkOS dashboard. ![The directory page on the WorkOS dashboard](https://images.workoscdn.com/images/88d4701b-7e6d-4655-ad74-48bc7c14959f.png?auto=format&fit=clip&q=50) 2. Create an assignment for "Engineering" to the "Developer" role. ![The role assignment dialog on the WorkOS dashboard](https://images.workoscdn.com/images/bdd4cc91-11cb-49b1-858b-f2509ce3675e.png?auto=format&fit=clip&q=50) From this point on, all new users added to "Engineering" will be given "Developer" role from the WorkOS API. The role will be in the [directory user response](/reference/directory-sync/directory-user). ![Screenshot of directory user page](https://images.workoscdn.com/images/18f584f6-d758-4f11-bfc8-e93c16452580.png?auto=format&fit=clip&q=50) ### Multiple roles When [multiple roles is enabled](/rbac/configuration/configure-roles/multiple-roles) in your environment, directory users can be assigned multiple roles from their identity provider group memberships. If a user belongs to multiple mapped groups, they will receive all corresponding roles. For example, if a user is a member of both "Engineering" and "Design" groups, and both groups are mapped to roles, the directory user will receive both the "Developer" and "Designer" roles. If a user is not a member of any groups with explicit mappings, they will receive the [default role](/rbac/configuration). When using [AuthKit with Directory Provisioning](/authkit/directory-provisioning), these multiple roles are automatically applied to the user's [organization membership](/reference/authkit/organization-membership) and reflected in their [session token](/authkit/sessions/integrating-sessions/access-token). #### Use cases By default, multiple roles is disabled and users can only have a single role per entity. It's recommended to start with a single-role setup for simplicity, where it's easier to maintain consistent and correct access patterns. You might want to enable multiple roles when you need: - **Cross-department collaboration**: e.g., designers who need some engineering permissions. - **Additive, disjoint permissions**: independent permission sets that should stack. - **Temporary access**: grant time-bound extra capabilities without creating hybrid roles. ### Role assignment in Admin Portal Once [roles](/rbac/configuration) are configured for your application, enable directory group role assignment in [Admin Portal](/admin-portal) to allow IT contacts to assign roles to groups during directory setup. ![Enable directory group role assignment dashboard setting](https://images.workoscdn.com/images/fe19e3ac-6370-404e-9590-cdb06b3de127.png?auto=format&fit=clip&q=50) This is an environment-level setting, but can be configured per organization via the _Roles_ tab under an organization in the WorkOS Dashboard. If your application is integrated with Directory Sync, it is recommended to use directory group role assignment as the environment default. ![Screenshot of admin portal with role assignment step](https://images.workoscdn.com/images/74d09b62-b2b2-4aba-9803-3ec6305897e0.png?auto=format&fit=clip&q=50) If enabled, all Admin Portal sessions for SCIM-based or Google Workspace directories will have the ability to see and assign roles to identity provider groups. ## Other forms of role assignment Your customers will store role information in different forms, depending on their preferred provisioning workflow. WorkOS allows for flexibility in how you source role data, though these formats are not automated today and not available on the role property on the [directory user response](/reference/directory-sync/directory-user). You can fetch role data via two distinct mechanisms: - A custom-mapped role attribute from the directory user profile. - A groups attribute in the SSO user profile. The type of mechanism needed will depend on the level of support for roles in your app, your app's architecture, and your customer's workflows: | Approach | Your app | Your customer | | ------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------ | | SSO group role assignment | Receives role data each time a user logs in | Uses identity provider groups to assign roles in your app | | Attribute-based role assignment | Sets roles based on a per-user custom-mapped attribute | Assigns roles using attributes on users in their identity provider | ### SSO group role assignment [SSO group role assignment](/sso/identity-provider-role-assignment/sso-group-role-assignment) involves mapping identity provider (IdP) groups to roles within your application during [Single Sign-On](/sso) and [JIT Provisioning](/sso/jit-provisioning). In this method, SSO groups corresponding to IdP groups are defined in the WorkOS Dashboard, and roles are assigned based on these group memberships. The user's role is then included in the [SSO profile](/reference/sso/profile) returned from WorkOS. [Read more](/sso/identity-provider-role-assignment/considerations/drawbacks) on this approach, including [drawbacks](/sso/identity-provider-role-assignment/considerations/drawbacks) to consider. ### Attribute-based role You can use [custom-mapped attributes](/directory-sync/attributes/custom-attributes/custom-attributes) if your customers do not use groups to establish and manage user roles. You can create a custom-mapped attribute role (e.g., `myRole`) in the [WorkOS Dashboard](https://dashboard.workos.com/) under Configuration → Directory Sync. You can set the status of a role attribute to "Required" or "Optional". ```json language="json" title="Directory user with a custom-mapped attribute" { "id": "directory_user_01E1X7B89OH8Z3SXFJR4H7RGX7", "idp_id": "821991", "first_name": "Jane", "last_name": "Doe", "name": "Jane Doe", "email": "jane@example.com", "state": "active", "created_at": "2021-06-25T19:07:33.155Z", "updated_at": "2021-06-25T19:07:33.155Z", "object": "directory_user", "directory_id": "directory_01E1X194NTJ3PXMAY79DYV0F0P", "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3PJNY", "custom_attributes": { "myRole": "admin" } } ``` The newly created attribute will appear as a field in the [Admin Portal](/admin-portal). When setting up Directory Sync with their identity provider in Admin Portal, your customers can map this role field to a field in their identity provider. You'll have to communicate with your customer what value(s) you expect in the custom-mapped attribute. An example being that `myRole` should be one of `"admin"`, `"viewer"`, or `"editor"`. This allows your app to parse the `myRole` field value correctly. ## Common edge cases ### A user is part of multiple groups Having a user who belongs to multiple groups is a common scenario. For example, there might be a case where an employee _Jane_ is an _Engineering Manager_ and belongs to an "Engineering", "Manager", and "Admin" group. With group-based role assignment, the user will be assigned the role that has the [highest priority defined](/rbac/configuration/configure-roles/priority-order). ### Role assignment availability on Directory Sync Identity provider role assignment through groups is only available through SCIM compliant and Google Workspace directories. ### Handle Inactive Users Learn why inactive users are deleted from directories by default and how to configure this behavior. ## Introduction Traditionally, user provisioning involves the ingestion of user information from various providers (either through SCIM or non-SCIM integrations). This process typically includes categorizing users into states such as `active`, or `inactive` as provided by the IdP data source. However, the challenge arises when businesses need to handle these `inactive` users differently based on their unique operational and security requirements. Some developers may prefer a security-first approach, automatically deleting these users to enhance data security, while others may opt to retain this information for reactivation processes or comprehensive directory management. --- ## Configuration To provide improved security and customizability, you can choose how `inactive` users are handled during the provisioning process. Here is an overview of the two options available: ### Secure flow (default) By selecting this option, customers can opt for a security-focused workflow. Any user marked as `inactive` will be automatically deleted from the directory, resulting in cleaner and potentially more secure data. This approach reduces the data footprint and minimizes potential security risks associated with unused accounts. ### Custom management flow Alternatively, customers can choose to maintain the existing flow, keeping the `inactive` users in the directory. This approach supports reactivation processes and ensures a comprehensive view of the directory, allowing for easier reintegration of users when needed. > Contact [customer support](mailto:support@workos.com) to enable custom management flow for your environment. ![A breakdown of the different events for each configuration path on handling inactive users.](https://images.workoscdn.com/images/2304739c-17e9-4521-96d2-81fa3fa83110.png?auto=format&fit=clip&q=80) ## Weighing the tradeoffs Both options offer distinct advantages, and the right choice depends on your organization's unique needs and security posture: ### Security vs. flexibility The automatic deletion option prioritizes data security by minimizing the data footprint, while the customized management option provides flexibility for reactivation flows and comprehensive directory oversight. ### Compliance and regulations Depending on industry regulations and compliance requirements, one option may align better with your organization's obligations. ### Operational efficiency Consider how each option impacts operational efficiency using WorkOS to handle a set of the computation for you. ### Reactivation If a user is temporarily removed, does the same user information need to be retained when they return? A new directory user will be created by default on return, whereas using the `inactive` user will retain the same information on reactivation. ### Example Apps View sample Directory Sync apps for each SDK. You can view minimal example apps that demonstrate how to use the WorkOS SDKs to power Directory Sync: ### Unique Emails Learn why directory user emails must be unique among active users, and how to avoid conflicts. ## Introduction Directory Sync requires directory user emails to be unique among active users within a directory. If an identity provider tries to provision or update a directory user with an email that another active user in the same directory already has, that request is declined and the affected user won't sync until the conflict is resolved. This is scoped per directory; the same email can still exist in different directories. Only active users count toward uniqueness. Deactivating a duplicate record in the identity provider immediately frees its email for the active user that should hold it. ### Why unique emails matter Unique emails make user resolution predictable. When each active user in a directory has a distinct email, just-in-time provisioning and your own application can reliably resolve a person by their email address. This keeps downstream authentication and account-linking behavior consistent for your users. --- ## Best practices for IT Admins Email conflicts originate in your customers' identity providers, so the fixes are IT admin actions. Share this guidance with the affected admins to keep directories syncing cleanly. - **Keep the username a stable field.** WorkOS identifies a directory user by their SCIM username. When a person's username changes, most providers re-provision them to WorkOS as a brand-new user instead of updating the existing one. To avoid this, map userName to a value that doesn't change for a person rather than something mutable; don't re-point the username mapping on a live directory; and don't rename users while you're also moving them between synced groups or reassigning them. - **Genuinely distinct identities need distinct emails.** Give each identity its own email address. For service or secondary accounts that don't need to sync, exclude them from the provisioning application instead. And on rehire, either reactivate the original user record, or deactivate the old record before re-provisioning so that only one active record holds the email. ### User Attributes Configure how attributes map from directory providers to Directory Users. ## Introduction WorkOS can automatically find and normalize most common attributes from directory providers into the [Directory User](/reference/directory-sync/directory-user) object, which represents an enterprise user. More unique cases can be mapped by your customers admins. In this guide, we'll explain how to map data from directory providers to the Directory Users. ## Definitions **Standard attributes** : The most common user information, normalized across providers. **Predefined attributes** : Detailed user attributes for specific use cases, normalized across providers. You can opt-in to each attribute you'd like auto-mapped. **Custom attributes** : For unique cases, you can create custom attributes your customers can map when setting up a directory. ## Standard attributes Every Directory User comes with the following standard attributes. These are the core set of attributes that are common across all identity providers. These are structured fields with a guaranteed schema in the top-level Directory User payload. | Attribute | Type and description | Status | | ------------ | ------------------------------------------------------------------------------------------------------------------------ | -------- | | `idp_id` | The user's unique identifier, assigned by the directory provider. Different directory providers use different ID formats | Required | | `first_name` | The user's first name | Optional | | `last_name` | The user's last name | Optional | | `email` | The user's email | Optional | | `state` | The user's state. May be `active`, or `inactive` | Required | > `emails`, `job_title`, and `username` were previously considered standard attributes, but have been deprecated in favor of equivalent [auto-mapped custom attributes](/directory-sync/attributes/custom-attributes/predefined-attributes). --- ## Custom attributes For more detailed user information, you can opt-in to additional predefined attributes and define your own custom attributes. These attributes will appear in the custom attributes field on [Directory User](/reference/directory-sync/directory-user) objects and can be configured in the [WorkOS Dashboard](https://dashboard.workos.com/). > Custom attributes are configured at the environment level. To configure attributes for a specific organization, please [contact our support team](mailto:support@workos.com). > When using AuthKit with directory provisioning, Directory User custom attributes are also available on the organization membership's `custom_attributes` field. See [JWT Templates](/authkit/jwt-templates) for how to include these in your access tokens. ### Predefined attributes When enabled, the values will be mapped without additional setup. Not every directory provider has data for every field, so they are always optional if enabled. These fields are named and schematized by WorkOS – they cannot be renamed. | Attribute | Type and description | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `addresses` | The user's list of address objects (`street_address`, `locality`, `region`, `postal_code`, `country`, `primary`, `raw_address`) | | `cost_center_name` | The user's cost center name | | `department_name` | The user's department name | | `display_name` | The user's display name | | `division_name` | The user's division name | | `emails` | The user's list of email objects (`type`, `value`, `primary`) | | `employee_number` | The user's employee number assigned by the organization | | `employee_type` | The user's employment type | | `employment_start_date` | The user's start date | | `job_title` | The user's job title | | `manager_name` | The name of the user's manager | | `manager_id` | The identifier of the user's manager from the directory provider | | `manager_email` | The email address for the user's manager | | `organization` | The name of the user's organization | | `phone_numbers` | The user's list of phone number objects (`value`, `display`, `type`, `primary`) | | `username` | The user's username | #### Enable or disable a predefined attribute Predefined attributes can be enabled or disabled in the [WorkOS Dashboard](https://dashboard.workos.com/) on the Identity Provider Attributes page. ![WorkOS Dashboard UI showing editing predefined attributes](https://images.workoscdn.com/images/73b775ed-c3ef-4c81-bb56-7b040d3d073a.png?auto=format&fit=clip&q=50) > Updates to these settings may take up to an hour to reflect in your Directory User API response. A [dsync.user.updated](/events/directory-sync) event is emitted for each Directory User changed by toggling auto-mapped attributes. ### Support per directory provider The following support table outlines the attribute availability across directory providers. ### Custom attributes Custom attributes can be utilized to enrich [Directory User](/reference/directory-sync/directory-user) objects with additional data from the identity provider. You can create attributes that appear as fields in the [Admin Portal](https://workos.com/admin-portal). Your customers can map these fields to the correct values in their system when setting up Directory Sync with their identity provider. #### Create a custom attribute Custom attributes can be created in the [WorkOS Dashboard](https://dashboard.workos.com/) on the Identity Provider Attributes page. ![WorkOS Dashboard UI showing custom attribute creation](https://images.workoscdn.com/images/c1d00c4c-4dea-415e-a8f8-c870317410df.png?auto=format&fit=clip&q=50) #### Delete a custom attribute When a custom attribute is deleted, the attribute will be deleted from all [Directory User](/reference/directory-sync/directory-user) objects. > Updates to custom attributes may take up to an hour to reflect in your Directory User API response. A [dsync.user.updated](/events/directory-sync) event is emitted for each Directory User changed. #### Nested attributes Custom attributes support nested attribute mapping. Different directory providers structure their data differently, and nested attribute support allows you or your customer to map values regardless of where they appear in the directory structure. Nested attributes from the directory can be mapped to custom attributes using the WorkOS [Dashboard](https://dashboard.workos.com/) or [Admin Portal](/admin-portal) by selecting attributes from an interactive schema viewer. The schema viewer displays the structure of user data from their directory, allowing them to browse and select any nested field. This ensures accurate mapping without manual configuration. ##### Example: Different structures across providers The same logical attribute (like "license") may appear at different nesting levels depending on the provider: ```json language="json" title="Provider A - Nested under URN" { "userName": "jdoe@example.com", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { "license_tier": "silver" } } ``` ```json language="json" title="Provider B - Under custom schemas" { "userName": "jdoe@example.com", "customSchemas": { "license_tier": "silver" } } ``` With nested attribute support, you can create a single custom attribute called `license_tier`, and IT admins can map it to the correct location in their specific directory provider's structure using the schema viewer. --- ## Raw attributes \[Deprecated] The `raw_attributes` field on [Directory User](/reference/directory-sync/directory-user) objects is deprecated and will **stop returning data on April 15, 2026**. [Custom attributes](/directory-sync/attributes/custom-attributes/custom-attributes) and [nested attribute mapping](/directory-sync/attributes/custom-attributes/custom-attributes) are the recommended replacements. These features provide a consistent, structured API while giving IT admins the flexibility to map any field from their directory provider. Contact support [via email](mailto:support@workos.com) or Slack if you need help with the migration. We also have tooling to automate the WorkOS-side configuration on your behalf. For a full migration walkthrough covering Directory Sync, SSO, and AuthKit, see the [migration guide](/deprecations/raw-attributes). --- ## Frequently asked questions ### Are existing directories required to update the attribute mapping when new required custom attributes are added? No, when you add a new required custom attribute to your settings, this won't be retroactively required for directories that have already been set up and configured. However, in the WorkOS dashboard, you will be able to navigate directly to the existing directory and fill in details for those attributes manually. ### Can our customers add their own custom attributes outside of what is defined in the WorkOS dashboard? We do not currently support this functionality, as you have to define any custom attributes in the dashboard first. Please reach out to [support](mailto:support@workos.com) if you have a specific use case that you would like to discuss. ### What happens if an attribute cannot be mapped from the IdP? Attributes that cannot be mapped for a particular [Directory User](/reference/directory-sync/directory-user) will result in a `null` value for the attribute. [dsync.user.updated](/events/directory-sync) events are not emitted when an attribute changes from `null` to `undefined` or vice versa. ### How do IT admins map nested attributes? IT admins can map nested attributes using the schema viewer in the WorkOS [Admin Portal](/admin-portal) when configuring their directory. The schema viewer displays the actual structure of user data from their directory provider, showing how attributes are organized. To map a nested attribute: 1. IT admins navigate to the attribute mapping step during directory configuration 2. They view a visual representation of their directory's user data structure 3. They select any field, regardless of nesting level, from the schema viewer 4. The mapping is automatically configured for that nested attribute This approach works consistently across all directory providers, even though each provider may structure their data differently. The schema viewer adapts to show the specific structure of the IT admin's directory provider, ensuring accurate mapping without requiring technical knowledge of the underlying data format. ## Deprecations {#deprecations} ### Migrate from raw_attributes How to migrate from raw_attributes and legacy standard attributes to custom attributes. ## Overview On **April 15, 2026**, two changes take effect across Directory Sync and SSO: 1. **`raw_attributes` will stop returning data.** The field will return an empty object everywhere your integration consumes it: - **API responses** — when you fetch [Directory Users](/reference/directory-sync/directory-user), [Directory Groups](/reference/directory-sync/directory-group), or [SSO Profiles](/reference/sso/profile) - **Webhooks and Events API** — on all Directory Sync user events (`dsync.user.created`, `dsync.user.updated`, `dsync.user.deleted`) and group events (`dsync.group.created`, `dsync.group.deleted`, `dsync.group.user_added`, `dsync.group.user_removed`) 2. **Top-level `job_title`, `username`, and `emails` will be removed** from [Directory User](/reference/directory-sync/directory-user) objects. These fields will return `null` (or `[]` for `emails`). > **Your customers do not need to make any changes.** You do not need to coordinate with your customers' IT contacts or ask them to remap anything. See the migration paths below for what you need to do. --- ## Migrating from `raw_attributes` If your code reads from `raw_attributes` on [Directory Users](/reference/directory-sync/directory-user) or [SSO Profiles](/reference/sso/profile), [contact us](mailto:support@workos.com) and we will automatically set up the equivalent custom attribute mappings across all of your existing connections. You then update your code to read from `custom_attributes` instead. You can also configure custom attribute mappings yourself from the [IdP Attributes page](https://dashboard.workos.com/environment/identity-provider-attributes) in the Dashboard. See [Custom Attributes for Directory Sync](/directory-sync/attributes/custom-attributes/custom-attributes) or [Custom Attributes for SSO](/sso/attributes/custom-attributes/custom-attributes) for details. ```javascript title="Before" // Directory Sync - nested fields const licenseTier = user.raw_attributes[ 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User' ]?.license_tier; const employeeId = user.raw_attributes.customSchemas?.Company?.employeeId; // SSO const department = profile.raw_attributes.department; ``` ```javascript title="After" // Directory Sync - custom attributes const licenseTier = user.custom_attributes.license_tier; const employeeId = user.custom_attributes.employee_id; // SSO const department = profile.custom_attributes.department_name; ``` > **Using AuthKit?** If you access `raw_attributes` via the SSO Profile or Directory User API, the migration above applies to you. Additionally, you can now access IdP attributes directly in AuthKit JWTs and the Organization Membership API - no standalone API call needed. See [Custom Attributes in AuthKit](/authkit/jwt-templates/custom-attributes). --- ## Migrating from legacy standard attributes If your code reads `job_title`, `username`, or `emails` from the top level of Directory User objects, you can migrate without contacting us: 1. Update your code to read from `custom_attributes` with a fallback to the top-level field, then deploy. 2. Enable the equivalent [predefined attribute](https://dashboard.workos.com/environment/identity-provider-attributes) in the WorkOS Dashboard. This order ensures no data is missed during the transition - your code handles both locations until the predefined attribute is active. ```javascript title="Before" const jobTitle = user.job_title; const emails = user.emails; const username = user.username; ``` ```javascript title="Step 1: Deploy with fallback" const jobTitle = user.custom_attributes?.job_title ?? user.job_title; const emails = user.custom_attributes?.emails ?? user.emails; const username = user.custom_attributes?.username ?? user.username; ``` ```javascript title="Step 2: After enabling predefined attributes, clean up" const jobTitle = user.custom_attributes.job_title; const emails = user.custom_attributes.emails; const username = user.custom_attributes.username; ``` > If you use `emails` only to get the user's primary email address, you can use the `email` standard attribute instead, which remains on the top-level Directory User object. --- ## Example payload ```json title="Before" { "id": "directory_user_xxxxx", "idp_id": "xyz", "email": "marcelina@example.com", "job_title": "Software Engineer", "username": "marcelinadavis", "emails": [ { "type": "work", "value": "marcelina@example.com", "primary": true } ], "custom_attributes": {}, "raw_attributes": { "name": { "givenName": "Marcelina", "familyName": "Davis" }, "userName": "marcelinadavis", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { "department": "Engineering", "costCenter": "R&D" } } } ``` ```json title="After" { "id": "directory_user_xxxxx", "idp_id": "xyz", "email": "marcelina@example.com", "custom_attributes": { "job_title": "Software Engineer", "username": "marcelinadavis", "emails": [ { "type": "work", "value": "marcelina@example.com", "primary": true } ], "department_name": "Engineering", "cost_center_name": "R&D" } } ``` --- ## Learn more - [Custom Attributes for Directory Sync](/directory-sync/attributes/custom-attributes/custom-attributes) - [Custom Attributes for SSO](/sso/attributes/custom-attributes/custom-attributes) - [Predefined Attributes](/directory-sync/attributes/custom-attributes/predefined-attributes) - [Custom Attributes in AuthKit](/authkit/jwt-templates/custom-attributes) - [Changelog](https://workos.com/changelog/custom-attributes-in-authkit) - [SAML Custom Attributes](https://workos.com/changelog/saml-custom-attributes) - [OIDC Attributes](https://workos.com/changelog/oidc-attributes) ## Custom Domains {#custom-domains} ### Custom Domains Configure your integration to match your brand identity. ## Overview By default, a WorkOS domain will be used for services such as sending email and hosting AuthKit. In the staging environment these will always use a WorkOS domain, however in production you have the option to provide your own custom domain. This is a paid service, for which you can find additional details on our [pricing page](https://workos.com/pricing.md). Custom domains can be set for: - [Email](/custom-domains/email) - [AuthKit](/custom-domains/authkit) - [Admin Portal](/custom-domains/admin-portal) - [Authentication API](/custom-domains/auth-api) ### Email Domain Guidance on configuring a custom domain for emails. ## Configuring a domain Several AuthKit features require sending emails: - Magic Auth - Email verification - Password resets - Invitations While developing with WorkOS in a staging environment, WorkOS will send AuthKit emails from `workos.dev`. In production environments, emails are sent from a custom domain when configured or from `workos-mail.com` by default. ### (1) Navigate to Domains configuration With the production environment selected, navigate to the _Domains_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). ![Dashboard displaying domain configuration settings](https://images.workoscdn.com/images/1b02397b-89b0-451d-9d6d-d222db5635b9.png?auto=format&fit=clip&q=80) ### (2) Add an email domain Click the _Add Domain_ button and enter the domain you would like to use for sending emails. ![Dashboard displaying a domain entry input](https://images.workoscdn.com/images/2e7840fb-1a05-444c-a68f-52f3ac3eceb5.png?auto=format&fit=clip&q=80) ### (3) Create CNAME records You will be prompted to create 3 CNAME records with your DNS provider. After creating these DNS records, click _Verify now_. ![Dashboard displaying CNAME entries](https://images.workoscdn.com/images/0d85fad9-2af7-425d-8b4b-55c407a0db83.png?auto=format&fit=clip&q=80) > It can take some time for DNS changes to take effect. If the initial verification attempt is not successful, WorkOS will continue trying to verify your domain for 72 hours. Once your domain is successfully verified, authentication emails and Admin Portal invites will be sent from `no-reply@your-domain.com`. It's important to keep the CNAME records in place to ensure that WorkOS can deliver mail on your behalf. ### AuthKit Domain Guidance on configuring a custom domain for AuthKit. ## Configuring a domain The domain for AuthKit will consist of a randomly generated phrase plus the domain `authkit.app`, for instance `youthful-ginger-43.authkit.app`. This is the default in the staging environment, in Production environments a custom domain can be configured via the dashboard. ### (1) Navigate to Domains configuration With the production environment selected, navigate to the _Domains_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). ![Dashboard displaying domain configuration settings](https://images.workoscdn.com/images/f04be28f-4af8-4a2e-a812-815d1a441674.png?auto=format&fit=clip&q=80) ### (2) Add an AuthKit domain Click the _Configure AuthKit domain_ button and enter the domain you would like to use. ![Dashboard displaying a domain entry input](https://images.workoscdn.com/images/b7e45bfe-2948-4d5e-a7ee-be3eb223d710.png?auto=format&fit=clip&q=80) ### (3) Create CNAME records You will be prompted to add a CNAME record to your DNS provider. If your DNS provider is Cloudflare, ensure the CNAME record is configured as DNS-only and is not proxied. To manage custom domains, WorkOS uses Cloudflare, who prohibit domains from being proxied across accounts. ![Dashboard displaying CNAME entries](https://images.workoscdn.com/images/68d96188-8d68-4a89-8843-5d21d9b739c5.png?auto=format&fit=clip&q=80) > It can take some time for DNS changes to take effect. If the initial verification attempt is not successful, WorkOS will continue trying to verify your domain for 72 hours. Once your domain is successfully verified, users signing in via AuthKit will be redirected to your custom domain. ### Authentication API Domain Guidance on configuring a custom domain for the Authentication API. ## Configuring a domain WorkOS authentication requests are done via the Authentication API, which defaults to `api.workos.com`. This can be configured to a custom domain if you prefer to use your own branding instead of the default. While developing with WorkOS in a Sandbox environment, requests are made to the `api.workos.com` domain. In production environments, requests are made to `api.workos.com` by default or a custom domain if configured. For instance, if you were retrieving a user via the API and you had a custom Authentication API domain `api.example.com` set up, you'd make requests to: `https://api.example.com/user_management/users/:id` Instead of the default: `https://api.workos.com/user_management/users/:id` > When a custom domain is configured, requests to the API should be routed through that domain. Continuing to make requests to `api.workos.com` after a custom domain is configured for the Authentication API can result in issues with your integration. ### Custom domains for SCIM endpoints Custom Authentication API domains are also used for SCIM endpoints when using [Directory Sync](/directory-sync). For example, if you had a custom domain `api.example.com` set up, your customer's identity provider would make requests to `https://api.example.com/scim/v2.0/:id`. The custom domain is reflected in the Admin Portal setup steps for a directory. Adding a custom domain does not affect existing directory integrations pointing to `api.workos.com`. ### Using custom domains in SDKs When using the WorkOS SDKs, a custom API hostname can be configured: ### (1) Navigate to Domains configuration With the production environment selected, navigate to the _Domains_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). ![Dashboard displaying domain configuration settings](https://images.workoscdn.com/images/28d1072b-1bc7-42af-8d7d-fb8da0363413.png?auto=format&fit=clip&q=80) ### (2) Add an email domain Click the _Configure authentication API domain_ button and enter the domain you would like to use. ![Dashboard displaying a domain entry input](https://images.workoscdn.com/images/cc648df5-603a-4001-bfc0-cea2bfca02e5.png?auto=format&fit=clip&q=80) ### (3) Create CNAME records You will be prompted to add a CNAME record to your DNS provider. If your DNS provider is Cloudflare, ensure the CNAME record is configured as DNS-only and is not proxied. To manage custom domains, WorkOS uses Cloudflare, who prohibit domains from being proxied across accounts. ![Dashboard displaying CNAME entries](https://images.workoscdn.com/images/e920f0c9-4bd5-4f11-a2e3-9d709b483ed1.png?auto=format&fit=clip&q=80) > It can take some time for DNS changes to take effect. If the initial verification attempt is not successful, WorkOS will continue trying to verify your domain for 72 hours. Once your domain is successfully verified, your custom domain will act as the [ACS URL](/glossary/acs-url) for authentication. ### Admin Portal Domain Guidance on configuring a custom domains for the Admin Portal. ## Configuring a domain When your customers' IT contacts use the Admin Portal self-serve onboarding experience, they'll be directed to a `setup.workos.com` domain. While developing with WorkOS in a staging environment, users will see the `setup.workos.com` domain. In production environments, users will see `setup.workos.com` by default or a custom domain if configured. ### (1) Navigate to Domains configuration With the production environment selected, navigate to the _Domains_ section of the [WorkOS Dashboard](https://dashboard.workos.com/). ![Dashboard displaying domain configuration settings](https://images.workoscdn.com/images/b6afe130-219c-4e0e-8209-49b1a0fb6098.png?auto=format&fit=clip&q=80) ### (2) Add an Admin Portal domain Click the _Configure Admin Portal domain_ button and enter the domain you would like to use. ![Dashboard displaying a domain entry input](https://images.workoscdn.com/images/6dc8c261-3f1a-4d7a-b9ea-e7541d5e1361.png?auto=format&fit=clip&q=80) ### (3) Create CNAME records You will be prompted to add a CNAME record to your DNS provider. If your DNS provider is Cloudflare, ensure the CNAME record is configured as DNS-only and is not proxied. To manage custom domains, WorkOS uses Cloudflare, who prohibit domains from being proxied across accounts. ![Dashboard displaying CNAME entries](https://images.workoscdn.com/images/467edbdc-ba6d-42be-809e-7b0b1e560385.png?auto=format&fit=clip&q=80) > It can take some time for DNS changes to take effect. If the initial verification attempt is not successful, WorkOS will continue trying to verify your domain for 72 hours. Once your domain is successfully verified, IT contacts using the self-serve Admin Portal will be redirected to your custom domain. ## AuthKit {#authkit} ### Get started with AuthKit Set up AuthKit in your app using either the AI Installer & CLI or a manual framework-specific guide. ## Use the AI Installer & CLI Automatically integrate WorkOS into your app with one command. The [AI Installer & CLI](/authkit/cli-installer) also manages resources, provisions environments, and equips your coding agents with WorkOS knowledge. ```bash title="AI Installer & CLI" npx workos@latest ``` ## Or install using your preferred stack Follow a framework-specific guide to integrate AuthKit manually. ### Waitlist Review and approve signup requests before granting access to your application. ## Introduction The waitlist collects signup requests and lets you review them before users can register. This is useful for gated launches, closed betas, or any application that requires vetting users before they can sign up. When the waitlist is enabled, the AuthKit signup form is replaced with a form that collects the user's email and adds them to the waitlist. Each entry appears in the WorkOS dashboard where it can be approved or denied individually. ## How the waitlist works When a user joins the waitlist from the AuthKit signup form, a pending entry is created for their email address. From the "Waitlist" tab in the "Users" section of the WorkOS dashboard, each entry can be: - **Approved.** The user receives an email with a link to complete their signup. - **Denied.** The entry is marked as denied and the user is not notified. Waitlist entries are scoped to an environment, so entries collected in a staging environment are kept separate from production. ## Who can sign up when the waitlist is enabled When the waitlist is enabled, users cannot register for a new account through the AuthKit signup form or the API. Existing users can still sign in. The following users can still sign up: - **Invited users.** When a valid invitation code is present in the sign-in flow, registration is opened up so that the invited user may sign up. See [Invitations](/authkit/invitations) for details on sending and accepting invitations. - **Users with verified email domains.** If the user's email domain matches a [verified domain](/authkit/domain-verification) of an organization with [JIT provisioning](/authkit/jit-provisioning) enabled, a new user is created and added to the organization. Pre-configured domain access is honored so members of known organizations aren't routed through the waitlist. ## Enabling the waitlist To enable the waitlist for your account, [contact us](mailto:support@workos.com?subject=AuthKit%20Waitlist). Once enabled, you can turn it on per environment from the authentication section of the WorkOS [dashboard](https://dashboard.workos.com/). ## Waitlist webhooks WorkOS emits webhook events when waitlist entries change state: - `waitlist_user.created` — a new user joined the waitlist. - `waitlist_user.approved` — an entry was approved. - `waitlist_user.denied` — an entry was denied. Subscribe to these events by [creating a webhook endpoint](/reference/webhooks/create) in the WorkOS dashboard. This lets you plug the waitlist into review workflows in other systems, such as auto-approving entries from known email domains or notifying a Slack channel when new entries arrive. ### Users and Organizations Flexible application modeling with user and membership features. ## Users The [User object](/reference/authkit/user) represents an identity that has access or owns artifacts in your application. A User object may not uniquely identify an individual person, since a person may present themselves as having multiple identities in the same system. What uniquely identifies a user is their **email address**, since having access to that email inbox ultimately gives access to all accounts based on that address. ### Authentication methods There may be multiple authentication methods on a single user object, such as [Email + Password](/authkit/email-password) or [OAuth](/authkit/social-login). A user can sign in with any of the authentication methods associated with them, as long as you have enabled those authentication methods in the WorkOS Dashboard. ### Identity linking Because a user is uniquely identified by their email address, you won't have users with duplicate email addresses. WorkOS handles [identity linking](/authkit/identity-linking) automatically. ### Email verification All users will go through an initial [email verification process](/authkit/email-verification) by default. This applies to all authentication methods, including OAuth and SSO. This unifying interface simplifies how your application considers the authenticity of your users. ### Domain verification If a user's email domain matches a verified organization domain when signing in with SSO, they will [automatically be considered verified](/authkit/domain-verification) and will not need to go through the email verification flow. --- ## Organizations Organizations represent both a collection of users that your customers' IT contacts have control over and a workspace within which members collaborate. Organizations are a first-class concept in WorkOS and support a suite of features around organizational management. There is no limit to the number of organizations you can create in WorkOS. ### Organization memberships An organization contains users as members. Organization membership allows you to model organizations as "workspaces" and user's access to them with memberships. WorkOS organization memberships are designed to be flexible, and support any B2B app model. For example: - **Multiple Workspaces:** A self-serve productivity app, like Figma, where each user can be in any number of organizations, can create their own workspace and join any number of other workspaces. - **Single Workspace:** An app that has no collaboration outside a customer's company, like an employee survey tool, where each user is in exactly one organization. While these are two distinct models, your choice may depend on your go-to-market strategy, which may change over time. **WorkOS AuthKit supports both**. ### Organization access It's common for users to create resources in B2B applications. You can use the organization as a container for these resources, so that access is dependent on a user's access to the organization. This means when a user leaves an organization and is no longer a member, the data remains with the organization and not the user. Organizations provide the level of data ownership that B2B applications structure around. While organization membership conveys the most basic form of access, you can attach more granular role information per member within your own application's database. ### Custom roles In addition to the [environment-level roles](/authkit/roles-and-permissions/configure-roles-and-permissions), organizations can define their own custom roles, which are assignable only within the context of the organization. Refer to the [custom roles documentation](/rbac/custom-roles) for more details. ### Membership management If your application uses a soft-delete model, you can utilize the extended organization membership lifecycle. Organization memberships have three possible statuses: - `pending`, when a user is invited to an organization - `active`, when a user is added as an organization member or accepts an invitation - `inactive`, when an organization membership is deactivated For soft-delete use cases, we also provide deactivation and reactivation APIs: - [Deactivating an organization membership](/reference/authkit/organization-membership/deactivate) sets its status to `inactive` and revokes all active [sessions](/authkit/sessions). Note `pending` memberships cannot be deactivated and should be deleted using the [deleting membership API](/reference/authkit/organization-membership/delete) instead. - [Reactivating an organization membership](/reference/authkit/organization-membership/reactivate) sets its status to `active` and retains the role attached to the organization membership prior to deactivation. This role can be updated using the [update organization membership API](/reference/authkit/organization-membership/update). Note `pending` memberships cannot be reactivated. For this the user should go through the [invitation acceptance flow](/authkit/invitations) instead. If invitations are not needed, the organization membership can be [created as active directly](/reference/authkit/organization-membership/create). If your application uses a hard-delete model, you may use organization memberships without deactivation/reactivation by [deleting memberships](/reference/authkit/organization-membership/delete) for users who should no longer have access to an organization. ### When to use deletion vs. deactivation Hard deletion is preferred if the app has no need to "remember" the membership. For example, when members operate solely on customer data and have no data of their own. When a member of the organization is gone, there's no need to keep around their membership data. An app in this case may even want to entirely [delete the User](/reference/authkit/user/delete) once the membership is deleted. Deactivation may be preferred in cases where a member retains some data after leaving the organization, for example: messages, documents, or other data which reference that member. It also allows for building a user interface to list former members, perhaps with the option to reactivate them. ### Automated memberships Beyond manually adding or removing users to and from organizations as members, users can be automatically [Just-in-Time (JIT) provisioned](/authkit/jit-provisioning) into an organization if their email address matches one of the organization's [verified domains](/authkit/domain-verification). This allows customers to quickly onboard teammates. Users can also [invite individuals to organizations](/authkit/invitations), regardless of their email domain. This is handy for contractors within a company, or a collection of people without a shared domain. ### Creating organizations for new users In some applications, all activity should happen within the context of an organization. This pattern is common in B2B applications where: - All features and data are scoped to an organization - Users need to be associated with an organization to use the application For these applications, when new users don't already belong to an organization via [Just-in-Time provisioning](/authkit/jit-provisioning) or an [invitation](/authkit/invitations), you'll want to create an organization for them. To ensure all users have at least one organization: 1. **Check the access token**: When AuthKit redirects a user to your application after sign up or sign in, check whether the [access token](/authkit/sessions/integrating-sessions/access-token) contains an `org_id` 2. **Present organization creation form**: If no organization is present, show the user a form with a name field to create a new organization 3. **Create the organization**: On form submission, use the [create organization API](/reference/organization/create) to create the organization 4. **Create organization membership**: Use the [create organization membership API](/reference/authkit/organization-membership/create) to add the user as a member of the new organization 5. **Refresh the token**: Call the [authenticate with refresh token API](/reference/authkit/authentication/refresh-token) with the new organization ID to receive a new access token that includes the organization ### Single Sign-On Facilitate greater security, easier account management, and accelerated application onboarding and adoption. ## Introduction Single Sign-On is the most frequently asked for requirement by organizations looking to adopt new SaaS applications. SSO enables authentication via an organization's [identity provider (IdP)](/glossary/idp). This service is compatible with any IdP and supports both the [SAML](/glossary/saml) and [OIDC](/glossary/oidc) protocols. It's modeled to meet the [OAuth 2.0](/glossary/oauth-2-0) framework specification, abstracting away the underlying authentication handshakes between different IdPs. ## Getting started AuthKit greatly simplifies the process of integrating SSO into your application. AuthKit will make the necessary API calls automatically and handle the routing of SSO users when their account is associated with an existing SSO connection. ## (1) Enable SSO Navigate to the _Authentication_ settings section in the [WorkOS Dashboard](https://dashboard.workos.com/) and enable Single Sign-On. ![Dashboard demonstrating how to enable Single Sign-On](https://images.workoscdn.com/images/09c9b3c5-833e-4fe0-985b-f5b1934e4284.png?auto=format&fit=clip&q=80) AuthKit will now automatically detect when a user is attempting to sign in via SSO and redirect them to the appropriate IdP. ## (2) Test with the Test Identity Provider To confirm your Single Sign-On integration works correctly you can use the Test Identity Provider to simulate login flows end-to-end. Your staging environment includes a default Test Organization and active SSO connection configured with the Test Identity Provider. ![WorkOS Test Identity Provider](https://images.workoscdn.com/images/7b7407d7-dcc7-4fd4-859f-4ee4214d69c2.png?auto=format&fit=clip&q=80) ### Getting started Log into the [WorkOS Dashboard](https://dashboard.workos.com/) and navigate to the _Test SSO_ page to get started with the Test IdP. This page outlines a number of different SSO scenarios you can follow and provides all the necessary information to complete the tests. ![Test SSO WorkOS Dashboard](https://images.workoscdn.com/images/7b7407d7-dcc7-4fd4-859f-4ee4214d69c2.png?auto=format&fit=clip&q=80) ### Service provider-initiated SSO This case is likely the first [login flow](/sso/login-flows/sp-initiated-sso) you would test when implementing SSO in your app. The test simulates users initiating authentication from your sign-in page. In this scenario, the user enters their email in your app, gets redirected to the identity provider, and then is redirected back to your application. ### Identity provider-initiated SSO This test simulates users initiating authentication from their identity provider. It is a common [login flow](/sso/login-flows/idp-initiated-sso) that developers forget to consider. In the scenario, users log in to the identity provider directly, select your application from their list of SSO-enabled apps, and are redirected to your application upon successful authentication. ### Guest email domain This test simulates users authenticating with an email domain different from the verified domain of the test organization, `example.com`. A relevant scenario is authenticating freelance users, whose email domain is not owned by the company. ### Error response This test simulates a generic [error response](/reference/sso/get-authorization-url/error-codes) from the user's identity provider. In this scenario, SSO authentication has failed for the user. Below is an example of the error-related parameters passed to the [redirect URI](/sso/redirect-uris) in your application. --- ## (3) Test with other identity providers Test Identity Provider saves time by providing an out of the box experience compared to the configuration process that someone using a real identity provider would have to go through to enable Single Sign-On for your app. If your integration works with the Test Identity Provider, you can be sure it will work with other identity providers. However, it may be helpful to also learn about the setup process that your customers will go through on their side, which varies depending on a specific identity provider. ### Create an organization To get started, you will need to [create an organization](https://dashboard.workos.com/organizations) in the WorkOS Dashboard. Organizations in WorkOS represent your customer, so by creating an organization, you can test your SSO connection the way your customers will experience it. ![Create an organization dialog](https://images.workoscdn.com/images/2ef3565c-526a-42e6-9830-622e83b67ee5.png?auto=format&fit=clip&q=80) ### Create a connection Go to the organization you created and click _Invite admin_. Select _Single Sign-On_ from the list of features. In the next step, enter an email address to send the setup link to, or click _Copy setup link_. The setup link goes to Admin Portal, where your customers get the exact instructions for every step they need to take to enable Single Sign-On with your app. > You can also integrate [Admin Portal](/admin-portal) directly into your app to enable self-serve setup of Single Sign-On and other enterprise features for your users. ![Invite an admin dialog](https://images.workoscdn.com/images/b9ab80fc-606a-417c-bade-3483ef48c2ae.png?auto=format&fit=clip&q=80) ### Follow the Admin Portal instructions To complete the integration, you'll have to also create an account with the identity provider you want to test with. After you have signed up with an identity provider of your choice, follow the corresponding Admin Portal instructions from the setup link. Once done, you can start testing your SSO integration with that identity provider. ![Admin Portal setup instructions](https://images.workoscdn.com/images/0ee15c3d-5356-4f41-a26a-440f95355b28.png?auto=format&fit=clip&q=80) The setup instructions you've seen in the Admin Portal are also available directly in the docs if you want to create a connection manually: --- ## Integrating via the API If you'd prefer to build and manage your own authentication UI, you can do so via the AuthKit [Authentication API](/reference/authkit/authentication). Examples of building custom UI are also [available on GitHub](https://github.com/workos/authkit). ### SSO with contractors Enforcing organization SSO access with external contractors. ## Introduction In this scenario, we outline the considerations, concepts, and best practices for configuring and enforcing SSO sign-in for all members of an organization, we'll also cover how to enforce these same constraints on external contractors who may need access to company resources but are not permanent members. ## Goals & requirements The application should be available to logged in users only. Each user is typically assigned to a single organization and will be able to collaborate with other users within that organization. - The majority of users collaborate within the same organization. - Permanent members of the organization use an email address that matches the organization's domain. - Organization members are required to authenticate using SSO. - External contractors and collaborators are also required to authenticate using SSO. ![Diagram of AnalyticsOS auth flow for users and contractors](https://images.workoscdn.com/images/b9752155-4f5d-4702-890d-c64caa54005e.png?auto=format&fit=clip&q=80)\[border=false] ## Integrating SSO Adding SSO to your application is a straightforward process when using AuthKit, and can mostly be done via the WorkOS dashboard. Steps include: (1) Add a new SSO connection to an organization in the dashboard (2) Configure a callback endpoint in your application (3) Add your endpoint URL as a redirect URI in the WorkOS dashboard (4) Handle the user session and grant access to the application ### Enforcing SSO authentication With an active SSO connection established, it's now possible to enable it as an authentication method in the WorkOS Dashboard. This can be achieved by visiting the authentication settings view for the environment and enabling Single Sign-On. ![Enable SSO in the WorkOS dashboard](https://images.workoscdn.com/images/feb25320-d75c-47bf-ae63-ae7a99a84afb.png?auto=format&fit=clip&q=80)\[border=false] This will allow users to sign-in with AuthKit using SSO, but will not enforce it as a requirement. In order to do so, we'll need to configure an authentication policy for the organization. ### SSO authentication flow When the user logs in, they will move through the following flow: (1) User clicks "Sign in" button (2) User is redirected to AuthKit, where they sign via SSO (3) User is redirected from AuthKit to the redirect URI configured for your application (4) User is authenticated via code presented in the `redirect_uri` (5) Access is provisioned by the application More in-depth information on configuration can be found in the [Single Sign-On section](/authkit/sso), with AuthKit implementation guidance available in the [Quick Start guide](/authkit). ## Understanding authentication policies An authentication policy is a way to enforce specific authentication methods during sign-in. They typically apply to all users attempting to access the organization. There are several approaches to enforcing SSO within an organization, including domain verification and enforcing specific policies on those inside and outside of the organization based on their attached email domain, but for the purposes of simplicity we will simply cover a blanket authentication policy which applies to all users attempting to sign-in, regardless of verified domain existence. An authentication policy allows the organization to: - Enforce SSO be used by all users accessing the organization - Enforce an MFA requirement for all users accessing the organization ## Adding an authentication policy Authentication policies can be applied in the organization settings view of the WorkOS Dashboard. ![Applying authentication policy in the WorkOS dashboard](https://images.workoscdn.com/images/22fc71c4-1565-45e4-a148-d96de148cdd4.png?auto=format&fit=clip&q=80)\[border=false] After adding SSO enforcement to the policy, all users will be required to sign-in using SSO. This will apply to all users, including external contractors. For this to function with external contractors, they will need to be added to the organization's IdP. For cases where external contractors can not be added to the organization's IdP, an MFA requirement can be set as an enforcement fallback. This is sometimes a reasonable compromise if many contractors rotate in out of the organization. ## Summary The organization should now be set up and to both accept SSO connections and enforce their use for all users, including external contractors. In the contractor case they will require adding to the organizations IdP or otherwise fallback to using MFA. This scenario did not cover the full range of access constraints that can be applied to an organization following domain verification, for more information on this topic see the Access Constraints section of the documentation. ### Social Login Quickly and easily integrate with social OAuth providers. ## Introduction Social Login allows users to sign in or sign up using their existing credentials with OAuth providers such as Google, Microsoft, GitHub, and Apple. ## Getting started AuthKit will make the necessary API calls and route users through OAuth providers automatically during the authentication flow, though the relevant providers must first be configured and enabled. ### (1) Configure OAuth providers Configuration can be supplied via the _Authentication_ section of the [WorkOS Dashboard](https://dashboard.workos.com). WorkOS provides integration guides for common providers such as [Google](/integrations/google-oauth), [Microsoft](/integrations/microsoft-oauth), [GitHub](/integrations/github-oauth), [Apple](/integrations/apple), [GitLab](/integrations/gitlab-oauth), [LinkedIn](/integrations/linkedin-oauth), and [Slack](/integrations/slack-oauth). ![Dashboard configure OAuth settings](https://images.workoscdn.com/images/037ede88-0b7a-4e26-9ede-441a25ce584c.png?auto=format&fit=clip&q=80) ### (2) Enable OAuth providers After a provider has been configured and enabled, it will appear as a sign in option on the AuthKit authentication page. ![AuthKit sign in page with social providers highlighted](https://images.workoscdn.com/images/f743cf4f-a32c-464b-94a4-db9f5c146773.png?auto=format&fit=clip&q=80) ## Custom OAuth scopes AuthKit offers support for custom OAuth scopes for Google, Microsoft, GitHub, GitLab, and Xero integrations. This allows you to request specific permissions when accessing user profile data from these providers. For instance, requesting access to read Google Calendar events or retrieve emails from a Microsoft account. See the relevant provider section for more information: - [Google](/integrations/google-oauth/configure-additional-oauth-scopes-optional) - [Microsoft](/integrations/microsoft-oauth/configure-additional-oauth-scopes-optional) - [GitHub](/integrations/github-oauth/configure-additional-oauth-scopes-optional) - [GitLab](/integrations/gitlab-oauth/configure-additional-oauth-scopes-optional) - [Xero](/integrations/xero-oauth/configure-additional-oauth-scopes-optional) ## Provider-driven user profile updates When a user logs in with a social provider, the user profile information may be updated. The user's profile picture and name will always be updated to match the information supplied by the social provider. If the email address at the provider has changed and the user is only linked to a single provider, the email will also be updated to match. If the new email is already in use, no change will take place. --- ## Integrating via the API If you'd prefer to build and manage your own authentication UI, you can do so via the AuthKit [Authentication API](/reference/authkit/authentication). Examples of building custom UI are also [available on GitHub](https://github.com/workos/authkit). ### Sessions Learn more about integrating sessions. ## Introduction When a user signs in to your app, a user session is created. Along with the [User object](/reference/authkit/user), a successful authentication response will include an access token and refresh token. Your application can use these tokens to ensure that the user's session is still active. Each user session can be viewed from within the WorkOS dashboard: ![Sessions Detail UI](https://images.workoscdn.com/images/295ded3e-7e8f-4322-bcc0-95db1cfc255b.png?auto=format&fit=clip&q=80) Navigate to _Users_ and select a user. Then, switch to _Sessions_ tab and click on a user session to get more information. ## Integrating Sessions Successful authentication responses will include both an access token and a refresh token. The access token should be stored as a secure cookie in the user's browser and should be validated by the backend on each request. The refresh token should either be stored in a secure cookie or persisted on your backend. Once the access token has expired, a new one can be obtained using the refresh token. ![Sessions Diagram](https://images.workoscdn.com/images/aa420ffa-3b8c-462c-992b-b53e458dd916.png?auto=format&fit=clip&q=80)\[border=false] ### Access Token If you're using our [Next SDK](https://www.npmjs.com/package/@workos-inc/authkit-nextjs) or [Remix SDK](https://github.com/workos/authkit-remix), all the work of validating access tokens and refreshing expired tokens is handled for you (more framework support coming soon). Read on for details about how token handling works. The access token is a JSON Web Token (JWT), which should be validated on each request using a library like jose. The [signing JWKS](/reference/authkit/session-tokens/jwks) can be found at `http://api.workos.com/sso/jwks/`. The JWT includes the following claims: - `sub`: the WorkOS user id - `sid`: the session ID (used for signing out) - `iss`: `https://api.workos.com/` (will be your custom auth domain if configured) - `org_id`: the organization that was selected at sign-in time (if applicable) - `role`: the role of the selected organization membership (only applicable if an organization is selected) - `permissions`: the permissions assigned to the role (if applicable) - `exp`: the standard `expires_at` claim (the token should not be trusted after this time) - `iat`: the standard `issued_at` claim ### Refresh Token Refresh tokens should be persisted on the backend in, for instance, a database, cache, or secure http-only cookie. A new access token can be obtained by using the [authenticate with refresh token](/reference/authkit/authentication/refresh-token) endpoint. If the session is still active, a new access token and refresh token will be returned. Refresh tokens may be rotated after use, so be sure to replace the old refresh token with the newly returned one. ### Switching Organizations Refresh tokens can be used to obtain a new access token for a different organization by passing the `organization_id` parameter to the [authenticate with refresh token](/reference/authkit/authentication/refresh-token) endpoint. If the session for the refresh token is authorized to access the organization, then the `org_id` will be set to the given organization, along with the `role` and `permissions` claims matching the user's membership in that organization. If the user is not authorized for the organization, then an appropriate [authentication error](/reference/authkit/authentication-errors) will be returned and the user will need to authenticate. Applications can use the [Get Authorization URL](/reference/authkit/authentication/get-authorization-url) and the `organization_id` parameter to initiate the authentication flow specifically for the organization. ### Signing Out When a user signs out of your app, the following steps should occur: - Get the session id (`sid` claim) out of the access token. - Delete the user's app session. - Redirect the user's browser to [logout endpoint](/reference/authkit/logout) endpoint (this will ensure the user's session ends at WorkOS). - The user will be redirected back to the URL configured as your _App homepage URL_ #### Example ```javascript // extract sessionId from access token const sessionId = jose.decodeJwt(session.accessToken).sid; // delete app session cookie cookies().delete('my-app-session'); // redirect to logout endpoint // (the user will be redirected to your app homepage url // after the logout completes) redirect(workos.userManagement.getLogoutUrl({ sessionId })); ``` ## Configuring Sessions Using the WorkOS dashboard you can configure how Sessions work in your integration. In the Applications page of the [WorkOS Dashboard](https://dashboard.workos.com/environment/applications), open your application. Session length, access token duration, and inactivity timeout can all be configured within the Sessions tab. ![Screenshot of the WorkOS dashboard Applications Sessions tab showing Session lifetime and Cross-Origin Resource Sharing cards.](https://images.workoscdn.com/images/dd7763cd-8359-46f6-b9db-98c43ac4f4e4.png?auto=format&fit=clip&q=80) - Maximum session length: The session will expire after this length of time. Once expired the user will need to sign in again. - Access token duration: Your backend can verify the access token on each request (see the [Integrating Sessions](#integrating-sessions) section above). It's recommended to keep the access token duration short so that changes in the session are quickly reflected in your app. - Inactivity timeout: The session ends if a refresh has not occurred in this length of time. The user will need to sign in again. Additionally, make sure to review your settings in the _Redirect_ section: ### Sign-out redirect Make sure to set a default Sign-out redirect, which will be the location users will be redirected to after their session has been ended. Non-default Sign-out redirects can be used as values to the `return_to` parameter of the [Logout API](/reference/authkit/logout/get-logout-url) in order to dynamically choose the final logout redirect location. #### Wildcards WorkOS supports using wildcard characters (`*`) in sign-out redirects to handle dynamic subdomains or variable ports during development. ##### Subdomains The `*` symbol can be used as a wildcard for subdomains; however, it must be used in accordance with the following rules: - The protocol of the URL **must not** be `http:` in production environments. - The wildcard **must** be located in the subdomain furthest from the root domain (e.g., `https://*.sub.example.com` will work, but `https://sub.*.example.com` will not). - The URL **must not** contain more than one wildcard. - A wildcard character **may** be prefixed and/or suffixed (e.g., `https://prefix-*-suffix.example.com`). - A wildcard **will not** match across multiple subdomain levels (e.g., `https://*.example.com` will not match `https://sub1.sub2.example.com`). - Wildcards cannot be used with [public suffix domains](https://publicsuffix.org) (e.g., `https://*.ngrok-free.app` will not work). - The wildcard will match letters, digits, hyphens, and underscores. - A URL with a wildcard cannot be set as the default sign-out redirect. ##### Ports To support [RFC 8252](https://datatracker.ietf.org/doc/html/rfc8252#section-7.3) ("OAuth 2.0 for Native Apps") and local development, a wildcard may be used in place of the port number. - This is strictly limited to `localhost` and loopback IP addresses (e.g., `127.0.0.1`). - Example: `http://localhost:*/signed-out` is valid. ### Roles and Permissions Manage and assign roles and permissions to users. ## Introduction A role represents a logical grouping of permissions, defining access control levels for users within your application. Roles are identified by unique, immutable slugs and are assigned to users through [organization memberships](/authkit/users-organizations/organizations). Permissions grant users privileged access to resources and actions in your application and are referenced in your code by unique, immutable slugs. A permission can be assigned to any number of roles. ### Standalone roles Roles alone can be sufficient when your application only requires very coarse-grained access control. This is suitable if users only need to be separated into broad categories and there is minimal overlap between roles. Simple roles can be easier to manage, but are less flexible for complex access control scenarios. ### Utilizing permissions with roles Permissions allow for more detailed and flexible management of access. They are particularly useful when: - You anticipate the need to frequently modify access rights or introduce new roles. - There is significant overlap in access rights between different roles, but with some variations. - You want to minimize code changes when modifying access rights. By abstracting access control checks to permissions, you can add or modify roles and their access rights without changing the application code. ## Configure roles and permissions Roles and permissions are managed in their own section of the [WorkOS Dashboard](https://dashboard.workos.com/environment/authorization/) or using the [authorization APIs](/reference/roles). ![Roles section WorkOS Dashboard](https://images.workoscdn.com/images/09c8fb23-5748-4236-914e-79849ac03a9a.png?auto=format&fit=clip&q=50) ### Create permissions When configuring permissions, we recommend: - Defining a common naming scheme to use across all permissions for your application. Consider separating the resource and action with a delimiter, such as `users:view`. The following delimiters are permitted: `-.:_*`. - Keep permission slugs clear and concise. When assigned to roles, these slugs will be included in session cookies in the [session JWT claims](/authkit/sessions/integrating-sessions/access-token), which is limited to a maximum size of 4KB in many modern web browsers. ### Assign permissions to roles Permissions can be assigned when creating a new role or when editing an existing role. ![Assign permissions to a role](https://images.workoscdn.com/images/f6fd6d9a-a7b0-4df7-908b-b657e669a3dc.png?auto=format&fit=clip&q=50) ### Default role Role configuration occurs at the environment level. Each environment is seeded with a default `member` role, which is automatically assigned to every organization member. This default role cannot be deleted, but any role can be set as the default. If you need to set default roles or other role configurations at the organization level, refer to the [Custom roles](/rbac/custom-roles) section. ### Assign roles By default, organization memberships require exactly one role. Every user with an organization membership is automatically assigned the default role when added to an organization. This role can be edited. When [multiple roles is enabled](/authkit/roles-and-permissions/multiple-roles), you can assign several roles to an organization membership. The user gets all permissions from each role. You can retrieve the role information from the user's [organization membership object](/reference/authkit/organization-membership) to determine their access level and capabilities within your application. Role changes are tracked and logged via the [`organization_membership.updated` event](/events/organization-membership). To view these changes, go to the [events page](https://dashboard.workos.com/environment/events) and filter by `organization_membership.updated`. ### Delete roles When roles are deleted: - **Single role mode**: All organization memberships with the deleted role are reassigned to the default role. - **Multiple roles mode**: The deleted role is removed from all organization memberships that have it assigned, while other roles on the organization membership remain intact. If the deleted role was the only role assigned to the membership, it will be reassigned the default role. Role deletion happens asynchronously, so there may be a slight delay between deleting a role and updating all affected organization memberships. > To migrate from one default role to another, set the new default role and delete the old one. All users will then be reassigned to the new default role. ### Priority order If a user is provisioned from multiple sources with conflicting roles, the role with the highest priority will be assigned. This is applicable for a single role architecture utilizing [role assignment](/authkit/roles-and-permissions/role-assignment). Priority order also determines which role will be assigned to users when migrating from a multiple roles to single role configuration in the environment. ## Multiple roles When [enabled](/rbac/configuration/configure-roles/multiple-roles), AuthKit supports multiple roles per organization membership. A user receives the **union of permissions** across all assigned roles. For example, a user with the _Designer_ and _Engineer_ roles gets both sets of permissions in their session. This prevents role explosion by avoiding redundant hybrid roles, like "designer-engineer". Each organization membership must have **at least one** role, they will always receive the default role if no other role(s) are set. ### Use cases By default, multiple roles is disabled and users can only have a single role per entity. You might want to enable multiple roles when you need: - **Cross-department collaboration**: e.g., designers who need some engineering permissions. - **Additive, disjoint permissions**: independent permission sets that should stack. - **Temporary access**: grant time-bound extra capabilities without creating hybrid roles. For most apps, start with **single-role relationships** for simplicity and predictability, and adopt multiple roles only when overlapping permission sets become common. | Mode | Access calculation | Pros | Considerations | | -------------- | ------------------------------------------ | -------------------------------------------- | --------------------------------------------------- | | Single role | One role's permissions per membership | Simple model; predictable audits; small JWTs | May require hybrid roles for cross-functional users | | Multiple roles | Union of permissions across assigned roles | Flexible; avoids role sprawl | Larger JWTs; more governance | ### Manually assign roles to a user Roles can be assigned manually following the steps below, or via identity provider roles assignment outlined in the next section. 1. From the WorkOS Dashboard, open [Users](https://dashboard.workos.com/environment/users). 2. Select a user and go to **Organization memberships** 3. Click **Edit roles** and add all relevant roles 4. Or assign roles [via the API](/reference/authkit/organization-membership/update) Each organization membership must have **at least one** role. ## Role assignment You can map identity provider groups to roles to automatically assign roles to users. AuthKit supports two methods for role assignment: ### SCIM (Directory Sync) Roles can be assigned via SCIM through [directory group role assignment](/directory-sync/identity-provider-role-assignment/directory-group-role-assignment). Admins can map group memberships to roles in the Admin Portal during SCIM or Google Workspace directory setup. These mappings are used to assign roles to organization memberships via [Directory Provisioning](/authkit/directory-provisioning). ### SSO Roles can also be assigned via [SSO group role assignment](/sso/identity-provider-role-assignment/sso-group-role-assignment). Groups returned in the SSO profile can be mapped to roles in the WorkOS Dashboard. If an AuthKit user authenticates via SSO and belongs to a mapped group, the corresponding role will be set on the [organization membership](/reference/authkit/organization-membership) and reflected in the [user's session](/authkit/sessions/integrating-sessions/access-token). > Ensure [SSO JIT provisioning](/authkit/jit-provisioning/sso-jit-provisioning) is enabled for each organization using SSO role assignment. ### Groups Roles can also be assigned through [group role assignments](/authkit/group-role-assignments). Unlike identity provider role assignment, groups are native to WorkOS and managed by your application through the API. Assigning a role to a [group](/authkit/groups) grants that role to every member of the group. When members are added or removed, their roles update accordingly. ### Enabling in Admin Portal IT contacts can assign roles to identity provider groups in the [Admin Portal](/admin-portal) during SSO or directory setup. From the _Authorization_ section in the WorkOS Dashboard, role assignment is an environment-level setting. However, it can also be configured per organization via the _Roles_ tab on that organization's page. If enabled, all Admin Portal sessions for the relevant SSO connection or directory will support group role assignment. ![Enable directory group role assignment dashboard setting](https://images.workoscdn.com/images/fe19e3ac-6370-404e-9590-cdb06b3de127.png?auto=format&fit=clip&q=50) Whether to enable role assignment for SSO or directory groups depends on your application's setup. When [provisioning users with Directory Sync](/authkit/directory-provisioning), we recommend enabling directory group role assignment due to [limitations of SSO role assignment](/sso/identity-provider-role-assignment/considerations/drawbacks). If you're not yet using directory provisioning, you can enable SSO group role assignment as the environment default. Because this setting is configurable per organization, choose a sensible default based on your customers' typical setup: - **A. All organizations use SSO:** If no organizations are using Directory Sync, enable SSO group role assignment in Admin Portal at the environment level. - **B. Some organizations use Directory Sync:** Enable directory group role assignment in Admin Portal for those specific organizations. - **C. Most organizations use Directory Sync:** Enable directory group role assignment in Admin Portal at the environment level, and override the setting for organizations that only use SSO. ### Migrating role assignment source It's recommended to use only one role assignment source per organization. If your organization currently uses SSO group role assignment and you'd like to switch to [directory group role assignment](/directory-sync/identity-provider-role-assignment/directory-group-role-assignment), consider the following paths: - **A. Directory is not yet configured:** [Enable directory group role assignment](/authkit/roles-and-permissions/role-assignment/enabling-in-admin-portal) for this organization via the **Roles** tab under an organization in the WorkOS Dashboard. IT contacts will be prompted to set up directory group role assignments in the Admin Portal. - **B. Directory is already configured:** Manually assign roles to directory groups in the WorkOS Dashboard, or regenerate an Admin Portal link so IT contacts can set the role mappings there. Directory group role assignments take precedence and will override any SSO group role assignments on the organization membership. Once directory group roles are properly set up and reflected, you can delete the SSO group mappings. ### Role source priority AuthKit enforces strict priority rules for assigning roles. When roles are sourced from SSO group role assignment: - An explicit SSO group role assignment **overrides** any role manually assigned via the [organization memberships API](/reference/authkit/organization-membership) or the [WorkOS Dashboard](https://dashboard.workos.com/). However, a default SSO group role assignment **does not override** a manual one. - The system may allow a temporary override through the [organization memberships API](/reference/authkit/organization-membership), but it **reapplies** the SSO-assigned role when the user next authenticates, provided the assignment came from an explicit SSO group. - The system **always overwrites** previous SSO role assignments with new ones, whether they originate from an explicit or default mapping. Role assignments sourced from [Directory Provisioning](/authkit/directory-provisioning): - An explicit directory group role assignment **overrides** any role manually assigned via the [organization memberships API](/reference/authkit/organization-membership) or the [WorkOS Dashboard](https://dashboard.workos.com/), or any SSO group role assignment. - The system **does not allow** SSO to override these roles. - You **can override** these roles temporarily via the [organization memberships API](/reference/authkit/organization-membership), but directory provisioning reapplies them during the next sync. - The system **always replaces** previous directory provisioned role assignments with new ones, regardless of whether they came from an explicit or default mapping. ## Role-aware sessions When a user signs into your app, a [user session](/authkit/sessions) is initiated. The authentication response includes an access token, a JSON Web Token (JWT), with role claims indicating the user organization membership's role(s) for that session. ## Custom roles Custom roles are roles scoped to a particular organization. They are managed via the "Roles" tab under an organization in the WorkOS Dashboard or using the [Custom Roles API](/reference/roles/custom-role). ![Roles tab for organization](https://images.workoscdn.com/images/7faa176d-bfb9-405b-bb24-700201566ac6.png?auto=format&fit=clip&q=50) ### Why might I use custom roles? In some cases, an application's fixed set of roles may not meet the needs of certain organizations. For example, an organization may require a lesser privileged set of permissions for their members. Custom roles allow you to create roles with the organization's desired set of permissions, without affecting access control for other organizations. ### Creating custom roles By default, organizations have no custom roles and simply inherit the environment-level roles. You can create a custom role by clicking the "Create role" button on the organization's "Roles" tab or using the [Custom Roles API](/reference/roles/custom-role/create). All custom role slugs are automatically prefixed with `org`. ![Create a custom role](https://images.workoscdn.com/images/fde65b6a-3a74-44bb-afc3-364e8a2041f1.png?auto=format&fit=clip&q=50) ### Custom role configuration Once you create the first role for an organization, that organization will have its own [default role](/authkit/roles-and-permissions/configure-roles-and-permissions/default-role) and [priority order](/authkit/roles-and-permissions/configure-roles-and-permissions/priority-order), independent from the environment. New roles added to the environment will be available to the organization and placed at the bottom of the organization's role priority order. ### Using custom roles Like environment-level roles, custom roles can be used in [role assignment](/authkit/roles-and-permissions/role-assignment), [sessions](/authkit/roles-and-permissions/role-aware-sessions), and the [organization membership API](/reference/authkit/organization-membership). No additional action is required to enable this behavior after creating custom roles. ### Deleting an environment role When attempting to delete an environment role that's the default role for one or more organizations, you'll be prompted to select a new default role for all affected organizations. Organization members previously assigned the deleted role will be assigned the new organization default role. ![Select a replacement role](https://images.workoscdn.com/images/5e6f3e51-5de5-4bb1-a850-52b2196282b9.png?auto=format&fit=clip&q=50) ### AuthKit Easy to use authentication platform designed to provide a flexible, secure, and fast integration. ## Introduction Integrating AuthKit into your app can be done in less than ten minutes. In this guide, we'll walk you through adding a hosted authentication flow to your application using AuthKit. In addition to this guide, there are a variety of [example apps](/authkit/example-apps) available to help with your integration. ## Before getting started To get the most out of this guide, you'll need: - A [WorkOS account](https://dashboard.workos.com/) - Your WorkOS [API Key](/glossary/api-key) and [Client ID](/glossary/client-id) --- ## (1) Configure your project Let's add the necessary dependencies and configuration in your WorkOS Dashboard. ### Install dependencies To use AuthKit with a Remix application, use the `authkit-remix` library. Start by installing it in your Remix project via `npm`. ```bash title="Install Remix SDK" npm install @workos-inc/authkit-remix ``` ### Configure a redirect URI A redirect URI is a callback endpoint that WorkOS will redirect to after a user has authenticated. This endpoint will exchange the authorization code returned by WorkOS for an authenticated [User object](/reference/authkit/user). We'll create this endpoint in the next step. You can set a redirect URI in the **Redirects** section of the [WorkOS Dashboard](https://dashboard.workos.com). We recommend using `http://localhost:3000/callback` as the default here. WorkOS supports using wildcard characters in Redirect URIs, but not for the default Redirect URI. More information about wildcard characters support can be found in the [Redirect URIs](/sso/redirect-uris/wildcard-characters) guide. ![Dashboard redirect URI](https://images.workoscdn.com/images/a7525cf3-ae4e-4dcd-91dd-27965b005472.png?auto=format&fit=clip&q=80) When users sign out of their application, they will be redirected to your app's [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) location which is configured in the same dashboard area. ### Configure sign-in endpoint Sign-in requests should originate from your application. In some instances, requests may not begin at your app. For example, some users might bookmark the hosted sign-in page or they might be led directly to the hosted sign-in page when clicking on a password reset link in an email. In these cases, AuthKit will detect when a sign-in request did not originate at your application and redirect to your application's sign-in endpoint. This is an endpoint that you define at your application that redirects users to sign in using AuthKit. We'll create this endpoint in the next step. You can configure the sign-in endpoint from the **Redirects** section of the WorkOS dashboard. ![Sign-in endpoint](https://images.workoscdn.com/images/25b53ea7-95ba-48cc-b6e7-ccd1b1bc35eb.png?auto=format&fit=clip&q=80) ### Set secrets To make calls to WorkOS, provide the API key and the client ID. Store these values as managed secrets and pass them to the SDKs either as environment variables or directly in your app's configuration depending on your preferences. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' WORKOS_REDIRECT_URI="http://localhost:3000/callback" # configured in the WorkOS dashboard WORKOS_COOKIE_PASSWORD="" # generate a secure password here ``` The SDK requires you to set a strong password to encrypt cookies. This password must be at least 32 characters long. You can generate a secure password by using the [1Password generator](https://1password.com/password-generator/) or the `openssl` library via the command line: ```bash title="Generate a strong password" openssl rand -base64 32 ``` > The code examples use your staging API keys when [signed in](https://dashboard.workos.com) --- ## (2) Add AuthKit to your app Let's integrate the hosted authentication flow into your app. ### Callback route When a user has authenticated via AuthKit, they will be redirected to your app's callback route. In your Remix app, [create a new route](https://remix.run/docs/en/main/discussion/routes) and add the following: ### Sign-in endpoint We'll need a sign-in endpoint to direct users to sign in using AuthKit before redirecting them back to your application. We'll do this by generating an AuthKit authorization URL server side and redirecting the user to it. ### Access authentication data in your Remix application We'll need to direct users to sign in (or sign up) using AuthKit before redirecting them back to your application. We'll do this by generating an AuthKit authorization URL server side and redirecting the user to it. Use `authkitLoader` to configure AuthKit for your Remix application routes. You can choose to return custom data from your loader, like for instance the sign in and sign out URLs. ### Protected routes For routes where a signed in user is mandatory, you can use the `ensureSignedIn` option in your loader. ### Ending the session Finally, ensure the user can end their session by redirecting them to the logout URL. After successfully signing out, the user will be redirected to your app's [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) location, which is configured in the WorkOS dashboard. > If you haven't configured a [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) in the WorkOS dashboard, users will see an error when logging out. ## Validate the authentication flow To test all of this out, call `npm run dev`, navigate to `localhost:3000`, and sign up for an account. You can then sign in with the newly created credentials and see the user listed in the **Users** section of the [WorkOS Dashboard](https://dashboard.workos.com). ![Dashboard showing newly created user](https://images.workoscdn.com/images/54fa6e6c-4c6f-4959-9301-344aeb4eeac8.png?auto=format&fit=clip&q=80) ### Reauthentication Require a fresh sign-in for sensitive actions. ## Introduction Re-authentication requires a user to actively sign in again to prove they authenticated recently, even when they already have a valid session. This is sometimes called step-up authentication, and it's useful before sensitive operations: changing security settings, irreversible deletes, or confirming a high-value action. AuthKit implements this with two standard fields: the `auth_time` claim, which records when the user last authenticated, and the `max_age` parameter ([RFC-9470](https://datatracker.ietf.org/doc/html/rfc9470#section-3-5.4)), which indicates the allowed elapsed time since last authentication. ## (1) Read the `auth_time` claim Every AuthKit access token includes an `auth_time` claim: a Unix timestamp, in seconds, of the user's most recent active authentication. It advances only from an active authentication, not from a refresh. Read it from the JWT and compare it against your freshness requirement. ```json { "sub": "user_01EH...", "sid": "session_01HQ...", "auth_time": 1735680000, "iat": 1735683600, "exp": 1735684500 } ``` ## (2) Prompt the user to re-authenticate When the session isn't fresh enough, let the user know they need to sign in again to continue with the action. ## (3) Redirect to AuthKit with `max_age` Send the user back through AuthKit, adding the `max_age` parameter to the [authorization URL](/reference/authkit/authentication/get-authorization-url). ```ts const authorizationUrl = workos.userManagement.getAuthorizationUrl({ provider: 'authkit', clientId: process.env.WORKOS_CLIENT_ID!, redirectUri: process.env.WORKOS_REDIRECT_URI!, maxAge: 300, }); ``` Set `maxAge` to `0` to always force a fresh sign-in — useful when you've already confirmed the user's intent in your own UI. AuthKit selects the re-authentication method for you based on the factors the user has, prompting for a password or MFA factor, or sending SSO users back through their identity provider. When the user returns from AuthKit, their new access token carries an updated `auth_time`. ## Best practices - **Avoid very short `max_age` values.** A `max_age` under 60 seconds forces users to re-authenticate almost immediately and is likely to frustrate them. - **Return the user to where they left off.** Re-authentication redirects the user out of your app, so preserve the original location and any in-progress action with the [`state`](/reference/authkit/authentication/get-authorization-url) parameter. AuthKit returns the exact value on the callback, letting you restore context so the user can continue with their high-value action. ### AuthKit Easy to use authentication platform designed to provide a flexible, secure, and fast integration. ## Introduction Integrating AuthKit into your app can be done in less than ten minutes. In this guide, we'll walk you through adding a hosted authentication flow to your application using AuthKit. In addition to this guide, there are a variety of [example apps](/authkit/example-apps) available to help with your integration. ## Before getting started To get the most out of this guide, you'll need: - A [WorkOS account](https://dashboard.workos.com/) - Your WorkOS [API Key](/glossary/api-key) and [Client ID](/glossary/client-id) --- ## (1) Configure your project Let's add the necessary dependencies and configuration in your WorkOS Dashboard. ### Install dependencies For a client-only approach, use the `authkit-react` library to integrate AuthKit directly into your React application. Start by installing the library to your project via `npm`. ```bash title="Install React SDK" npm install @workos-inc/authkit-react ``` ### Configure a redirect URI A redirect URI is a callback endpoint that WorkOS will redirect to after a user has authenticated. This endpoint will exchange the authorization code returned by WorkOS for an authenticated [User object](/reference/authkit/user). We'll create this endpoint in the next step. You can set a redirect URI in the **Redirects** section of the [WorkOS Dashboard](https://dashboard.workos.com). We recommend using `http://localhost:3000/callback` as the default here. WorkOS supports using wildcard characters in Redirect URIs, but not for the default Redirect URI. More information about wildcard characters support can be found in the [Redirect URIs](/sso/redirect-uris/wildcard-characters) guide. ![Dashboard Redirect URIs](https://images.workoscdn.com/images/a7525cf3-ae4e-4dcd-91dd-27965b005472.png?auto=format&fit=clip&q=80) > For the client-only integration, make sure to set the callback URI as the same route where you require auth. When users sign out of their application, they will be redirected to your app's [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) location which is configured in the same dashboard area. ### Configure sign-in endpoint All sign-in requests must originate at your application for the [PKCE](/reference/authkit/authentication/get-authorization-url/pkce) code exchange to work properly. In some instances, requests may not begin at your app. For example, some users might bookmark the hosted sign-in page or they might be led directly to the hosted sign-in page when clicking on a password reset link in an email. In these cases, AuthKit will detect when a sign-in request did not originate at your application and redirect to your application's sign-in endpoint. This is an endpoint that you define at your application that redirects users to sign in using AuthKit. We'll create this endpoint in the next step. You can configure the sign-in endpoint from the **Redirects** section of the WorkOS dashboard. ![Sign-in endpoint](https://images.workoscdn.com/images/25b53ea7-95ba-48cc-b6e7-ccd1b1bc35eb.png?auto=format&fit=clip&q=80) ### Configure CORS Since your user's browser will be making calls to the WorkOS API directly, it is necessary to add your domain to the allow list in your WorkOS Settings. This can be configured in the **Configure CORS** dialog on the **Authentication** page of the WorkOS dashboard. ![Screenshot of the WorkOS dashboard showing the "Configure CORS" option in the "Authentication" section.](https://images.workoscdn.com/images/3b7863df-8c59-4d48-ab91-f537fd5c9f66.png?auto=format&fit=clip&q=50) While building your integration in the Staging environment you should add your local development URL here. In the example below we're adding `http://localhost:5173` to the list of allowed web origins. ![Screenshot of the WorkOS dashboard showing the CORS configuration panel.](https://images.workoscdn.com/images/e20fdbfb-965f-47b5-9c64-b83f6e6b8a39.png?auto=format&fit=clip&q=50) > The code examples use your staging API keys when [signed in](https://dashboard.workos.com) --- ## (2) Add AuthKit to your app Let's integrate the hosted authentication flow into your app. ### Wrap your app with the AuthKit provider The `AuthKitProvider` component will handle the redirect from Hosted AuthKit, refresh the session when needed and provide context for hooks used in the components of your app. Initialize it with your client ID, which you can find in the WorkOS dashboard. You should also specify your custom authentication API domain. > If you have not set up a custom authentication domain in WorkOS, set `devMode={true}` on ``. This will keep the refresh token in local storage instead of a secure, HTTP-only cookie. > For security reasons, the client-only integration cannot be nested inside an `iframe`. ### Use the auth hook in your components The `useAuth` hook will return user information and loading status. It also provides functions to retrieve the access token and sign in and sign out the user. ### Protect routes with custom hooks If you have routes that you wish to only be accessible to logged in users, you can use a custom React hook. Then use that hook to protect your mandatory sign in routes. > If you haven't configured a [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) in the WorkOS dashboard, users will see an error when logging out. ## Validate the authentication flow You can then sign in with the newly created credentials and see the user listed in the **Users** section of the [WorkOS Dashboard](https://dashboard.workos.com). ![Dashboard showing newly created user](https://images.workoscdn.com/images/54fa6e6c-4c6f-4959-9301-344aeb4eeac8.png?auto=format&fit=clip&q=80) ### Radar Protecting against bots, fraud and abuse. ## Introduction Radar adds automated protections on top of AuthKit by collecting signals on the behavior of users as they sign in to your app. These signals feed into an engine that identifies abusive or anomalous behavior. When Radar detects a suspicious authentication attempt, it can block or challenge that attempt based on the settings you configure. Radar leverages device fingerprinting to identify which client is being used to authenticate with AuthKit. This enables Radar to differentiate between legitimate and malicious users, so that automated protections won't impact your app's availability during an attack. It's also a signal for suspicious behavior, such as when a device is used for multiple accounts or multiple devices are using the same account. ## Getting Started Radar works with AuthKit without additional integration effort. You can enable Radar directly from the WorkOS dashboard. If you are interested in using Radar but are not an AuthKit customer, please reach out to [our team](mailto:support@workos.com), or for current customers, drop a note in your shared Slack channel. ## Dashboard Radar's dashboard provides a summary of authentication activity in your app. The top chart shows counts of suspicious events that Radar is detecting, along with automated actions that Radar took based on configuration. The counts are updated in real time to make it easy to spot spikes in anomalous behavior. To see historical trends, the time range for the chart can be toggled between 24 hours, 7 days and 30 days. ![Radar dashboard](https://images.workoscdn.com/images/87812b47-e72f-4edb-8164-e171545c9d8d.png?auto=format&fit=clip&q=50) Below the top chart is a set of cards that show Radar detection activity for different user identifiers. This is helpful to understand which types of devices, locations, users, etc. have been detected most often by Radar. Each card is linked to the events page to drill into a list of individual event activity. ![Radar identifier cards](https://images.workoscdn.com/images/a2239641-2ef4-4742-bf9c-97189069ddaa.png?auto=format&fit=clip&q=50) ## Event list A complete list of Radar events appears under the "Events" tab. This list can be filtered by detection type, action taken, or a specific user ID or email. By clicking into a single event, you can view all of the metadata related to that action including device, location, user agent and IP address. Reviewing events in Radar can help inform when custom restrictions may be useful, such as allowing a known legitimate user to bypass detections, or blocking an IP range that is abusing your sign-in. ![Radar events](https://images.workoscdn.com/images/bde4e906-d680-4f18-baa5-d33fac803a7d.png?auto=format&fit=clip&q=50) ## Configuration Radar gives you full control over the automated actions that are taken to suppress suspicious activity. Depending on the detection, you can configure Radar to block, challenge, or notify on an authentication attempt that exhibits suspicious behavior. **Blocking** an attempt will cause the authentication to fail, even if valid credentials are provided. The user will see a message indicating their sign-in was not successful, and can reach out to an administrator for more detail. **Challenging** an attempt will send the user an email with a one-time passcode (OTP). The user is then prompted to enter that code to continue authentication. Challenging suspicious authentication attempts with an OTP is effective in stopping bots that are capable of solving CAPTCHAs, as well as malicious users who have stolen credentials but don't have access to the user's email account. Radar also supports [SMS challenges](#sms-challenges) for sign up attempts, where suspicious sign ups are verified with a phone number instead of email. **Notifying** on an attempt will send an informational email to users and/or admins when Radar detects a suspicious behavior. This is helpful to proactively make individuals aware that an attack might be taking place, or their account was compromised. ![Radar configuration](https://images.workoscdn.com/images/f9f112c8-e731-4b8a-9e83-7bcea4527ac9.png?auto=format&fit=clip&q=50) Out of the box, Radar ships with the following detections: ### Bot detection Automatically block or challenge sign-in attempts that are initiated by a bot or program. When enabled, Radar will determine the appropriate action without additional configuration. In addition to detecting that the client is a bot, Radar can differentiate between different types of bots such as AI agents or search engine crawlers. ![Radar bot configuration](https://images.workoscdn.com/images/5748359e-3d07-44ae-bef1-a9ebd55a817f.png?auto=format&fit=clip&q=50) ### Brute force Block or challenge sign-in attempts that are part of an attempt to break into accounts using brute force. These are attacks where a bad actor is trying many sign-ins over a short period of time. Radar leverages the device fingerprint to identify and isolate bad actors from legitimate traffic, ensuring that your users can use your app even when it's under attack. ![Radar brute force configuration](https://images.workoscdn.com/images/28988276-a698-4517-8d9b-48e75d4e1b2b.png?auto=format&fit=clip&q=50) ### Impossible travel Block or challenge sign-in attempts that occur from different geolocations in short succession. By tracking device geolocation, Radar can detect when subsequent authentication requests are spread around the globe. Radar will detect if these attempts happen over a short period where it's not possible for the person to physically travel that distance ![Radar impossible travel configuration](https://images.workoscdn.com/images/458b59af-a3e8-4646-b8a2-1bc04ae27e8e.png?auto=format&fit=clip&q=50) ### Repeat sign up Block or challenge repeat sign up attempts from the same email. By default, AuthKit fully deletes users. If your application allows for account deletion and has a free-trial, then users may be able to delete their account and sign up again to get a new free-trial. This protection restricts an email to a max of three uses before denying further sign ups. ![Radar Repeat Sign Up protection modal](https://images.workoscdn.com/images/3e4a6937-c891-4076-b2bf-a2ed829c8004.png?auto=format&fit=clip&q=50) ### Stale accounts Get notified when an account that has been dormant without use becomes active In contexts such as financial services, a dormant account becoming active might be an indication that the account has been taken over from the user and is being used for fraud. For these kinds of apps, Radar can notify the user and administrator if an account that hasn't been used in a while has a sign-in attempt. Accounts are considered stale if there have been no successful sign-in in the past 60 days. ![Radar stale account configuration](https://images.workoscdn.com/images/f7a1a8e9-61ba-4c54-9cdb-d54ae7890092.png?auto=format&fit=clip&q=50) ### Unrecognized device Get notified when a device that has never been used before signs in to an account Using the device fingerprint, Radar checks if the device being used has been part of a successful sign-in before. If it hasn't, both the user and an administrator can be notified by email. ![Radar unrecognized device configuration](https://images.workoscdn.com/images/f574e3d9-feed-43bc-aadb-2790cbfd2ce0.png?auto=format&fit=clip&q=50) ### Domain protections Block or challenge authentication attempts from email addresses on suspicious domains. When enabled, Radar automatically identifies and takes action on authentication attempts that use email addresses from disposable, throwaway, or known fraudulent email providers. This consolidates domain-based protections into a single setting, making it easy to guard against abuse from temporary or suspicious email services without needing to manage individual domain lists. Domain protections can be enabled or disabled from the Protections section of the [Radar configuration page](https://dashboard.workos.com/environment/radar/configuration) in the WorkOS Dashboard. ![Radar domain protections configuration](https://images.workoscdn.com/images/2f6ddec4-eee8-477b-a3b6-84184e5df7f6.png?auto=format&fit=clip&q=50) ## SMS challenges SMS challenges add a layer of verification that is effective against bots and fraudulent sign ups, since a valid phone number is required to complete the challenge. When enabled, Radar uses signals such as email domain reputation and geographic mismatches between IP address and phone number to determine when to trigger an SMS challenge. SMS challenges apply to sign up attempts only — sign in attempts continue to use email challenges. SMS usage is billed at cost — WorkOS does not up-charge. The cost per message varies by destination country. SMS charges will appear on your next invoice as a separate line item. You can enable SMS challenges from the Policies section of the [Radar configuration page](https://dashboard.workos.com/environment/radar/configuration) in the WorkOS Dashboard. ## Managed lists ### Disposable email domains Radar maintains a constantly updated list of email domains known to provide disposable email services. Disposable email services may be used to bypass free account or free trial limits in your application. You can choose to block or log registrations that match an email domain in this list. Logging is useful to verify no adverse impact will occur before blocking all the domains. ![Radar Disposable Email List Protection](https://images.workoscdn.com/images/33d5c007-a5c3-4451-8da2-745bb4096268.png?auto=format&fit=clip&q=50) ### U.S. Sanctioned countries Block users from countries under US Sanctions from signing up or logging into your application. Contact [support](mailto:support@workos.com) to get the current list of countries. > If you need to block a different set of countries, please reach out to support via [email](mailto:support@workos.com) or slack to configure regional blocks. > Radar supports any region in the [ISO 3166-1 specification](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes). ![Radar US sanctions country managed lists](https://images.workoscdn.com/images/a2cff432-daf6-4c8f-a192-f33071afacf5.png?auto=format&fit=clip&q=50) ## Custom restrictions Specific user identifiers can be configured to always allow or deny an authentication attempt. Examples of using a custom restrictions: - Restricting sign-ins to a corporate IP range - Allow a script with a specific user agent to bypass bot detection - Banning specific devices (i.e. iPods) from using your app - Allowing certain users to bypass detections that are false positives > Note: the allow list takes preference -- if an user matches an identifier that is in the allow list, they will bypass all other Radar rules. ![Radar restrictions configuration](https://images.workoscdn.com/images/bda02327-1d15-4e9c-b559-08b101930880.png?auto=format&fit=clip&q=50) ### Email aliases When blocking or allowing an email address, Radar treats email aliases (the `+` suffix, e.g. `user+test@gmail.com`) as follows: - **Blocking or allowing a specific alias** (e.g. `user+test@gmail.com`) only affects that exact alias. Other aliases like `user+other@gmail.com` and the root address `user@gmail.com` are not affected. - **Blocking or allowing the root address** (e.g. `user@gmail.com`) will match all aliases of that address during sign up attempts. For example, blocking `user@gmail.com` will also block sign ups from `user+test@gmail.com`, `user+other@gmail.com`, and so on. > Note: For Gmail addresses, Radar also normalizes dots in the local part (e.g. `u.s.e.r@gmail.com` is treated the same as `user@gmail.com`) and treats `googlemail.com` as equivalent to `gmail.com` during sign up matching. ### Projects Group related environments under a project, and learn when to use projects, environments, and applications. ## Introduction A project is a dashboard-level grouping of environments. Every WorkOS team is organized as a hierarchy: ```txt Team └─ Project └─ Environment (staging / production) └─ Application (web / desktop / mobile) ``` Every team starts with a single project that contains a staging and a [production environment](/authkit/environments). Projects let you keep more than one of these setups under a single WorkOS team, each with its own environments and project-level configuration. ![Project picker open in the dashboard](https://images.workoscdn.com/images/4e4a51c3-4f09-44ae-b984-c6c4c3f3b028.png?auto=format&fit=clip&q=50) ## When to use a project Create a separate project when you need a fully isolated setup that still lives under one WorkOS team. Common reasons include: - **Distinct products or business units**, each with their own staging and production environments. - **Separate feature flags and other project-level configuration** that shouldn't be shared across products. If you only need to isolate configuration between development and staging, add an [environment](/authkit/environments) to your existing project instead of creating a new project. And if you need to support several client surfaces (such as a web app and a mobile app) that share the same users, use [applications](/authkit/applications) within a single environment. ## Projects vs. environments vs. applications These three concepts solve different problems. Each row below describes one of them. | Concept | What it is | Use it when | User base | | ----------- | ----------------------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------ | | Project | A grouping of the environments that belong to one product | You manage more than one product under a single team | Inherited from each environment; projects only group them | | Environment | An isolated instance of your product, such as staging or production | You need to build and test without affecting real users | Isolated from every other environment | | Application | A single client of your product (web, mobile, or desktop) within an environment | You have multiple clients that should share one set of users | Shared with the other applications in the environment | When deciding which to reach for: - Need separate sign-in surfaces that share one user base? Use [applications](/authkit/applications). - Need somewhere isolated to develop and test before going live? Add an [environment](/authkit/environments). - Need a fully separate setup — its own configuration and staging and production environments — under one team? Create a project. ## Project-level configuration Most configuration is scoped to a single environment and doesn't carry over between environments. API keys, organizations, connections, users, and webhook endpoints all belong to one environment. A handful of settings are instead shared across every environment in a project: - [Feature flags](/feature-flags) - [Audit Logs schema](/audit-logs/metadata-schema) - [Custom email domains](/custom-domains/email) Because these settings live at the project level, they affect whether an environment can be transferred. An environment can't be moved out of a project that has any of this configuration until WorkOS supports copying it to the new project. See [transfer environments from another project](#transfer-environments-from-another-project). Branding is configured per environment, so each environment can have its own logo, colors, and theme. To avoid setting up branding from scratch in a new environment, you can [copy it from another environment](/authkit/branding). ## Creating a project Create a project from the [WorkOS Dashboard](https://dashboard.workos.com/). Give it a name (visible only to your team and editable at any time), then choose how to populate it: start from scratch with new environments, or transfer existing environments from another project. ### Start from scratch Starting from scratch provisions a brand new staging environment, and optionally a production environment. Staging is always included; production is added by default but can be left off and unlocked later by adding billing information. You can add more environments after the project is created. ![Create project from scratch dialog](https://images.workoscdn.com/images/46a1f847-8ddb-4e55-a417-3b8ba9b30ca0.png?auto=format&fit=clip&q=50) ### Transfer environments from another project Instead of starting fresh, you can move existing environments into the new project. Select a single source project, then choose one or more of its environments to transfer. A few rules apply: - All transferred environments must come from the **same source project**. You can't pull environments from several projects at once. - The source project must **keep at least one environment**. You can't move all of them out. - The source project can't have [project-level configuration](#project-level-configuration) that isn't yet copyable. Transferring out of a project with feature flags, an Audit Logs schema, or custom email domains isn't supported yet. Transferring is effectively irreversible: the environments leave the source project for good, and replacing them isn't self-serve. Before the transfer runs, the dashboard shows a review step that lists the environments being moved (grouped into staging and production) and requires you to acknowledge the implications. Environments can only be transferred into a **new** project at creation time. Transferring into an existing project isn't supported yet. ![Create project by transferring dialog](https://images.workoscdn.com/images/daa7acc0-dd7a-42b1-b9ee-9d9e7020cc77.png?auto=format&fit=clip&q=50) ## Frequently asked questions ### Do projects cost extra? No. Projects are an organizational layer in the dashboard. Billing still applies per environment based on usage — see [pricing](https://workos.com/pricing) for details. ### Can I move an environment to a different project? Today, environments can only be moved into a **new** project when you create it. See [transfer environments from another project](#transfer-environments-from-another-project). Transferring into an existing project isn't supported yet. A transfer is also blocked when the source project has [project-level configuration](#project-level-configuration), such as feature flags, that can't yet be copied to the new project. ### How do projects relate to organizations? They're unrelated. A project is a dashboard-level grouping of environments that you manage as a developer. An [organization](/reference/organization) is an in-app, multi-tenant concept that represents one of your customers and the users within it. ### Pipes Enable your customers to connect their third-party accounts to your application. ## Introduction Pipes allows your users to securely connect their third-party accounts to your application. With Pipes, you can easily integrate with popular services like GitHub, Slack, Google, Salesforce, and many more without managing OAuth flows, token refresh logic, or credential storage. ## Configuring providers To make an provider available to your users, you will need to configure it in the WorkOS Dashboard. Visit the _Pipes_ section of the WorkOS Dashboard to get started. Click _Connect provider_ then choose the provider from the list. If you don't see the provider you need, please reach out to [our team](mailto:support@workos.com). ### Custom Credentials Configure the provider with your own OAuth credentials: 1. **Create an OAuth application** within the provider's dashboard. 1. You can find instructions on setting up the provider in the documentation section of the setup modal. 2. Use the provided **redirect URI** when configuring the provider. 3. Set the **client ID and secret** from the provider. 4. Specify the required **scopes** for your application. 1. You may need to set these scopes in the provider configuration as well. 5. Provide an optional **description**. This will be used in the widget to inform users on how your application will use their data from the provider. Commonly used scopes are provided in-line, but you should consult each provider's documentation for the full list of available scopes. ## Provider management in your application The [Pipes Widget](/widgets/pipes) provides a pre-built UI for users to connect and manage their connected accounts. The widget shows the user which providers are available, and lets them easily initiate the authorization flow. It communicates with the WorkOS API and stores the connection information for the user. If there's ever a problem with the user's access token, the widget will let them know they need to reauthorize. ![Pipes widget screenshot](https://images.workoscdn.com/images/e84a33bb-0510-4d85-9041-33b1a0ce938c.png?auto=format&fit=clip&q=50) > The description in the widget is set in the provider's configuration in the WorkOS Dashboard. ## Fetching access tokens Once a user has connected a provider, you can [fetch access tokens](/reference/pipes) from your backend to make API calls to the connected service on their behalf. Pipes takes care of refreshing the token if needed, so you'll always have a fresh token. If there's a problem with the token, the endpoint will return information about the issue so you can direct the user to the correct it. This may require sending the user to re-authorize directly or via the page with the Pipes widget. ### Passkeys Configuring passkey authentication and enrollment. ## Introduction Passkey authentication allows users to sign up and sign in to your application using public-key cryptography, which is more secure than a traditional password. Passkeys are built on top of the [WebAuthn](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API) standard that enable the user's device to securely store the passkey's private key, with access protected by biometrics, such as a fingerprint. When the user signs in, the private key is used to sign a payload that is verified with the matching public key. You can read more about how WebAuthn and passkeys work at the [official FIDO alliance passkey website](https://passkeys.dev/), the consortium behind passkey web standards. ## Passkey configuration Passkeys can be enabled in the _Authentication_ section of the [WorkOS Dashboard](https://dashboard.workos.com). ![The WorkOS Dashboard displaying the configuration dialog for passkeys](https://images.workoscdn.com/images/5ed77bef-cfa0-4a40-958f-d19b23a1ec1b.png) > **Developers should configure an [AuthKit custom domain](/custom-domains/authkit) before enabling passkeys in production**. Passkeys are bound to the domain they were registered on. Adding the domain later would prevent the usage of passkeys that were registered on the old domain. ### Enabling progressive enrollment Optionally, your users who are still using password-based authentication can be prompted to create a passkey on their next sign-in. This flow, known as "progressive enrollment", is disabled by default but can be enabled alongside passkey authentication in the WorkOS Dashboard. ![AuthKit displaying the passkey progressive enrollment prompt.](https://images.workoscdn.com/images/c541f4f6-5956-489d-be7e-c8b242c9923d.png) If users skip passkey enrollment they will be reminded every two weeks, and additionally have the option to never be prompted again if they prefer passwords. ### Multi-factor auth If [MFA](/authkit/mfa) is also enabled and required, users who sign in with a passkey will not be prompted for a separate TOTP code. AuthKit treats passkeys as both a first and second factor by requiring user verification when a passkey is presented. User verification in the context of a passkey means the passkey must be combined with another "authorization gesture", like the scanning of a fingerprint, or entering a separate PIN. --- ## Integrating via the API Passkey authentication is currently only available with the hosted UI in AuthKit. ### AuthKit Easy to use authentication APIs designed to provide a flexible, secure, and fast integration. ## Introduction WorkOS AuthKit is a user management platform that provides a set of user authentication and organization security features that securely power your application. Features are designed to be flexible, while offering a fast integration to handle all of the user management complexity that comes with advanced business and customer needs. ## Authentication AuthKit supports many authentication methods out of the box. They are designed to grow with your app, from the simplest use case all the way to complex Enterprise [SSO](/authkit/sso) for your largest customers, these include: - [Single Sign-On](/authkit/sso) - [Email & Password](/authkit/email-password) - [Social Login](/authkit/social-login) - [Multi-Factor Auth](/authkit/mfa) - [Magic Auth](/authkit/magic-auth) These features are available via [AuthKit](/authkit), or through the public [API](/reference/authkit). AuthKit provides an easy to integrate, pre-built authentication flow, while integrating against the API allows you to implement your own UI and Sign In flow. ## Fast integration The fastest way to integrate AuthKit features is with the [Hosted UI](/authkit/hosted-ui). ![AuthKit Sign In UI](https://images.workoscdn.com/images/b8286e7e-3ad9-4d43-99d5-e022e6bb36fb.png?auto=format&fit=clip&q=80) AuthKit abstracts away many of the UX and WorkOS API calling concerns automatically, allowing you to focus on building your application. See the [Quick Start](/authkit) guide for more information on how to get started. ## Security Adopting AuthKit in your app provides a wealth of security benefits. - Best-in-class [email verification](/authkit/email-verification), enabled by default. - Safe [identity linking](/authkit/identity-linking) and merging of duplicate accounts. This protects against spoofing and reduces the user support burden. - Identity Provider (IdP) differences are normalized, so that you get consistency across user profiles. This reduces the likelihood of security issues related to differing semantics across providers. - Automatic bot detection and blocking, to protect against brute force attacks. - [Multi-Factor Authentication (MFA)](/authkit/mfa) available per environment to further enhance your app's security posture. ## Getting started Start integrating AuthKit into your app today, check out the [Quick Start](/authkit) guide to get started with AuthKit or review the [API Reference](/reference/authkit) material. ### Organization Authentication Policies Customize available authentication methods for each organization. ## Introduction Some organizations may prefer to limit their users to specific authentication methods to meet security requirements. These organization-level customizations can be configured on the organization page in the Dashboard. ## Domain policy A domain policy allows an organization to control authentication and membership behavior of users whose email domain matches one of the organization's [verified domains](/authkit/domain-verification). Domain policies are enforced for _all_ users with email domains included in the policy, regardless of their membership status within the organization or the organization selected during sign-in. Additionally, users provisioned through a [directory](/authkit/directory-provisioning) with an email domain included in the organization's domain policy will be automatically added as active members of the organization without needing an invitation. ![Configuring a domain policy in the dashboard](https://images.workoscdn.com/images/b98493d9-f9fe-475d-a448-f9099558cd19.png?auto=format&fit=clip&q=50) > Only one organization can include a specific domain in its domain policy per environment. ### Requiring SSO by default When an SSO connection is first set up for an organization, all non-SSO authentication methods for the organization are automatically disabled. Typically, IT contacts who configure SSO intend for it to be the sole authentication method. Any additional methods can be enabled manually if the organization prefers. ## Organization policy Unlike the domain policy, which is enforced regardless of the organization selected during sign-in, the organization policy is enforced when a member selects the specific organization during sign-in. The organization policy can require authentication via its SSO connection or require MFA. This is particularly useful for guest members who do not have an organization email domain, or when the organization cannot include an email domain in its domain policy because the domain is managed by another organization. ![Configuring an organization policy in the dashboard](https://images.workoscdn.com/images/bcc25d91-602d-420f-a465-6ea790d27005.png?auto=format&fit=clip&q=50) ### AuthKit Easy to use authentication platform designed to provide a flexible, secure, and fast integration. ## Introduction Integrating AuthKit into your app can be done in less than ten minutes. In this guide, we'll walk you through adding a hosted authentication flow to your application using AuthKit. In addition to this guide, there are a variety of [example apps](/authkit/example-apps) available to help with your integration. ## Before getting started To get the most out of this guide, you'll need: - A [WorkOS account](https://dashboard.workos.com/) - Your WorkOS [API Key](/glossary/api-key) and [Client ID](/glossary/client-id) --- ## (1) Configure your project Let's add the necessary dependencies and configuration in your WorkOS Dashboard. ### Install dependencies For a Next.js integration, use the `authkit-nextjs` library. Start by installing it in your Next.js project via `npm`. ```bash title="Install Next.js SDK" npm install @workos-inc/authkit-nextjs ``` ### Configure a redirect URI A redirect URI is a callback endpoint that WorkOS will redirect to after a user has authenticated. This endpoint will exchange the authorization code returned by WorkOS for an authenticated [User object](/reference/authkit/user). We'll create this endpoint in the next step. You can set a redirect URI in the **Redirects** section of the [WorkOS Dashboard](https://dashboard.workos.com). We recommend using `http://localhost:3000/callback` as the default here. WorkOS supports using wildcard characters in Redirect URIs, but not for the default Redirect URI. More information about wildcard characters support can be found in the [Redirect URIs](/sso/redirect-uris/wildcard-characters) guide. ![Dashboard redirect URI](https://images.workoscdn.com/images/a7525cf3-ae4e-4dcd-91dd-27965b005472.png?auto=format&fit=clip&q=80) When users sign out of their application, they will be redirected to your app's [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) location which is configured in the same dashboard area. ### Configure sign-in endpoint Sign-in requests should originate from your application. In some instances, requests may not begin at your app. For example, some users might bookmark the hosted sign-in page or they might be led directly to the hosted sign-in page when clicking on a password reset link in an email. In these cases, AuthKit will detect when a sign-in request did not originate at your application and redirect to your application's sign-in endpoint. This is an endpoint that you define at your application that redirects users to sign in using AuthKit. We'll create this endpoint in the next step. You can configure the sign-in endpoint from the **Redirects** section of the WorkOS dashboard. ![Sign-in endpoint](https://images.workoscdn.com/images/25b53ea7-95ba-48cc-b6e7-ccd1b1bc35eb.png?auto=format&fit=clip&q=80) ### Set secrets To make calls to WorkOS, provide the API key and the client ID. Store these values as managed secrets and pass them to the SDKs either as environment variables or directly in your app's configuration depending on your preferences. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' WORKOS_COOKIE_PASSWORD="" # generate a secure password here # configured in the WorkOS dashboard NEXT_PUBLIC_WORKOS_REDIRECT_URI="http://localhost:3000/callback" ``` The `NEXT_PUBLIC_WORKOS_REDIRECT_URI` uses the `NEXT_PUBLIC` prefix so the variable is accessible in edge functions and proxy configurations. This is useful for configuring operations like Vercel preview deployments. The SDK requires you to set a strong password to encrypt cookies. This password must be at least 32 characters long. You can generate a secure password by using the [1Password generator](https://1password.com/password-generator/) or the `openssl` library via the command line: ```bash title="Generate a strong password" openssl rand -base64 32 ``` > The code examples use your staging API keys when [signed in](https://dashboard.workos.com) --- ## (2) Add AuthKit to your app Let's integrate the hosted authentication flow into your app. ### Provider The `AuthKitProvider` component adds protections for auth edge cases and is required to wrap your app layout. ### Proxy [Next.js proxy](https://nextjs.org/docs/app/api-reference/file-conventions/proxy) is required to determine which routes require authentication. #### Implementing the proxy When implementing the proxy, which [was called middleware before Next 16](https://nextjs.org/docs/messages/middleware-to-proxy), you can opt to use either the complete `authkitMiddleware` solution or the composable `authkit` method. You'd use the former in cases where your proxy is only used for authentication. The latter is used for more complex apps where you want to have your proxy perform tasks in addition to auth. - | Complete The proxy can be implemented in the `proxy.ts` file. This is a full proxy solution that handles all the auth logic including session management and redirects for you. With the complete proxy solution, you can choose between page based auth and middleware auth. #### Page based auth Protected routes are determined via the use of the `withAuth` method, specifically whether the `ensureSignedIn` option is used. Usage of `withAuth` is covered further down in the _Access authentication data_ section. #### Middleware auth In this mode the proxy is used to protect all routes by default, redirecting users to AuthKit if no session is available. Exceptions can be configured via an allow list. In the above example, the home page `/` can be viewed by unauthenticated users. The `/account` page and its children can only be viewed by authenticated users. - | Composable The proxy can be implemented in the `proxy.ts` file. This is a composable proxy solution that handles the session management part for you but leaves the redirect and route protection logic to you. ### Callback route When a user has authenticated via AuthKit, they will be redirected to your app's callback route. Make sure this route matches the `WORKOS_REDIRECT_URI` environment variable and the configured redirect URI in your WorkOS dashboard. ### Sign-in endpoint We'll need a sign-in endpoint to direct users to sign in using AuthKit before redirecting them back to your application. We'll do this by generating an AuthKit authorization URL server side and redirecting the user to it. ### Access authentication data AuthKit can be used in both server and client components. - | Server component The `withAuth` method is used to retrieve the current logged in user and their details. - | Client component The `useAuth` hook is used to retrieve the current logged in user and their details. ### Protected routes For routes where a signed in user is mandatory, you can use the `ensureSignedIn` option. - | Server component - | Client component ### Ending the session Finally, ensure the user can end their session by redirecting them to the logout URL. After successfully signing out, the user will be redirected to your app's [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) location, which is configured in the WorkOS dashboard. > If you haven't configured a [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) in the WorkOS dashboard, users will see an error when logging out. ## Validate the authentication flow To test all of this out, call `npm run dev`, navigate to `localhost:3000`, and sign up for an account. You can then sign in with the newly created credentials and see the user listed in the **Users** section of the [WorkOS Dashboard](https://dashboard.workos.com). ![Dashboard showing newly created user](https://images.workoscdn.com/images/54fa6e6c-4c6f-4959-9301-344aeb4eeac8.png?auto=format&fit=clip&q=80) ### Modeling Your App Learn how to architect your WorkOS integration ## Introduction WorkOS has a wide suite of products to solve your business needs. This guide explains some of the common choices when it comes to modeling your integration. WorkOS is designed to support a wide array of use cases and architectural scenarios, from simple business-to-consumer (B2C) user authentication to complex business-to-business (B2B) architectures with multiple organizations and authentication policy enforcement. Features are designed to grow with you, allowing you get started easily and expand your security options as you onboard larger and larger enterprise customers. Whether you are looking to add the initial authentication piece to a new application, or exploring migration from an existing vendor, you may find yourself asking: - Does WorkOS fit into my existing architecture? - Can I start small and later adopt more features? - I have very specific requirements, can I still use WorkOS? In most cases the answer is yes, and the aim of this guide is to help you understand how. We'll cover the terminology used in this space, describe some common B2C and B2B flows, and finally demonstrate some scenarios that explain how everything fits together. ## Understanding the authentication flow Supporting Email + Password, Single Sign-On, OAuth, Magic Auth, and other authentication concerns on your own is a complex task. You'd need to understand the authentication process, as well as model your applications sign-in and signup user interfaces to account for and handle all possible routes, error states and edges cases. There are three main ways to add WorkOS authentication to your application: ### AuthKit A [hosted login solution](/authkit) that provides a customizable UI and supports a wide range of authentication methods. ### Custom AuthKit UI If you prefer to craft your own UI in your own stack, you can use the [AuthKit APIs](/reference/authkit) directly. ### Standalone Single Sign-On (SSO) For applications that are only interested in [SSO capabilities](/reference/sso). In the majority of cases we recommend using the hosted AuthKit solution. ![AuthKit authentication flow diagram](https://images.workoscdn.com/images/12d849cf-c710-493d-a189-48264d1c3ed7.png?auto=format&fit=clip&q=80)\[border=false] On successful completion, AuthKit will return an authentication code to your application via your specified redirect URI, this is exchanged for the user object and used to create a session. See the [Quick Start guide](/authkit) for more information on how to implement this. ## Authentication methods Prior to building your integration, it is useful to think about which authentication methods are part of your requirements. Typical consumer authentication methods include the following: ### Email + Password The most common method of authentication, users sign up or sign in to your app with email and password. This method is enabled by default. ### OAuth OAuth, also known as Social Login, is when a user logs in with an account belonging to a different service. Examples include logging in with your Google, Microsoft or GitHub account instead of making a new account with your app. These authentication methods can be configured from the WorkOS dashboard. ### Magic Auth Also known as Passwordless, Magic Auth authentication works by emailing the user a unique, one-time-use 6 digit code which they then use to authenticate. A similar technique is Magic Link, where the user can log in by clicking a link emailed to them. This method has proven to be unreliable as IT teams often employ security measures that scan user emails and programmatically click any links found in the email, invalidating the Magic Links. As such, WorkOS has deprecated Magic Links in favour of Magic Auth. ### SSO The favored authentication method by enterprise sized companies, SSO allows an organization's users to sign in with a single ID to related, yet independent software systems. The AuthKit APIs make the above easy to implement using your own UI, or you can use AuthKit's Hosted UI for a fully hosted experience. ## Single-tenant and multi-tenant models You might encounter the concepts of single-tenant and multi-tenant when discussing an application's authentication model. Single-tenant and multi-tenant architectures offer different approaches to managing resources and data in software applications, especially in cloud services or Software as a Service (SaaS) environments. ![Diagram of single and multi-tenant models](https://images.workoscdn.com/images/48ef829e-6758-4606-a696-7963beb803b2.png?auto=format&fit=clip&q=80)\[border=false] ### Single-tenant In the context of authentication and authorization, single-tenant refers to a software architecture where a separate instance of the software is set up for each client on separate servers or virtual machines. Each organization is paired with its own instance of both the application and the underlying database. This approach offers full data isolation between customers, but comes at the cost of being more resource-intensive and costly. Each client's setup may require separate maintenance, updates, and support. ### Multi-tenant Multi-tenant refers to a software architecture where a single instance of the software serves multiple customer organizations, known as tenants. Each tenant's data is isolated and remains invisible to other tenants because the software is designed to securely handle this data across all tenants. In the context of WorkOS, a multi-tenant application could be accomplished by the use of [Organizations](/reference/organization) and [Organization Memberships](/reference/authkit/organization-membership) to ensure that end-users only have access to the data they are authorized to. By default WorkOS comes with two environments: staging and production. The former is for development and testing, the latter for live traffic. For single-tenant applications, new environments can be added to your WorkOS account to accommodate each of your users. For more information or to request new environments, please reach out to [support](mailto:support@workos.com). ## Simple B2C model ![Simple B2C model](https://images.workoscdn.com/images/55ffa6da-ec2b-4f03-881c-3f68e5a2a818.png?auto=format&fit=clip&q=80)\[border=false] In a simple B2C model, all users belong to the application, users do not require assignment or management by an organization in order to perform actions or access resources. In this model your customer is also the end-user, they sign up or sign in to your app in order to use your services without being associated with an organization. ### User data in B2C models It's common to have a single users table in your database linking to the WorkOS user (among other services), you may optionally decide to use WorkOS as the source of truth for other user information such as `firstName`, `lastName` or `email`, though this depends on your application requirements. In this model, WorkOS's primary role is to authenticate users and store them in a simple, flat structure. This is the default model and is the simplest to implement, but as your needs grow you may find yourself needing to add additional functionality. ## B2B modeling In contrast to the B2C example, a typical B2B model introduces the concept of Organizations. Organizations relate a set of users and provide a structure to manage and enforce authentication methods and resource access. We can extend our previous diagram to introduce this concept. ![B2B model](https://images.workoscdn.com/images/21e07368-ab1a-460e-8dcb-499d763cbdd4.png?auto=format&fit=clip&q=80)\[border=false] In this model, we have a one-to-many relationship between users and organizations, a user can belong to many organizations and an organization can have many users, this relationship is expressed by our Organization Membership table. Unlike the B2C example, the customer here is a (usually enterprise) company that has its own users, typically employees or contractors. While you can still use all the authentication methods outlined above with B2C models, the main difference between B2C and B2B is that the latter tends to prefer SSO as its authentication method of choice. This model starts to become incredibly powerful as we can now capture more complex scenarios. For example, we could leverage features such as domain verification and domain policies to control authentication behavior and provision members automatically. ### Domain verification and domain policies [Domain verification](/authkit/domain-verification) is the process of proving ownership of a specific domain, typically handled by a company's IT department. Once a domain is verified, all existing and future users with email addresses matching the domain are, by default, managed by the organization's [domain policy](/authkit/organization-policies/domain-policy). This allows the organization to control authentication and membership behavior for these users, such as requiring these users to authenticate via SSO. Users signing in with SSO with a verified email domain are automatically considered verified and do not need to complete the email verification process. ### Integrating SSO with the Admin Portal When onboarding a new enterprise customer, they will likely ask to integrate their SSO connection provided by their own Identity Provider (IdP) with your application. The Admin Portal provided by WorkOS makes this process easy to implement by providing a hosted UI that guides your user through SSO configuration. ![Admin Portal flow](https://images.workoscdn.com/images/77050e33-5dcc-480f-a0a7-3f46a6b33abf.png?auto=format&fit=clip&q=80)\[border=false] With the Admin Portal, the process of configuring your customer's SSO integration is reduced to creating an Organization in WorkOS, saving relevant data in your own database and then redirecting the user to the Admin Portal to guide them through the configuration flow. ### User data in B2B models As with B2C models, user data on the WorkOS side can be used as the source of truth, but the far more common scenario is to store user information in your own database which links to the WorkOS user. The AuthKit and SSO products can be used independently, with the latter acting as authentication middleware which intentionally does not handle user database management for your application. If you're unsure which is best for your business, it's recommended to stick with AuthKit as it gives you the aforementioned flexibility to add and/or remove features as your needs grow. ## Example scenarios As your application grows you may find yourself needing to add additional features to support customer needs. AuthKit is designed with this is mind. As you move upmarket and take on larger and larger customers, you can easily adopt and extend your feature set within an established architecture. The following scenarios explain some common use cases with specific feature sets. - [SSO with contractors](/authkit/sso-with-contractors) – Enforcing Organization SSO with external guest members. - [Invite-only Signup](/authkit/invite-only-signup) – An invite only application that allows existing users to invite new members. ### Migrating to AuthKit Guidance on moving your existing users to WorkOS. ## Introduction WorkOS provides a [range of guides](/migrate) to help you migrate your existing integration to AuthKit. ## Migrate from another service These guides will walk you through the process of moving your users and organizations to WorkOS from another service. ## Migrating an existing WorkOS integration If you already have an integration with WorkOS (for example, using the [standalone API](/sso) to provide SSO to your customers), you can migrate to AuthKit and take advantage of all of the features it provides by following [this guide](/migrate-standalone-sso). ### Multi-Factor Authentication Add an additional layer of security to your application. ## Introduction Multi-Factor Authentication (MFA) is an additional method of securing your application. MFA adds a layer of security during sign in that requires a user to provide an additional time-based one-time password (TOTP). ## Getting started AuthKit will make the necessary API calls to handle first-time configuration of users' MFA factors automatically, and validate one-time codes as part of the authentication flow. ### Enabling MFA MFA can be enabled in the _Authentication_ section of the [WorkOS Dashboard](https://dashboard.workos.com). New and existing users will be required to set up multi-factor authentication with an authenticator app that supports one-time passcodes before they can sign in. > The MFA requirement **does not** apply to SSO users. ![Dashboard showing how to enable MFA](https://images.workoscdn.com/images/f660826c-cb2d-4912-ba10-1f622d6a447d.png?auto=format&fit=clip&q=80) ![AuthKit displaying MFA configuration](https://images.workoscdn.com/images/31fcbe12-63c2-47e2-9685-d45fe4d41fb5.png?auto=format&fit=clip&q=80) --- ## Integrating via the API If you'd prefer to build and manage your own authentication UI, you can do so via the AuthKit [Multi-Factor API](/reference/authkit/mfa). Examples of building custom UI are also [available on GitHub](https://github.com/workos/authkit). ### Metadata and External IDs Store additional information about users and organizations. ## Introduction Metadata is an attribute of organizations and users that allows you to store additional information about these objects, structured as key-value pairs. For example, you can use metadata to store information about a user's profile picture, or the organization's address. External identifiers allow you to associate organizations and users with an identifier in your own system. --- ## External identifiers External identifiers are an attribute of organizations and users that allows you to associate these objects with an identifier in your own system. Once you have set an external identifier for an object, you can query on it via dedicated endpoints in the WorkOS API. External identifiers must be unique within your environment and are limited to 64 characters. ## Metadata You can add up to 10 key-value pairs to an organization or user within these data limits: - **Key**: Up to 40 characters long. ASCII only. - **Value**: Up to 600 characters long. ASCII only. If your integration requires more than 10 key-value pairs, consider storing the additional data in your own external database and use an external identifier to associate the data with an organization or user. > Never store sensitive information in metadata such as passwords, API keys, or other private information. Metadata is returned in the response body for backend API operations that return organization or user objects, but not in the response body of the [User Authentication](/reference/authkit/authentication) operations. If you want to publicly expose metadata properties from users or organizations in your access tokens, you can use JWT templates to customize claims in your application's access tokens. ## Set an external identifier To set an external identifier for an organization or user, include the `external_id` property in the request body of the [Create an organization](/reference/organization/create) or [Create a user](/reference/authkit/user/create) endpoints. To update an external identifier, include the `external_id` property in the request body of the [Update an organization](/reference/organization/update) or [Update a user](/reference/authkit/user/update) endpoints. ## Query by external identifier To query an organization or user by their external identifier, use the [Get organization by external identifier](/reference/organization/get-by-external-id) or [Get user by external identifier](/reference/authkit/user/get-by-external-id) endpoints. ## Add and update metadata Updates to metadata are partial. This means that you only need to include the metadata attributes that you want to update. Metadata can be included in the request body of the following endpoints: - [Create an organization](/reference/organization/create) - [Update an organization](/reference/organization/update) - [Create a user](/reference/authkit/user/create) - [Update a user](/reference/authkit/user/update) To add a metadata attribute to an entity, include the key and value pair in the `metadata` object of the request body. ```json { "metadata": { "key": "value" } } ``` To update a metadata attribute, include the key and value pair in the `metadata` object of the request body. ```json { "metadata": { "key": "new_value" } } ``` To delete a metadata attribute, set the key to `null` in the `metadata` object of the request body. ```json { "metadata": { "key": null } } ``` To delete all metadata attributes, set the `metadata` property an empty object. ```json { "metadata": {} } ``` ## Exposing metadata in JWTs Custom metadata and external identifiers can be exposed as claims in JWTs using [JWT Templates](/authkit/jwt-templates). ### Model Context Protocol How to use AuthKit as the authorization server for your MCP server. ## Introduction [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) is a new protocol that standardizes how LLM-based clients can programmatically interact with applications. This includes querying data, in the form of resources, or taking direct actions in the application in the form of tools. This guide is intended for application developers implementing an MCP _server_ that requires authentication. WorkOS and AuthKit can provide a secure way to manage access to your MCP server with minimal effort. > If you have feedback or questions about MCP, we'd love to hear from you! Reach out to [WorkOS support](mailto:support@workos.com?subject=MCP%20Authentication%20with%20AuthKit) or via your team's WorkOS Slack channel. ## Authorization The MCP specification builds on industry-standard protocols like [OAuth 2.0](https://datatracker.ietf.org/doc/html/rfc6749) in order to secure access to an MCP server. It makes the following distinctions between entities in the authorization flow: - **Resource Server** – This is your MCP server, which you may choose to build using the [official Model Context Protocol SDKs](https://github.com/modelcontextprotocol). - **Authorization Server** – This is AuthKit, which is a spec-compatible OAuth authorization server. While the spec allows the authorization and resource server to be the same, it can be architecturally simpler to delegate to an existing authorization server like AuthKit. Support for MCP authorization is built on top of [WorkOS Connect](/authkit/connect/oauth), which provides all of the necessary OAuth API endpoints MCP clients will use to authenticate. You can view your AuthKit metadata by making a request to its `/.well-known/oauth-authorization-server` endpoint: ```bash curl https://authkit_domain/.well-known/oauth-authorization-server | jq { "authorization_endpoint": "https://authkit_domain/oauth2/authorize", "code_challenge_methods_supported": ["S256"], "grant_types_supported": ["authorization_code", "refresh_token"], "introspection_endpoint": "https://authkit_domain/oauth2/introspection", "issuer": "https://authkit_domain", "registration_endpoint": "https://authkit_domain/oauth2/register", "scopes_supported": ["email", "offline_access", "openid", "profile"], "response_modes_supported": ["query"], "response_types_supported": ["code"], "token_endpoint": "https://authkit_domain/oauth2/token", "token_endpoint_auth_methods_supported": [ "none", "client_secret_post", "client_secret_basic" ] } ``` ## Integrating AuthKit handles the authentication flow so your MCP server only needs to implement the following concerns: 1. Verifying access tokens issued by AuthKit for your MCP server. 2. Direct clients to AuthKit using standardized metadata endpoints. ### Enabling Client ID Metadata Document (CIMD) MCP clients often have no prior relationship with your MCP server. The MCP protocol specifies that authorization servers (AuthKit) should support [Client ID Metadata Document](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-client-id-metadata-document-00) (CIMD) to allow MCP clients to identify themselves. Client ID Metadata Document is off by default, but you should enable it in the WorkOS Dashboard under _Connect_ → _Configuration_. Client ID Metadata Document was added to the MCP specification in November 2025. You can enable the previous approach, [Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591) (DCR), in the WorkOS Dashboard for backwards compatibility with MCP clients that don't yet support Client ID Metadata Document. ![A screenshot of the Connect Configuration page in the WorkOS Dashboard.](https://images.workoscdn.com/images/0b2eefe1-901d-422b-916b-185b2caeed10.png) ### Configure MCP Server URL Add the URL of your MCP endpoint as a valid "Resource Indicator" in the WorkOS dashboard. MCP clients will send this value as the `resource` parameter during the authorization flow. This should be the same value as the [`resource` field in your server's metadata endpoint](#metadata). ![A screenshot of the Resource Indicators configuration dialog in the WorkOS Dashboard.](https://images.workoscdn.com/images/8d580fb6-3b05-49f7-95c8-e2c20053d844.png) Multiple resource URLs can be added, in case you are building multiple MCP servers or need to account for different environments. > Access tokens will be issued with an `aud` claim that matches the requested `resource`. If you don't configure any Resource Indicators in the WorkOS Dashboard, then a default `aud` value unique to your WorkOS Environment will be used instead, with the `resource` parameter then ignored. ### Token Verification Your app needs to gate access to the MCP endpoints by verifying access tokens issued by AuthKit for your MCP server. This process is very similar to [the way any Connect JWT is verified](/authkit/connect/oauth/verifying-tokens), with one important addition: ```js import { jwtVerify, createRemoteJWKSet } from 'jose'; const JWKS = createRemoteJWKSet(new URL('https://authkit_domain/oauth2/jwks')); const WWW_AUTHENTICATE_HEADER = [ 'Bearer error="unauthorized"', 'error_description="Authorization needed"', `resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource"`, ].join(', '); const bearerTokenMiddleware = async (req, res, next) => { const token = req.headers.authorization?.match(/^Bearer (.+)$/)?.[1]; if (!token) { return res .set('WWW-Authenticate', WWW_AUTHENTICATE_HEADER) .status(401) .json({ error: 'No token provided.' }); } try { const { payload } = await jwtVerify(token, JWKS, { issuer: 'https://authkit_domain', audience: 'https://mcp.example.com', }); // Use access token claims to populate request context. // i.e. `req.userId = payload.sub;` next(); } catch (err) { return res .set('WWW-Authenticate', WWW_AUTHENTICATE_HEADER) .status(401) .json({ error: 'Invalid bearer token.' }); } }; ``` Note the addition of a [`WWW-Authenticate`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/WWW-Authenticate) header with the `resource_metadata` challenge parameter containing a `/.well-known/oauth-protected-resource` URL. This allows clients to dynamically discover the appropriate authorization server, enabling zero-config interoperability between different MCP clients and servers. ### Metadata Your MCP server should implement `/.well-known/oauth-protected-resource` endpoint mentioned in the previous section, returning the following minimal JSON response: ```js app.get('/.well-known/oauth-protected-resource', (req, res) => res.json({ resource: `https://mcp.example.com`, authorization_servers: ['https://authkit_domain'], bearer_methods_supported: ['header'], }), ); ``` MCP clients that support metadata discovery will automatically fetch this metadata when they initially encounter a `401 Unauthorized` error from the middleware implemented above. Since AuthKit is included in the metadata under `authorization_servers` the MCP client will redirect the user to AuthKit in order for them to sign in. ![The authorization prompt users will be shown when giving access to an MCP client.](https://images.workoscdn.com/images/ce1d133c-503c-4abc-8422-c274bbd8786c.png) Behind the scenes, AuthKit implements the necessary authorization and token endpoints so that your application doesn't need to. You can read more in the [latest version of the MCP authorization spec](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/901ac03e1c72827acb8017f80eeb14e38ad8ba42/docs/specification/draft/basic/authorization.mdx) but most apps can consider them implementation details of AuthKit as the authorization server. Upon successful authentication the client will receive credentials and can start making requests to your application's MCP endpoints. ## Compatibility The MCP space is rapidly evolving and not every client may support the latest version of the specification. In particular, some clients may not support [OAuth 2.0 Protected Resource Metadata](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-resource-metadata-13) and its `/.well-known/oauth-protected-resource` endpoint, instead attempting to fetch [OAuth 2.0 Authorization Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414) directly from your application's MCP server. For these clients, your server can implement a metadata endpoint as a proxy with AuthKit as the upstream source of truth: ```js app.get('/.well-known/oauth-authorization-server', async (req, res) => { const response = await fetch( 'https://authkit_domain/.well-known/oauth-authorization-server', ); const metadata = await response.json(); res.json(metadata); }); ``` Clients will use AuthKit as the authorization server and the rest of the flow will be identical. ## Cross App Access > Cross App Access is available in early access. Reach out via [email](mailto:support@workos.com?subject=MCP%20Cross%20App%20Access) or Slack to have it enabled for your environment. Cross App Access (XAA) allows users who use SSO in two applications to authenticate from one to the MCP server of the other via their IdP, without needing to go through an OAuth flow. For example, a user signed in to one application can seamlessly access an MCP server belonging to a different application within the same organization. MCP Auth with AuthKit supports [ID Token JWT Authorization Grant](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-identity-assertion-authz-grant) (ID-JAG) token exchange by default, so no additional implementation work is needed on your end. Once Cross App Access is enabled for your environment, users authenticated in one application can exchange their token for an access token scoped to your MCP server. If you are an agent platform provider looking to add Cross App Access for your SSO connections so that your users can leverage XAA with MCP servers in your product, [contact us](mailto:support@workos.com?subject=Cross%20App%20Access%20for%20SSO%20Connections) to get started. > Cross App Access is not currently supported when using [Standalone MCP Auth](#standalone-mcp-auth). ## Standalone MCP Auth If you already have an existing authentication system in your application, you can use [Standalone Connect](/authkit/connect/standalone) to integrate AuthKit's OAuth capabilities with your MCP server while preserving your current authentication stack. Standalone Connect is particularly useful for MCP scenarios where you: - Want to add MCP support to an application with existing user authentication. - Need to maintain consistency with your current login experience and user management. - Require custom authentication logic. ### How it works With Standalone Connect for MCP, the authentication flow works differently from the standard AuthKit integration described above: 1. **MCP clients** initiate the OAuth flow for your MCP server with AuthKit as your authorization server. 2. **AuthKit redirects** users to your application's Login URI instead of showing AuthKit's login page. 3. **Your application** authenticates users using your existing authentication system. 4. **Your application** calls [AuthKit's completion API](/reference/workos-connect/standalone/complete) to complete the OAuth flow. 5. **AuthKit** handles the OAuth consent, token issuance, and returns control to the MCP client. This approach allows you to maintain full control over the user authentication experience while leveraging AuthKit's OAuth infrastructure for MCP client authorization. ### Implementation considerations When using Standalone Connect with MCP: - You'll still need to enable [Client ID Metadata Document](#enabling-client-id-metadata-document-cimd) to support MCP clients that register themselves. - [Token verification](#token-verification) works identically—your MCP server validates tokens using the same JWT verification process. - The [metadata endpoints](#metadata) remain the same, ensuring MCP clients can discover and interact with your server. - Your Login URI must be configured in the WorkOS Dashboard and handle the `external_auth_id` parameter from AuthKit. The key difference is in the authentication step: instead of users signing in through AuthKit's interface, they authenticate with your existing system, and AuthKit handles only the OAuth authorization and token issuance portions of the flow. For detailed implementation steps and code examples, see the [Standalone Connect documentation](/authkit/connect/standalone). ### Magic Auth Maximize user experience and security with passwordless authentication. ## Introduction Magic Auth is a passwordless authentication method that allows users to sign in or sign up via a unique, six digit one-time-use code sent to their email inbox. ## Getting started AuthKit will make the necessary API calls to issue one-time-use codes via email and provide input verification and authentication automatically. If desired, you can [send these emails yourself](/authkit/custom-emails). ### Enabling Magic Auth Magic Auth can be enabled in the _Authentication_ section of the [WorkOS dashboard](https://dashboard.workos.com). Users will then be able to sign in or sign up via Magic Auth on the AuthKit authentication page. One-time-use codes expire after **10 minutes**. ![Dashboard showing how to enable Magic Auth](https://images.workoscdn.com/images/78df279e-3bd5-451e-a0a0-7e93ed5e5bd5.png?auto=format&fit=clip&q=80) ![AuthKit displaying email sign-in](https://images.workoscdn.com/images/9129ad29-d488-462b-ad85-3a2a7908235d.png?auto=format&fit=clip&q=80) ![AuthKit displaying code input UI](https://images.workoscdn.com/images/1810724e-466f-4f76-b905-12167a051cdf.png?auto=format&fit=clip&q=80) --- ## Integrating via the API If you'd prefer to build and manage your own authentication UI, you can do so via the AuthKit [Magic Auth API](/reference/authkit/magic-auth). Examples of building custom UI are also [available on GitHub](https://github.com/workos/authkit). ### Get started with AuthKit Set up AuthKit in your app using either the AI Installer & CLI or a manual framework-specific guide. ## Use the AI Installer & CLI Automatically integrate WorkOS into your app with one command. The [AI Installer & CLI](/authkit/cli-installer) also manages resources, provisions environments, and equips your coding agents with WorkOS knowledge. ```bash title="AI Installer & CLI" npx workos@latest ``` ## Or install using your preferred stack Follow a framework-specific guide to integrate AuthKit manually. ### JWT Templates Customize the claims in your application's access tokens. ## Introduction JWT templates allow you to customize the claims in your application's access tokens issued by WorkOS. You can leverage core attributes of users and organizations, in addition to [custom metadata](/authkit/metadata) you set on these objects. --- ## Create a JWT template JWT templates can be managed in the Authentication page within the [WorkOS Dashboard](https://dashboard.workos.com/environment/authentication/features). The JWT Template can be found within Features. JWT templates are comprised of a template string which is rendered with the user and organization context after a user successfully authenticates. ## Example usage --- ## Custom attributes You can include IdP-sourced attributes in your JWT claims using the `organization_membership.custom_attributes` context. These attributes are available from the linked [Directory User](/reference/directory-sync/directory-user) or [SSO Profile](/reference/sso/profile). To configure custom attributes, see the [IdP Attributes](/sso/attributes) guide for SSO or the [User Attributes](/directory-sync/attributes) guide for Directory Sync. ### Example ### Priority rules When a membership is linked to both a Directory User and an SSO Profile, the Directory User's `custom_attributes` take precedence. This ensures consistent data when both IdP sources are configured. --- ## Syntax ### 1. **Basic Variable Interpolation** You can reference variables inside the template. ### 2. **Fallback Values** (`||` operator) If the first value is `null` or undefined, the next value in the fallback chain is used. ### 3. **String Literals** Strings can be used as fallback values. ### 4. **Concatenation in Strings** Multiple variables can be used within a single string. ### 5. **Object Interpolation** Interpolating entire objects and arrays is allowed if they are valid JSON objects. This is not allowed inside string literals and will throw a validation error. ### 6. **Reserved Keys Restriction** The following keys cannot be used in templates: - `iss` - `sub` - `exp` - `iat` - `nbf` - `jti` Any attempt to use these keys will result in a validation error. ## Whitespace Handling The rendering engine trims whitespace from the beginning and end of string values. ## Error Handling If the template contains invalid syntax, an error will be thrown: - **Template must render to an object with at least one explicitly defined top-level key:** If the template does not evaluate to a valid JSON object (e.g., an array or primitive value). Example: ```js [ {{ user.email }} ] ``` - **Keys reserved (`iss`, `sub`, `exp`, etc.):** These keys cannot be used in the template. ```js { "iss": {{ user.email }} } ``` - **String encapsulated expression cannot contain object reference:** Objects cannot be interpolated inside a string. ```js { "user": "{{ user.metadata }}" } ``` - **Invalid expression segment:** Logical operators (`||` with empty operands) or malformed expressions are not allowed. ```js {{ user.email && user user }} {{ user.email || || user.email }} ``` - **Template parse error: missing '}}':** A template block was opened but never closed. ```js {{ user.id ``` - **Expression cannot be empty:** An empty expression inside `{{ }}` is invalid. ```html {{}} ``` - **Missing closing braces:** `Template parse error: missing '}}'` - **Invalid key usage:** `Keys reserved (iss, sub, exp, etc.)` - **Unknown variables:** `Invalid path: "unknown.variable"` ## Null Handling JWT templates provide built-in handling for `null` values to ensure access tokens only contain populated claims. ### **1. Removing Top-Level Null Values** If an expression evaluates to `null`, the corresponding key is removed from the final JSON output. #### **Example** ### **2. Handling Null Values in Concatenated Strings** If a `null` value appears in a string concatenation, it is replaced with an empty string (`""`) instead of being removed. ### **3. Using Fallbacks to Avoid Null Values** The `||` operator can be used to provide a fallback value when an expression evaluates to `null`. ## Size limits JWT templates must render to a JSON object that is 3072 bytes or smaller due to cookie size constraints in web browsers. ### Just-in-time Provisioning Automatically provision users and memberships with JIT provisioning. ## Introduction JIT provisioning automatically creates users and organization memberships when a user signs in. This feature allows users to access an organization's resources without requiring manual invitations from IT contacts. ## Automatically add users with verified domains as members Users with [verified email domains](/authkit/domain-verification) can be automatically added as members to an organization through the organization's [domain policy](/authkit/organization-policies/domain-policy). This feature is useful when an application or organization wants to automatically group individuals into the same workspace based on their email domain. ![Configuring a domain policy in the dashboard](https://images.workoscdn.com/images/b98493d9-f9fe-475d-a448-f9099558cd19.png?auto=format&fit=clip&q=50) ## SSO JIT provisioning When a user signs in, WorkOS detects when their email domain matches a verified domain of an organization and prompts the user to sign in through the organization's IdP. If the user existed in WorkOS previously, that existing user is automatically added to the organization. Otherwise, a new user is created and added to the organization. ![Configuring just-in-time provisioning for SSO users in the dashboard](https://images.workoscdn.com/images/90a85516-ed7a-4bd4-88a5-384b2f818436.png?auto=format&fit=clip&q=50) ### Custom attributes When JIT provisioning creates a membership via SSO, [custom attributes](/sso/attributes) from the SSO Profile are made available on the organization membership's `custom_attributes` field. This allows you to access IdP-sourced attributes in your application via the [organization membership API](/reference/authkit/organization-membership) or [JWT templates](/authkit/jwt-templates). > If a directory is linked to the membership, the directory user's custom attributes will always take precedence over the SSO profile's attributes. ### Guest provisioning SSO JIT provisioning is not fully supported for guests whose email domain has not been [verified](/authkit/domain-verification) by the organization. For example, an IT contact may want to gate all contractor access through their IdP (to enable access revocation across applications) but the contractor prefers to use their own email address. Instead, guest users must be [invited](/authkit/invitations) to join the organization before they are able to sign in with the organization's IdP. ## Disabling JIT provisioning Both automatic membership by email domain and SSO JIT provisioning are enabled by default but can be disabled in the [WorkOS Dashboard](https://dashboard.workos.com). Disabling these features may be useful if IT contacts prefer to manually control membership through [invitations](/authkit/invitations). ### Invite-only signup Modeling an invite-only application without a public signup page. ## Introduction In this scenario, we outline the considerations, concepts, and best practices for modeling a closed-registration application in which users may only be added to the application via an invitation. ## Goals & requirements Imagine a company that wishes to model an invite only application that requires an exclusive invite to access. The product is yet to launch, and as the initial release approaches they plan to seed memberships from a small subset of organizations and later allow existing users to invite new members from a quota. The requirements are as follows: - Signup should be unavailable to the general public. - An initial set of invites will be sent from a pre-existing mailing list. - Later, members should be able to invite other members, but only to a given quota. - Invites should be sent and accepted via email. ## Invite-only model In order to implement a invite only structure, the application must account for the following: - AuthKit must not expose sign up controls to the general public. - Invites will be performed programmatically from a seed script. - Members can invite other members via an invite UI within the application. ![Closed-registration authentication flow](https://images.workoscdn.com/images/4cb2c8f9-896d-4191-8b04-90d7bd908e6b.png?auto=format&fit=clip&q=80)\[border=false] ## Disabling signup AuthKit provides an out-of-the-box signup form which handles validation UX, makes the necessary WorkOS API calls and handles the end-to-end lifecycle of the invite flow (emailing of members, accepting of invites, assignment of members to organizations where appropriate). In this scenario, the application should not expose the signup flow to the general public. It can be disabled per environment by toggling the "Sign up" setting in the authentication section of the WorkOS dashboard. ![Image of a modal in the WorkOS dashboard to disable sign-ups](https://images.workoscdn.com/images/76369560-2e4c-41bd-b3ba-1e7e1cf806e3.png?auto=format&fit=clip&q=80)\[border=false] ## Inviting users User invitations can be issued in one of two ways: - Via the WorkOS dashboard. - Programmatically via the WorkOS SDK. The simplest way to get started is via the WorkOS dashboard. Invites can be created by navigating to "Invites" tab in the "Users" section of the dashboard. ![Image of a modal in the WorkOS dashboard to invite new users](https://images.workoscdn.com/images/94103735-c85e-43e2-aee1-3a46c33bf2a2.png?auto=format&fit=clip&q=80)\[border=false] This is helpful in the early stages of product development where there may be a small number of potential users and the product is not yet mature enough to warrant development time spent implementing custom invitation controls, or when dealing with support requests from users who are having difficulty. ## Programmatic invitations Manually issuing invitations from the dashboard is not scalable nor always feasible when needing to issue a large number of invites, or if organic sign up growth is desired without a support team. In this case using the WorkOS API to perform and manage invitations is preferred. ### Seeding initial users from a script Typically, an application will implement a "seed" script which will be run once to issue a set of invites to a pre-existing mailing list. This can be done by using the WorkOS API to create an invite for each email address in the list. ## Inviting users within the application Custom invitation controls can be implemented within the application to allow members to invite other members. This generally requires adding a form to the UI to collect the email address of the user to invite alongside a button to trigger the API call. Additionally, a count of the number of invites a user has made might be stored and checked against a quota to ensure they don't exceed the number of invites they are allowed to send. A call can then be made to [the WorkOS API](/reference/authkit/invitation/send) by supplying the target users email address as well as the ID of the originating organization. The invited user can then accept this invite via email and move through the steps to gain access to the application. ## Summary This scenario covers some high-level considerations when thinking about closed-registration application. By using AuthKit, the WorkOS API, and the dashboard it's possible to limit signup and implement an invite flow within your application. In cases where the signup restriction is temporary, signup in AuthKit can be easily re-enabled via a setting in the WorkOS dashboard. ### Invitations Easily add users to your application or as members of an organization. ## Introduction Invitations are a way of adding a specific user to your application or as a member of an organization. They provide a flow for end-users to engage in collaboration that takes into consideration security and user choice. ## Invitation flow Each invitation is for a specific email address to a specific organization. Invitations are for both new users and existing users. Each invitation is a two step process: - The inviter expresses intent for someone to join an organization. - The invitee chooses to join that organization. ### Inviting new users to an organization If an invitation is created for an email address that does not yet exist, an email is sent to that user with a link to sign up for your application and join the organization. As part of signing up, they automatically join the organization. If a user is invited to multiple organizations, they only join the organization for which they clicked the invitation email for, indicating intent to join that specific organization. ### Inviting existing users to an organization If an invitation is for an existing user, clicking the link in the email and signing in adds the user as a member to the organization. If the user is already signed in, you can use the invitation code to validate that the signed-in user is eligible to use the invitation, by querying the [Invitation API](/reference/authkit/invitation). This offers choice for the end-user so that they aren't automatically added to organizations that may be attempting phishing attacks. ## Application-wide invitations Invitations do not have to be specific to an organization. An invitation sent without specifying an organization is an invitation to join the application. This enables your existing users to help grow your application by inviting peers organically. When signup is disabled, users cannot register for a new account through [AuthKit](/authkit) or the [API](/reference/authkit/invitation). When a valid invitation code is present in the sign-in flow, registration is opened up both in AuthKit and the API so that a new user may sign up. This lets you model your application as a closed-registration invitation-only system. ## Sending invitations Invitations can be sent programmatically by your application with the [Invitation API](/reference/authkit/invitation), or viewed and manually created in the [WorkOS Dashboard](https://dashboard.workos.com/). By default, WorkOS sends these emails, but you can also [send the emails yourself](/authkit/custom-emails). ![Dashboard displaying a list of user invitations](https://images.workoscdn.com/images/18299a05-f824-410e-a17b-828fbe5826f1.png?auto=format&fit=clip&q=80) ## Email address used to accept an invite Often, a user might want to accept their invitation using an email address that's different from the one that the invitation was sent to. ### Without organization membership When an invitation doesn't include an organization to join, a user can accept the invitation using any email address. For example, an invitation sent to `user@example.com` can be used with `another-user@foo-corp.com` email address. ### With organization membership For organization-specific invitations, there are different rules based on the email domain on the invitation. - **Consumer email domains**, such as Gmail or Yahoo: the invited user must sign up using exactly the same email address to which the invitation was sent. - **Corporate domains**: the user can sign up with any email address from the same domain as the email on the invitation. For example, an invitation sent to `user@foo-corp.com` can be accepted with `another-user@foo-corp.com` ### Impersonation Learn how to sign into your application as one of your users. ## Introduction Impersonation allows administrators and support team members to assume the identity of any of your users, allowing them to reproduce or debug issues the user may be having in your application. The ability to see the application in an identical state as the user helps to greatly speed up the support process. ## Enabling impersonation Since impersonation allows any member of your WorkOS team to bypass the normal authentication flow for a user, it is not enabled by default in any of your environments. You must have the **Admin** role in order to enable impersonation for an environment. ![A screenshot showing the WorkOS Dashboard configuration card for impersonation](https://images.workoscdn.com/images/7ceec4ef-0c64-45ad-a729-b529d8f13cb5.png?auto=format&fit=clip&q=80) Navigate to _Authentication_ → _Features_ → _User Impersonation_ and select _Configure_ to enable impersonation for your current environment. ## Using impersonation To impersonate one of your users, navigate to _Users_, select the user you'd like to impersonate, and under _Danger Zone_ select _Impersonate User_. ![A screenshot of the User details page in the WorkOS Dashboard](https://images.workoscdn.com/images/afcfc2b9-275c-4a08-9976-ab9b1b30a7b8.png?auto=format&fit=clip&q=80) You will be prompted for the reason your are impersonating the user. The reason is required and will be recorded internally on the `session.created` event that is emitted whenever impersonation is used. If the user is a member of more than one organization, you will also need to choose which of these organizations you will be signing-into as the user. You can read more about users and organizations in our [dedicated guide](/authkit/users-organizations). Finally, click _Impersonate user_ to start an impersonation session, redirecting your browser to your application's callback endpoint with an authorization code for the impersonated user. You can read more about how to implement a callback endpoint in our [Quick Start guide](/authkit/2-add-authkit-to-your-app/add-a-callback-endpoint). > Impersonation sessions automatically expire after 60 minutes. Be aware that impersonating a user usually generally gives the same level of access as that user, allowing the impersonator to see the user's information. If your application contains sensitive user data, see the [Integrating impersonation](/authkit/impersonation/integrating-impersonation) section about how to customize your application when using impersonation. ### Deep-linking to the impersonation flow You can deep-link to the impersonation flow in the WorkOS Dashboard from your own admin tool using the following URL structure: `https://dashboard.workos.com//users//details?dialog=impersonate` ## Auditing impersonation usage User sessions that were initiated via impersonation will be clearly marked as such when viewing their details in the WorkOS Dashboard. Additionally, WorkOS emits a [`session.created`](/events/session) event which you can view under the events for the user, or listen for in your application via the [events API](/events). ![A screenshot of the User events page in the WorkOS Dashboard](https://images.workoscdn.com/images/e213fa51-4aa6-4260-8c31-84823fbcc77b.png?auto=format&fit=clip&q=80) The `session.created` event has an `impersonator` field that contains information about the impersonation session, like the `email` of your team member who performed the impersonation, along with their `reason` for doing so. ## Integrating impersonation No additional code is required to start using impersonation once you have integrated with WorkOS. However, many developers may want to augment their application's behavior when your team members are impersonating one of your users. The response from the [Authenticate with Code API](/reference/authkit/authentication/code) will include an additional `impersonator` field when the resulting session was created via impersonation, containing the impersonator's `email` and `reason` for using impersonation. Similarly, the `access_token` will include an `act` claim with the impersonator's `email`. Your application can use either in order to trigger impersonation-specific behavior. A common enhancement is to change the appearance of the application in order to make it obvious to the viewer they are currently impersonating one of your users, such as a "Staff Bar" displayed at the top of the viewport. You may also want to restrict access to sensitive views or redact certain fields in your application. ### Impersonation with `authkit-nextjs` If using the [`authkit-nextjs` library](https://github.com/workos/authkit-nextjs), impersonation can be easily added by using the provided helper component. After completing the setup instructions in the [quick start](/authkit) guide, add the Impersonation component to your app code. ```js title="Impersonation component" import { Impersonation } from '@workos-inc/authkit-nextjs'; export default function RootLayout({ children }) { return ( {children} ); } ``` The above will automatically render a visually distinct frame on your page with an option to hide it or stop the impersonation session. ![A screenshot showing the Impersonation frame rendered over a page](https://images.workoscdn.com/images/c4305ab6-d4fa-4f36-be9c-5a60ee12a7b3.png?auto=format&fit=clip&q=80) ### Identity Linking Automatic deduplication of user credentials across identity providers. ## Introduction Users have unique email addresses, because each user's access to their inbox represents ultimate access to all of their credentials and thus services they control. The [User object](/reference/authkit/user) unifies all of the identities they use so that your application does not have to consider different identity systems. Identity linking is the process in which WorkOS safely deduplicates various credentials across identity providers to offer a single, unified user interface. It does this by using the **email address** as the unique identifier and access to the email inbox as the source of truth. ## Credentials A credential is an authentication method in a specific identity provider. For example, WorkOS offers a [password credential](/authkit/email-password) for users to authenticate with. In this case, WorkOS is the identity provider and password is the authentication method. [Google OAuth](/authkit/social-login) is another credential, where Google is the identity provider and OAuth is the authentication method. Users may use multiple types of authentication methods based on preference, perhaps because one is more convenient to use on one of their devices, or they simply didn't remember which method they used in the past. ## Email verification WorkOS ensures all user emails are unique via an [email verification process](/authkit/email-verification). By default, email verification is required by all users for authentication to succeed. This ensures that verified users are always returned to your application. When a user signs in with a new credential for the first time, e.g. they sign in through Google OAuth despite already having a password account, WorkOS will safely attach the new credential to the existing user. This is only performed if WorkOS can verify that the user has access to the email inbox referenced by that credential. WorkOS considers it a **security risk if the user cannot verify access to their email**. Some identity providers allow creating accounts with any email address. For instance, an IT contact of an organization with the domain `apple.com` could make an account for `billg@microsoft.com`. If access to `billg@microsoft.com` is not verified, the IT contact could sign in to the application as that user. > WorkOS does not complete the authentication flow when a new identity cannot be safely linked to an existing user to ensure account takeover risks are minimized. ## Domain verification When an IT contact [verifies a domain for their organization](/authkit/domain-verification), it means they have access to create email inboxes. Thus, a **verified domain implies the ability to verify all users with that email domain**. In practice, when a domain is verified and an SSO connection is configured, users who sign in through an organization's IdP are automatically considered email verified if the domain matches. This shortcut reduces friction for your end users. > Users who sign-in through SSO with an email address that is not a verified domain are not considered verified and will have go through the [email verification](/authkit/email-verification) process. ## SSO identity linking Not only can a user have multiple credentials, they may also have multiple SSO credentials. This might happen when a user works with multiple organizations that require SSO authentication for all members. In this case, there is still only one [User object](/reference/authkit/user), but they would choose which organization's SSO IdP to use when authenticating. ![Example UI showing organization selection](https://images.workoscdn.com/images/876aeb05-cd96-46b4-9adf-3e9dd0208e47.png?auto=format&fit=clip&q=80) The email verification safety still applies. When the user signs-in for the first time through an SSO IdP where the user's email address is not a verified domain, the user is asked to verify their email before the SSO credential is linked to their account. Users without a verified domain **must be invited to the organization** before they have access via SSO for the first time. > An [invitation](/authkit/invitations) ensures that the authentication flow gives the user an opportunity to go to the SSO's identity provider. ### Hosted UI Customizable sign-in UI that abstracts away all of the complexity associated with building secure authentication flows. ## Introduction Implementing authentication flows that handle every possible error state and edge case across multiple identity providers can be a daunting task. AuthKit makes this easy by providing a hosted, pre-built, customizable authentication UI with automatic handling of: - Sign up, sign in, password reset, and [email verification](/authkit/email-verification) flows. - Enterprise [SSO](/authkit/sso) routing and [MFA](/authkit/mfa) enrollment. - Automatic bot detection and blocking, to protect against brute force attacks. - Customizable [domain](/custom-domains/authkit) and [branding](/authkit/branding). ![AuthKit sign-in UI](https://images.workoscdn.com/images/4d736ca3-eec8-4a90-bd14-2530c4210415.png?auto=format&fit=clip&q=80) ## Authentication flow AuthKit is conceptually similar to a [Social Login (OAuth)](/authkit/social-login) experience, but with the added benefit of being able to authenticate users with any identity provider. AuthKit sits outside of your application code. When a user initiates a sign-in request, your application redirects them to the AuthKit URL. The user then completes the authentication process with WorkOS before being returned to the application. Your application will exchange the resulting authorization code to retrieve an authenticated [User object](/reference/authkit/user) and handle the session. ![AuthKit authentication flow diagram](https://images.workoscdn.com/images/0b3265fa-a209-4ca7-beaf-7d2514a3e00a.png?auto=format&fit=clip&q=80)\[border=false] > The AuthKit flow abstracts away many of the UX and WorkOS API calling concerns automatically, for more guidance on integrating with AuthKit, see the [Quick Start](/authkit) guide. AuthKit also provides a signup flow for creating users. Available options are determined by the configured [authentication methods](/authkit/hosted-ui/authentication-methods). If a user's email address is associated with an SSO connection, they will automatically be redirected to sign up via their IdP. ## Authentication methods AuthKit's hosted UI supports all of the authentication methods available and will automatically adjust the available options depending on the configured methods in the _Authentication_ section of the [WorkOS Dashboard](https://dashboard.workos.com). ![Dashboard displaying available authentication methods](https://images.workoscdn.com/images/ea3b2c3b-723e-462c-aa10-6b1cec1b635f.png?auto=format&fit=clip&q=80) Email + Password authentication is enabled by default, though set up may be required to enable additional methods. See the relevant feature section for more information: - [Single Sign-On](/authkit/sso) - [Email + Password](/authkit/email-password) - [Social Login](/authkit/social-login) - [Multi-Factor Auth](/authkit/mfa) - [Magic Auth](/authkit/magic-auth) ## Localization By default, AuthKit's hosted UI is automatically localized into many global languages. Your users will be served in the locale that closest matches their device's OS preference. All user-facing text, including error messages and transactional emails, are translated into the user's native tongue. In cases where a user's browser does not send their preferred locale, or when AuthKit cannot identify a match, the user is served in the environment's **fallback language**. The fallback language can be configured [in the dashboard](https://dashboard.workos.com/environment/authentication/features) in the _Authentication > Features > Localization_ section. ![With localization, you can change the environment's fallback language](https://images.workoscdn.com/images/bb8c017b-f9cd-4882-baa2-b38e01a51875.png?auto=format&fit=clip&q=50) ## Integrating Integration into your app is quick and easy, though the route you choose varies depending on your specific requirements: ### (A) Integrate with AuthKit's Hosted UI In just a few lines of code, you can add AuthKit to your app and start authenticating users. See the [quick start](/authkit) guide for more information. ### (B) Build your own authentication flows While the hosted solution is the fastest way to get started, if you'd prefer to build and manage your own authentication UI, you can do so via the [AuthKit API](/reference/authkit). Examples of building custom UI are [available on GitHub](https://github.com/workos/authkit). ### Groups Organize organization members into groups for easier management. ## Introduction Groups let you organize [organization memberships](/authkit/users-organizations) into named collections within an organization. An organization membership represents a single user's access to an organization. A group represents a logical subset of members. A user can belong to zero or more groups. Groups are native to WorkOS and managed by your application through the API. This is distinct from [directory groups](/directory-sync), which are provisioned by an external identity provider through SCIM. ## Why use groups? Groups give you a way to model users within teams, departments, or any organizational unit. For example, you might create an "Engineering" group or a "Finance" group to reflect your customer's organizational structure. Groups unlock capabilities across the WorkOS platform: - **[Group role assignments](/authkit/group-role-assignments)** — assign roles to a group and have them apply to all of its members automatically. - **[Resource-scoped access control](/authkit/group-role-assignments)** — grant resource-scoped roles from [FGA](/fga) to a group so all members inherit access to the same resources. ## Managing groups Groups are managed entirely through the API. You can view the full [Group object](/reference/groups) in the API reference. > Groups is currently API-only. If you're interested in managing groups through the WorkOS Dashboard, we'd love to hear from you. Please reach out at [support@workos.com](mailto:support@workos.com). ### Creating and updating groups Create a group within an organization using the [create group API](/reference/groups/create). Each group has a name and belongs to a single organization. You can update a group's name using the [update group API](/reference/groups/update), or remove it entirely with the [delete group API](/reference/groups/delete). ### Adding members Add an organization membership to a group using the [add group member API](/reference/groups/add-member). Adding a member that already belongs to the group is a no-op, the API returns successfully without creating a duplicate. ### Listing members Retrieve a paginated list of organization memberships in a group using the [list group members API](/reference/groups/list-members). ### Listing groups for a member Retrieve a paginated list of groups that an organization membership belongs to using the [list groups for organization membership API](/reference/authkit/organization-membership/list-groups). ### Removing members Remove an organization membership from a group using the [remove group member API](/reference/groups/remove-member). Removing a member deletes the group membership. The organization membership and the group are unaffected. ## Cascade behavior Group memberships are automatically cleaned up when the underlying organization membership or organization is removed: - **Deleting an organization membership** removes group memberships for the organization membership. - **Deleting a user** removes all of the user's organization memberships, which in turn removes all associated group memberships. - **Deleting an organization** removes all group memberships before removing the groups themselves. > No manual cleanup is needed. WorkOS handles cascade deletion to keep group membership data consistent. ## Events Group lifecycle changes emit [`group.*` events](/events/group) that can be used to trigger workflows in your application or received via [webhooks](/events/data-syncing/webhooks). You can view these events on the [events page](https://dashboard.workos.com/environment/events) of the dashboard. ### Group Role Assignments Assign roles to groups so all members automatically inherit the role and its permissions. ## Introduction Group role assignments let you assign a role to a [group](/authkit/groups) so that every member of that group automatically receives the role and its permissions. When you add or remove members from the group, their roles update accordingly. This eliminates the need to manage role assignments on a per-user basis. --- ## How it works A group role assignment connects a group to a role. WorkOS automatically reconciles the roles for all members of the group: - **Assign a role to a group** — all current members receive the role - **Add a member to the group** — the new member receives all roles assigned to the group - **Remove a member from the group** — the member loses any roles they received from that group - **Remove a group role assignment** — all members lose the role that came from that assignment In [multiple-roles mode](/authkit/roles-and-permissions/multiple-roles), roles sourced from group role assignments are additive. A user's effective permissions are the union of all roles from direct assignment and group assignment. In single-role mode, the highest-priority role wins across all sources. If a group role was the highest-priority role and the assignment is removed, the member's role resets to the [default role](/rbac/configuration/configure-roles/default-role) for the organization. When you assign or remove a role from a group, WorkOS reconciles the roles for all group members asynchronously. There may be a brief delay between the API call and the roles being fully propagated to all members. Adding or removing individual members from a group reconciles that member's roles synchronously. The updated roles take effect before the API response is returned. --- ## Assigning a role to a group When you assign a role to a group without specifying a resource, every member of that group receives the role. These roles behave the same as directly assigned roles — they appear in the [session token](/authkit/sessions/integrating-sessions/access-token) and are enforced through the standard [RBAC](/rbac) system. To create a group role assignment, use the [create group role assignment API](/reference/groups/role-assignment/create). --- ## Resource-scoped assignments Group role assignments can also target a specific [FGA resource](/fga/resources), granting members of the group a role on that resource. This is useful for giving an entire team access to a workspace, project, or any other resource in your authorization model. You can identify the target resource using either: - `resource_id` — the WorkOS resource ID (`authz_resource_...`) - `resource_type_slug` + `resource_external_id` — a combination of the resource type and your external identifier Resource-scoped role assignments are checked through the [Authorization API](/fga/access-checks). Permissions propagate down to child resources via [permission inheritance](/fga/roles-and-permissions), just like directly assigned resource-scoped roles. Resource-scoped roles are always additive, regardless of whether you are using single-role or multiple-roles mode. To create a resource-scoped group role assignment, use the [create group role assignment API](/reference/groups/role-assignment/create) with the resource fields. --- ## Managing group role assignments ### Listing assignments Retrieve all role assignments for a group using the [list group role assignments API](/reference/groups/role-assignment/list). ### Removing assignments Remove a specific assignment by ID using the [remove group role assignment API](/reference/groups/role-assignment/remove-group-role-assignment), or remove by criteria (role and optional resource) using the [remove group role assignments API](/reference/groups/role-assignment/remove-group-role-assignments). When a group role assignment is removed, all members lose the role that came from that assignment. Any roles from other sources (direct assignment or other groups) remain intact. --- ## Single vs. multiple roles Group role assignments work in both single-role and [multiple-role](/authkit/roles-and-permissions/multiple-roles) modes: - **Single-role mode**: The highest-priority role wins across all sources (direct and group). If a group role assignment grants a higher-priority role than the member's current role, it takes effect. If that assignment is later removed, the member's role resets to the [default role](/rbac/configuration/configure-roles/default-role). - **Multiple-roles mode**: All applicable group roles are granted to the member. The member's effective permissions are the union of all assigned roles. --- ## Cascade behavior Group role assignments are automatically cleaned up in these scenarios: - **Deleting a group** removes all role assignments for that group and revokes the associated roles from all members. - **Removing a member from a group** revokes any roles that member received from that group's assignments. --- ## Example: department-level roles Consider an application where you want all members of the finance department to have the `billing-admin` role: 1. [Create a group](/reference/groups/create) named "Finance" in the organization 2. [Add members](/reference/groups/add-member) to the group for each finance team member's organization membership 3. [Assign the role](/reference/groups/role-assignment/create) `billing-admin` to the group Every member of the "Finance" group now has the `billing-admin` role. When a new team member joins, adding them to the group grants the role automatically. When someone leaves the team, removing them from the group revokes the role. --- ## API reference For the full API specification, see the [Group Role Assignment API reference](/reference/groups/role-assignment). ### Example apps View sample AuthKit apps. You can view minimal example apps that demonstrate how to use AuthKit to authenticate users: ### Staging vs. production environments Understand the differences between staging and production environments, when to use each, and how to go live. ## Introduction WorkOS provides two separate environments — **staging** and **production** — so you can build and test your integration before going live. This guide explains the differences between them, when to use each, and how to transition from staging to production. Every WorkOS workspace includes a staging environment and a production environment. These are fully separate: API keys, organizations, connections, users, webhook endpoints, and [branding](/authkit/branding) are all scoped to a single environment and don't carry over between them. Environments live inside a [project](/authkit/projects). A few settings — such as feature flags — are shared across all environments in a project rather than scoped to a single environment. Branding is configured per environment, so you can use different logos, colors, and themes in staging and production. To avoid setting it up from scratch, you can [copy branding](/authkit/branding) from another environment. ## When to use staging Use the staging environment when you're: - **Evaluating WorkOS** for the first time and exploring the API - **Building your integration** locally or in a development environment - **Testing Single Sign-On, Directory Sync, or other enterprise features** using the built-in test identity provider (IdP) - **Running automated tests** or CI pipelines against WorkOS - **Demoing your integration** to internal stakeholders before launch Staging is free. No connections in staging incur charges, regardless of type. ## When to use production Use the production environment when you're: - **Serving real end users** who need to authenticate or connect via Single Sign-On - **Onboarding enterprise customers** with live identity provider connections - **Deploying to a customer-facing URL** with HTTPS Production requires adding billing information in the [WorkOS Dashboard](https://dashboard.workos.com/). Enterprise connections (such as SAML-based Single Sign-On or SCIM-based Directory Sync) in production incur per-connection charges. AuthKit is free for up to 1 million monthly active users (MAUs), after which usage-based pricing applies. OAuth connections and all staging connections are free. > If you're building an app that only uses AuthKit for username/password authentication with no Single Sign-On connections, you won't incur any charges in production as long as you stay under 1 million monthly active users. However, you still need to add billing information to unlock the production environment. See [pricing](https://workos.com/pricing) for details. ## Key differences | Feature | Staging | Production | | -------------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------- | | **Redirect URIs** | Allows `http://` and `localhost` for local development | Requires `https://` for web apps; `http://127.0.0.1` is still allowed for native clients | | **API keys** | Reviewable in the dashboard | Shown once at creation — store securely | | **Custom domains** | Uses WorkOS domains | Can use [custom domains](/custom-domains) | | **Billing** | No charges | Enterprise connections incur charges; AuthKit free up to 1M MAUs | | **Test identity provider** | Built-in test IdP available | No test IdP — use real connections | | **Rate limits** | Same as production | Same as staging | | **Branding** | Set independently from production | Set independently from staging | ## What to set up in production Staging and production are separate environments. Nothing carries over automatically. When you switch to production, you'll need to set up the following: - **API keys and Client IDs** — see [API authentication](/reference/api-authentication) - **Redirect URIs** — see [Redirect URI requirements](/reference/authkit/authentication/get-authorization-url/redirect-uri) - **Branding** — configure your logo, colors, and theme for the production environment; see [Branding](/authkit/branding) - **Organizations and connections** — if you're using SSO or Directory Sync - **Webhook endpoints and secrets** — if your integration consumes WorkOS events; see [Webhooks](/reference/webhooks) - **Custom domains** — if you want to use them in production; see [Custom domains](/custom-domains) ## Going live Every integration should do the following: 1. **Verify your integration works end-to-end in staging.** For most workflows, staging is sufficient to fully validate your integration before touching production. 2. **Unlock production** by adding billing information in the [WorkOS Dashboard](https://dashboard.workos.com/). 3. **Generate your production API key** and store it securely. Production API keys can only be viewed once. See [API authentication](/reference/api-authentication). 4. **Note your production Client ID** and update your app's environment variables. 5. **Configure production redirect URIs** for your application. For most web apps these must use `https://`. See [Redirect URI requirements](/reference/authkit/authentication/get-authorization-url/redirect-uri). 6. **(Optional) Set up [custom domains](/custom-domains)** for AuthKit, Admin Portal, or the Authentication API. 7. **Test the full authentication flow in production** before sending real traffic there. If you're using enterprise features like SSO or Directory Sync, you'll also need to: 1. **Recreate organizations and connections** in production for your live customers. 2. **Set up production webhook endpoints** and store the new signing secret if your integration consumes WorkOS events. See [Webhooks](/reference/webhooks). 3. **Generate Admin Portal links** for customer IT contacts to self-configure their connections if you're using self-serve setup. For the full Single Sign-On launch checklist, see the [SSO launch checklist](/sso/launch-checklist). > Avoid configuring test SAML providers in production. Test providers may display generic or placeholder company names to your users, and any enterprise connections in production may count toward billing — even test ones. Do all SSO testing in staging. ## Frequently asked questions ### Do I need a separate WorkOS account for staging and production? No. Both environments are included in a single WorkOS workspace. ### Can I have multiple staging or production environments? Yes. Every workspace starts with a staging and production environment, but you can add more. Additional environment creation may be available directly in your dashboard settings. If you don't see the option, contact [support](mailto:support@workos.com) to have one created. ### Can I copy data from staging to production? Not currently. Staging and production are fully isolated, and there isn't a built-in way to promote or migrate organizations, connections, or users between them today. When you're ready to go live, you'll need to recreate your organizations and connections in the production environment. Your end users will re-authenticate through AuthKit, which creates their accounts in production automatically. Branding is the exception. You can [copy branding](/authkit/branding) from one environment to another. ### Can I convert a staging environment to a production environment? Not self-serve. If you've accidentally been serving live traffic from a staging environment, contact [support](mailto:support@workos.com) for assistance. To avoid this situation, keep staging for development and testing only — staging environments are not intended for customer-facing traffic per the [Terms of Service](https://workos.com/terms). ### What features are only available in production? Almost everything works identically across both environments. The main differences are: - [Custom domains](/custom-domains) for AuthKit, Admin Portal, and the Authentication API are only available in production environments. - SSO and Directory Sync connections in staging are not billed, so you can test freely. ### Is it safe to use real OAuth credentials in staging? Yes. You can safely configure real OAuth provider credentials (Google, Microsoft, GitHub, etc.) in your staging environment for testing. Staging environments are fully functional and secure — the only limitations are the production-only features listed above. ### Can I move an environment between workspaces? No. Environments are tied to a specific workspace and can't be transferred. ### Can I move an environment to a different project? Environments can only be moved into a **new** project at creation time — transferring into an existing project isn't supported yet. Additionally, the source project can't have [project-level configuration](/authkit/projects), such as feature flags, that can't yet be copied to the new project. See [Projects](/authkit/projects) for details. ### Email Verification Learn more about the email verification process. ## Introduction Email verification is a process in which a new user must validate ownership of their email inbox before they can access the application, ensuring authenticity of inbox ownership. ## The email verification flow Verification is a two-step process: - A user signs up to your application and an email is sent with a verification code. - The user inputs the verification code to complete the signup process. This applies to all authentication methods including [OAuth](/authkit/social-login) and [SSO](/authkit/sso). This unifying interface simplifies how your application considers the authenticity of your users. **Email verification is always on** to ensure that verified users are always returned to your application. ## Users with verified email domains Users signing in with SSO with a [verified domain](/authkit/domain-verification) are automatically considered verified and do not need to complete the email verification process. ## Sending verification emails [AuthKit](/authkit) automatically handles email verification out of the box. When a user signs up via the hosted signup form, AuthKit will automatically send the verification email, prompt the user to input the code and route them through the authentication process before they gain access to the application. If desired, you can [send these emails yourself](/authkit/custom-emails). If a verification email bounces or is blocked, the recipient's address may be added to your provider's suppression list, preventing future deliveries. See [Check suppression status](/email/e-check-suppression-status) to check and resolve suppressions. ### Email + Password Configuring email and password authentication and requirements. ## Introduction Email + Password authentication allows users to sign up and sign in to your application using an email address and password combination. This is one of the most common forms of authentication and is enabled by default. ## Password configuration In the majority of cases, no additional configuration is required. However, depending on your application's security requirements you may wish to modify the password strength policy. ### Modifying the password strength policy A strong set of password rules are applied to all users by default. This ensures that: - All passwords meet a minimum required length - Low complexity passwords are rejected - Breached passwords (flagged by [haveibeenpwned](https://haveibeenpwned.com)) are rejected These defaults are recommended in the majority of cases, however, if you wish to modify the password policy you can do so in the _Authentication_ section of the [WorkOS dashboard](https://dashboard.workos.com). You can enable password history to prevent password reuse. When modifying your policy, you can reject up to 10 of each user's most recently used previous passwords. Password history is disabled by default. AuthKit will enforce your policy within the sign up and password reset flows. ![Dashboard password strength policy](https://images.workoscdn.com/images/d9ab3375-78b8-4dc4-a15c-76af2fad671e.png?auto=format&fit=clip&q=80) ### Disabling Email + Password Disabling this method entirely will prevent users from signing up or signing in using a password. This is useful when you want to restrict access to your application to only those users who have been provisioned via SSO. --- ## Integrating via the API If you'd prefer to build and manage your own authentication UI, you can do so via the AuthKit [Authentication API](/reference/authkit/authentication). Examples of building custom UI are also [available on GitHub](https://github.com/workos/authkit). ### Domain Verification Verify organization domains for secure authentication and provisioning. ## Introduction Domain verification allows IT contacts to prove they control specific domains. This allows WorkOS to trust actions from users with the verified domain and enables authentication and membership policy enforcement for those users. Verifying an organization domain enables the following features: 1. Users with the verified domain who sign in with the organization's SSO connection don't need to [verify their email](/authkit/email-verification). 2. By default, users with the verified domain are managed by the organization's [domain policy](/authkit/organization-policies/domain-policy), allowing for enhanced control over authentication and membership. ## Self-serve domain verification Domain verification can be delegated to the [Admin Portal domain verification flow](/domain-verification). This out-of-the-box UI guides IT contacts to add a DNS TXT record to prove domain ownership. Once the DNS TXT record is correctly added, the organization domain is automatically verified. ## Manual domain verification Verified domains may also be added manually via the [WorkOS Dashboard](https://dashboard.workos.com) or [API](/reference/organization/update). This shortcut is useful if the IT contact has already proven domain ownership in another context. > Manually verified domains can be used to define a domain policy that applies to any users with email addresses on that domain. The organization that defines this [domain policy](/authkit/organization-policies/domain-policy) exerts authentication policy control over that domain across your application. For this reason, it is important to verify ownership of manually added domains. Additionally, WorkOS does not allow addition of common consumer domains, like `gmail.com`. ![Adding a verified domain in the dashboard](https://images.workoscdn.com/images/c015b42d-fc39-453c-a4c9-1be220c88a37.png?auto=format&fit=clip&q=80) ### Directory Provisioning Manage users and organization memberships via directory sync providers. > Please reach out to [support@workos.com](mailto:support@workos.com) or via your team's WorkOS Slack channel if you would like Directory Provisioning enabled. ## Introduction Directory provisioning gives IT contacts full control over user and membership management, eliminating the need for manually adding or removing members. Users from a directory are pre-provisioned and managed by their [Identity Provider](/glossary/idp). ## Initial configuration A [Directory Sync](/directory-sync) integration will need to be configured for every organization that wants to source users and memberships via directory provisioning. Directories can be set up via the [WorkOS Dashboard](https://dashboard.workos.com/) with [Setup Links](/admin-portal/a-setup-link-from-workos-dashboard). You can also [integrate the Admin Portal with your app](/admin-portal/b-integrate-with-your-app) to generate links to configure directories. ### Supported directory providers Directory provisioning is supported for all SCIM directory providers, Google Workspace, and SFTP. ## Provision users from a directory Users provisioned through a directory with an email domain matching a verified organization domain will be automatically added as members of the organization, without needing an invitation. Other users are created with `pending` memberships and receive an email [invitation](/authkit/invitations) to join the organization. Pending members cannot sign in until the invitation is accepted, at which point they become active organization members. > [Invitation emails](/authkit/custom-emails/disabling-default-emails) can be disabled if you prefer to manage invitations with a custom approach. ## Manage users from a directory In addition to provisioning new users, any updates to existing users and de-provisioning events will be reflected in AuthKit. Users with email addresses matching one of the organization's verified domains are fully managed by the directory. Updates to their attributes from the directory will override changes made through SSO, the API, or manually in the dashboard. > If multiple organizations with directory provisioning contain the same verified domain, the user's name will always reflect the most recent directory update. Other users, with email domains not verified by the organization, will not be fully managed by the directory, so updates made via SSO, API, or manually in the dashboard will persist. When a user is de-provisioned in the directory, the [status](/reference/authkit/organization-membership) of their corresponding organization membership will be set to `inactive`. While the user will no longer be able to sign in to the organization, the membership and user are not automatically deleted. If a user is re-provisioned in the directory, their organization membership will be reactivated with its previous role and its [status](/reference/authkit/organization-membership) will be set to `active`. ## Custom attributes When using directory provisioning, [custom attributes](/directory-sync/attributes) configured on directory users are available on the corresponding organization membership. This allows you to access IdP-sourced attributes like department, job title, and cost center directly from the [membership object](/reference/authkit/organization-membership) or in [JWT templates](/authkit/jwt-templates). When a directory user's attributes are updated, the changes are automatically reflected on the linked organization membership's `custom_attributes`. > If the membership is also linked to an [SSO Profile](/reference/sso/profile), the directory user's custom attributes take precedence. ## Directory provisioning actions Below is a list of directory provisioning and deprovisioning actions and the corresponding changes triggered in AuthKit. If you're using standalone Directory Sync, refer to the [standalone Directory Sync documentation](/directory-sync/api-overview/directory). Actions depend on the user's email domain: - A user is domain-managed when their email domain matches one of the [organization's verified domains](/reference/domain-verification). These users are fully managed by the directory. - A user is a domain guest when their email domain does not match one of the [organization's verified domains](/reference/domain-verification). Changes only impact the linked organization membership. | Directory Action | Changes triggered in WorkOS | Event(s) Emitted | | ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | Directory user provisioned | [User](/reference/authkit/user) and [organization membership](/reference/authkit/organization-membership) objects created. Domain-managed users are created with an active status, while domain guest users are invited to the organization with a pending status. | [user.created](/events/user), [organization\_membership.created](/events/organization-membership) | | Directory user info updated | For domain-managed users, any updates to the user's name will be reflected on the [user](/reference/authkit/user) object. Otherwise, the user object will not be modified. User email address is always immutable. The user's organization membership role will be re-synced to match the IdP role assignment. | [user.updated](/events/user), [organization\_membership.updated](/events/organization-membership) | | Directory user with active membership deprovisioned | Organization membership deactivated and all sessions for the user are revoked. Their role is reset to the default role. | [organization\_membership.updated](/events/organization-membership) | | Directory user with pending membership deprovisioned | Organization membership deleted. | [organization\_membership.deleted](/events/organization-membership) | | Directory user reactivated | Organization membership reactivated. | [organization\_membership.updated](/events/organization-membership) | --- ## Frequently asked questions ### I am using directory provisioning, but some directory users aren't being provisioned in AuthKit. Why would a directory user not be provisioned in AuthKit? Directory users need to have a primary email address to be provisioned in AuthKit. If the directory user is missing a primary email, they won't be provisioned. Additionally, if the primary email of a directory user is shared by another directory user, only one will be provisioned in AuthKit, as emails are unique to AuthKit users. ### If a user's email is changed in the directory, will this change be reflected on the user's email in WorkOS? The email address on the [User object](/reference/authkit/user) is immutable, but the email on the underlying [directory user](/reference/directory-sync/directory-user) object will be modified. ### Why is there a distinction between domain-managed users and domain guest users? For domain-managed users, the organization has proven they own the email domain through [domain verification](/authkit/domain-verification), and therefore have full control over the user's account and email. This allows the directory to manage all aspects of the [user object](/reference/authkit/user). For domain guests, the organization has not proven ownership of the user's email domain. As a result, the organization only has the ability to manage data within the scope of the organization itself, represented by the [organization membership object](/reference/authkit/organization-membership). ### Why aren't organization memberships deactivated when a directory is deleted? User deprovisioning and directory deletion have different behaviors because they serve different use cases. Deactivating all users is typically an off-boarding task that affects the entire organization, not just the directory. By leaving memberships active when a directory is deleted, customers can switch directory providers without the disruption of deactivating all memberships. ### Custom Emails Learn how to send your own emails for user lifecycle events. ## Introduction By default, WorkOS will send emails related to AuthKit for you, such as password reset and Magic Auth. If you'd like to customize email content or have more control over deliverability, you can turn off the default emails and deliver your own emails using the WorkOS API. --- ## Disabling default emails To change email settings for an environment, navigate to [_Emails_ → _Configuration_](https://dashboard.workos.com/environment/emails/configuration) and select _Manage_. You should have an **Admin** role to update this setting. ![A screenshot showing the WorkOS Dashboard configuration card for emails](https://images.workoscdn.com/images/2b83140f-a458-4c9c-a778-f92863bccbba.png?auto=format&fit=clip&q=80) ![A screenshot showing the WorkOS Dashboard dialog for email settings](https://images.workoscdn.com/images/ac757dde-b1c1-4564-b33d-2d8438fcc7ca.png?auto=format&fit=clip&q=80) --- ## Invitations Once you've turned off the default user invitation emails, use the information below to send custom invitation emails. **[invitation.created](/events/invitation)** : Event emitted when an invitation is created, which can be consumed using the events API or webhooks. **[Get Invitation API](/reference/authkit/invitation/get)** : Used to retrieve the invitation object from the ID in the invitation created event. **[Send Invitation API](/reference/authkit/invitation/send)** : Used to create an invitation via the API without handling the invitation created event. ### Set up your user invitation URL Make sure you have the correct user invitation URL set by navigating to [_Applications_](https://dashboard.workos.com/environment/applications) → your application → _Redirects_ in the dashboard. The default setting is the AuthKit URL for accepting invitations. If you are using your own authentication UI, make sure the URL path is configured on your end to capture the `invitation_token` query parameter, and [pass it into one of the authenticate methods](/reference/authkit/authentication/code). ![A screenshot showing the WorkOS Dashboard configuration card for user invitation URL](https://images.workoscdn.com/images/4cff773d-4ef7-431a-95e6-83d232efe911.png?auto=format&fit=clip&q=80) ### (A) Handle manually creating invitations If you're creating invitations using the WorkOS dashboard, you'll need to handle `invitation.created` events using the events API or webhooks. Due to security concerns, the events do not contain the sensitive information you'll need to send the email. To retrieve the full invitation object with this information, use the invitation ID from the event to call the Get Invitation API. You can skip this step if you don't plan to create the invitations manually in the dashboard. ### (B) Handle invitations created via the API If you're creating invites via the Send Invitation API, you can send your own email using the information returned in the invitation object. If you also plan to create invitations manually in the dashboard, you can just handle `invitation.created` events as described above. ### Send your email The recipient of the email should match the `email` attribute in the invitation object retrieved via the API. The body of the email should include a link where the user can accept the invitation. For most use cases, you can use the `accept_invitation_url` as this link. If you are building your own authentication app, and your invitation acceptance path diverges from this pattern, you may want to construct your own URL with the `token`, rather than using the `accept_invitation_url`. Additionally, if the invitation object contains an organization ID and/or an inviter user ID, you may want to include that information in the body of the email. --- ## Magic Auth Once you've turned off the default Magic Auth emails, use the information below to send custom Magic Auth emails. **[magic\_auth.created](/events/magic-auth)** : Event emitted when a user initiates a Magic Auth authentication, which can be consumed using the events API or webhooks. **[Get Magic Auth API](/reference/authkit/magic-auth/get)** : Used to retrieve the Magic Auth object from the ID in the Magic Auth created event. **[Create Magic Auth API](/reference/authkit/magic-auth/create)** : Used to create a Magic Auth code via the API without handling the Magic Auth created event. ### (A) Handle Magic Auth codes created via AuthKit If you are using AuthKit, you'll need to handle `magic_auth.created` events, using the events API or webhooks. Due to security concerns, the events do not contain the sensitive information you'll need to send the email. To retrieve the full Magic Auth object with this information, use the Magic Auth ID from the event to call the Get Magic Auth API. You can skip this step if you're building your own authentication app. ### (B) Handle Magic Auth codes created via the API If you're initiating Magic Auth authentication via the Create Magic Auth API, you can send your own email using the information returned in the Magic Auth object. ### Send your email The recipient of the email should match the `email` attribute for the Magic Auth object retrieved via the API, and the email should include the `code`. Recipients will input that code into AuthKit, or your own authentication UI, to authenticate into your application via Magic Auth. --- ## Email verification Once you've turned off the default email verification emails, use the information below to send custom email verification emails. **[email\_verification.created](/events/email-verification)** : Event emitted when a user requires email verification, which can be consumed using the events API or webhooks. **[Get Email Verification API](/reference/authkit/email-verification/get)** : Used to retrieve the email verification object from the ID in the email verification created event. **[Email Verification Required error](/reference/authkit/authentication-errors/email-verification-required-error)** : Returned in the API when attempting to authenticate a user that requires email verification. ### (A) Handle email verification codes created via AuthKit If you are using AuthKit, you'll need to handle `email_verification.created` events, using the events API or webhooks. Due to security concerns, the events do not contain the sensitive information you'll need to send the email. To retrieve the full email verification object with this information, use the email verification ID from the event to call the Get Email Verification API. You can skip this step if you're building your own authentication app. ### (B) Handle email verification codes created via the API If you are using the [authentication API](/reference/authkit/authentication), an `email_verification_required` error will be returned if the user you're authenticating needs to verify their email. This error contains an `email_verification_id` that can be used to call the Get Email Verification API endpoint which returns the email verification object that contains the information needed to send the email. ### Send your email The recipient of the email should match the `email` attribute for the email verification object retrieved via the API, and the email should include the `code`. Recipients will input that code into AuthKit, or your own authentication UI, to verify their email. --- ## Password reset Once you've turned off the default password reset emails, use the information below to send custom password reset emails. **[password\_reset.created](/events/password-reset)** : Event emitted when a user requests to reset their password, which can be consumed using the events API or webhooks. **[Get Password Reset API](/reference/authkit/password-reset/get)** : Used to retrieve the password reset object from the ID in the password reset created event. **[Create Password Reset API](/reference/authkit/password-reset/create)** : Used to create a password reset object via the API without handling the password reset created event. ### Set up your password reset URL Make sure you have the correct password reset URL set by navigating to [_Applications_](https://dashboard.workos.com/environment/applications) → your application → _Redirects_ in the dashboard. The default setting is the AuthKit URL for resetting passwords. If you are using your own authentication UI, make sure the URL path is configured on your end to capture the `token` query parameter, and [use it to reset the password](/reference/authkit/password-reset/reset-password). ![A screenshot showing the WorkOS Dashboard configuration card for password reset URL](https://images.workoscdn.com/images/a1f26490-f263-4688-bfcd-910359563bff.png?auto=format&fit=clip&q=80) ### (A) Handle password resets created via AuthKit If you are using AuthKit, you'll need to handle `password_reset.created` events, using the events API or webhooks. Due to security concerns, the events do not contain the sensitive information you'll need to send the email. To retrieve the full password reset object with this information, use the password reset ID from the event to call the Get Password Reset API. You can skip this step if you're building your own authentication app. ### (B) Handle password resets created via the API If you're creating password resets via the Create Password Reset API, you can send your own email using the information returned in the password reset object. ### Send your email The recipient of the email should be the `email` attribute in the password reset object retrieved via the API. The body of the email should include a link where the user can reset their password. For most use cases, you can use the `password_reset_url` as this link. If you're building your own authentication app, and your password reset path diverges from this pattern, you may want to construct your own URL with the `password_reset_token`, rather than using the `password_reset_url`. ### Custom Email Providers Learn how to send emails through your own email service provider. ## Introduction By default, WorkOS will send emails via our default email service provider, either through our domain or through your own [custom email domain](/custom-domains/email). If you would like to have more control over deliverability, reputation, and compliance, while still offloading the heavy lifting of email handling, you can configure a custom email provider. This option is also ideal if you already have an existing email service provider configuration. --- ## Configure a custom email provider To configure a custom email provider for an environment, navigate to [_Emails_ → _Providers_](https://dashboard.workos.com/environment/emails/providers) and click _Enable_ next to the provider you would like to use and enter the required information. > If the email service provider you'd like to use is not listed, please [contact support](mailto:support@workos.com). ![A screenshot showing the WorkOS Dashboard email providers page](https://images.workoscdn.com/images/660bd317-6240-40ce-8cb7-d80dccac294a.png?auto=format&fit=clip&q=80) ### Amazon SES To connect WorkOS to Amazon SES, you'll need to [create an IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html) with an access key, and [verify email sending identities](https://docs.aws.amazon.com/ses/latest/dg/creating-identities.html). Ensure the IAM user has a policy like the following: ```json { "Version": "2012-10-17", "Statement": [ { "Sid": "SendEmailAccess", "Effect": "Allow", "Action": "ses:SendEmail", "Resource": [ "arn:aws:ses:::identity/*", "arn:aws:ses:::configuration-set/*" ] }, { "Sid": "IdentityManagementAccess", "Effect": "Allow", "Action": ["ses:GetIdentityVerificationAttributes", "ses:ListIdentities"], "Resource": "*" } ] } ``` You'll need to update the resource scope with your Amazon SES region and account ID. For additional ways to restrict access, refer to the [Amazon SES documentation](https://docs.aws.amazon.com/ses/latest/dg/control-user-access.html). > If you're interested in using temporary security credentials to access Amazon SES, please [contact support](mailto:support@workos.com). Once you have an IAM user with the necessary permissions and have verified sending identities, you can configure the Amazon SES custom email provider in the [WorkOS Dashboard](https://dashboard.workos.com/): ![A screenshot showing the WorkOS Dashboard Amazon SES custom email provider configuration](https://images.workoscdn.com/images/4df55e43-d68c-410c-9452-32978e0ca874.png?auto=format&fit=clip&q=50) ### Mailgun Before configuring the Mailgun custom email provider in WorkOS, you'll need to [verify your domain in your Mailgun account](https://help.mailgun.com/hc/en-us/articles/32884700912923-Domain-Verification-Setup-Guide). Once you've verified a domain, you'll need an API key, which you can create on the [API Security page of the Mailgun dashboard](https://app.mailgun.com/settings/api_security). The API key is used to validate verified domains in your account and send emails. ![A screenshot showing the Mailgun API Security page](https://images.workoscdn.com/images/fc6d06dd-790e-419e-ba0d-5a1783e8748d.png?auto=format&fit=clip&q=80) Once you've verified your domain and obtained an API key, you can configure the Mailgun custom email provider in the [WorkOS Dashboard](https://dashboard.workos.com/): ![A screenshot showing the Mailgun custom email provider configuration](https://images.workoscdn.com/images/5e287a26-7851-49f5-95b5-bc74ab58b506.png?auto=format&fit=clip&q=80) ### Postmark Before configuring the Postmark custom email provider in WorkOS, you'll need to [verify sender signatures in your Postmark account](https://postmarkapp.com/developer/user-guide/managing-your-account/managing-sender-signatures). Once you've verified a sender signature, you'll need an account and server token, which you can find on the [API Tokens page of the Postmark dashboard](https://postmarkapp.com/account/api-tokens). ![A screenshot showing the Postmark API Tokens page](https://images.workoscdn.com/images/e441ca41-2768-4887-83f1-8f298ab25847.png?auto=format&fit=clip&q=50) The account token is used to validate sender signatures in your account, and the server token is used to send emails. Once you've verified your sender signature and obtained your account and server token, you can configure the Postmark custom email provider in the [WorkOS Dashboard](https://dashboard.workos.com/): ![A screenshot showing the Postmark custom email provider configuration](https://images.workoscdn.com/images/21f94d07-b661-4a24-9e2b-940cd0bbfdaa.png?auto=format&fit=clip&q=50) Upon enabling the Postmark custom email provider, a WorkOS transactional message stream with the ID `workos-transactional-s` will be created for you. All WorkOS emails will be sent using this message stream. ### Resend Before configuring the Resend custom email provider in WorkOS, you'll need to [verify domains in your Resend account](https://resend.com/docs/dashboard/domains/introduction). Once you've verified your domain, you'll need to create an API key with the "Full access" permission on the [Resend API Keys page](https://resend.com/api-keys). ![A screenshot showing creating an API key in the Resend dashboard](https://images.workoscdn.com/images/ce0ae76c-7ab4-4506-9e48-78a61243a42d.png?auto=format&fit=clip&q=50) "Full access" permission is required to fetch verified domains and send emails. Once you've verified your domain and obtained an API key, you can configure the Resend custom email provider in the [WorkOS Dashboard](https://dashboard.workos.com/): ![A screenshot showing the Resend custom email provider configuration](https://images.workoscdn.com/images/25efadf6-405f-416b-aaa0-7e7fb266034a.png?auto=format&fit=clip&q=50) ### SendGrid Before configuring the SendGrid custom email provider in WorkOS, you'll need to verify your domain in the [Sender Authentication settings in your SendGrid dashboard](https://app.sendgrid.com/settings/sender_auth). Once you've verified your domain, you'll need to create an API key under _Settings_ → _API Keys_ in the [SendGrid dashboard](https://app.sendgrid.com/settings/api_keys). ![A screenshot showing the SendGrid API Keys side panel](https://images.workoscdn.com/images/61bf31b4-0e7f-4616-988f-69319d542866.png?auto=format&fit=clip&q=50) For API key permissions, select "Full Access" for Mail Send, and "Read Access" for Sender Authentication. Once you've verified your domain and obtained an API key, you can configure the SendGrid custom email provider in the [WorkOS Dashboard](https://dashboard.workos.com/): ![A screenshot showing the SendGrid custom email provider configuration](https://images.workoscdn.com/images/4502c8ad-2bdf-481b-82a7-0d8829032da4.png?auto=format&fit=clip&q=50) --- ## Re-enable the WorkOS default provider At any time when you are using a custom email provider, you can re-enable the WorkOS default provider by navigating to [_Emails_ → _Providers_](https://dashboard.workos.com/environment/emails/providers) and clicking _Enable_ next to the WorkOS provider. ![A screenshot showing re-enabling the WorkOS default provider](https://images.workoscdn.com/images/7b4f4713-3381-49aa-b77c-679c9698b429.png?auto=format&fit=clip&q=80) Alternatively, you can also remove your current custom email provider, which will automatically re-enable the WorkOS default provider. ![A screenshot showing removing a custom email provider](https://images.workoscdn.com/images/7b4f4713-3381-49aa-b77c-679c9698b429.png?auto=format&fit=clip&q=80) --- ## Frequently asked questions ### What types of emails are sent through custom email providers? All transactional emails for your users will be sent through your custom email provider when configured. This includes AuthKit invitations and magic codes, Radar challenges, and Admin Portal notification emails. ### If I am using a custom email provider, do I need to set up a custom email domain in WorkOS? No. When using a custom email provider, you configure the sending domain in that provider, not in WorkOS. Any custom email domain set up in WorkOS will not be used. ### What happens if emails fail to send via my custom email provider? If emails fail to send via your custom email provider, you will be notified according to your notifications preferences via the [WorkOS Dashboard](https://dashboard.workos.com/), email, or Slack. You can also utilize the [_Emails_ → _Events_ page](https://dashboard.workos.com/environment/emails/events) in the WorkOS Dashboard to track email delivery failures. Additionally, repeated delivery failures may cause the provider to suppress the recipient's email address. See [Check suppression status](/email/e-check-suppression-status) for how to check and resolve suppressions. ### Connect Enable other applications to access your users and their identities. ## Introduction Connect is a set of controls and APIs that developers can use to allow different types of applications to access their users' identity and resources. Connect is built on top of industry-standard specifications like OAuth 2.0 and OpenID Connect in order to support many common use-cases out of the box. Unlike AuthKit's other features that help users sign into **your application**, Connect enables **other applications** to authenticate and access your users' data through secure, managed APIs. ## Common use-cases **Customer applications** : Enable your customers to build custom integrations with your platform. This can include allowing them to add a "Sign in with \[your app]" button on their login page. **Auxiliary applications** : Allow secondary applications that support your primary application, such as support tools or discussion forums, to authenticate using the same user identities in AuthKit. **Partner integrations** : Issue credentials for trusted partners to authenticate with when calling your application's API. ## Getting started Each Connect integration is defined as an Application, which can be created inside of the WorkOS Dashboard. When creating an application, you first choose the type of integration: **OAuth** or Machine-to-Machine (**M2M**). ### OAuth applications Select OAuth when building web or mobile applications where the actor being authenticated is a [User](/reference/authkit/user). Integrating with an OAuth application uses the underlying `authorization_code` OAuth flow which is supported by many libraries and frameworks out of the box. Upon successful authorization, the issued tokens will contain information about the user who signed in. [Learn more about OAuth applications →](/authkit/connect/oauth) ### M2M applications Select M2M when the application will be a third-party service, such as one of your customer's applications. Integrating with an M2M application uses the underlying `client_credentials` flow. Unlike OAuth applications, the actor being authenticated is not an individual user. Instead issued access tokens will contain an `org_id` claim which represents the customer you are granting access to via the M2M application. The M2M application will use its `client_id` and `client_secret` to authenticate requests to your application's API or services. [Learn more about M2M applications →](/authkit/connect/m2m) ## Concepts All Connect applications share the following concepts: ### Participants When using Connect, there are several actors involved with the integration of each Application: - **Relying Party**: The application that receives Connect-issued tokens and identity information. It may also use the access token to make requests to your API. - **Resource server**: The service (generally your app) that allows other clients to authenticate using the Connect-issued tokens. - **Authorization server**: This is Connect, the issuer of identity and access tokens to requesting clients after authenticating the user. ### Credentials Applications can have up to 5 credentials. These are only shown once upon creation and do not expire. The application `client_id` and `client_secret` from a credential can be used to authenticate to the [Connect APIs](/reference/workos-connect). When sharing app credentials with an external party, use a secure method — like encrypted email or file sharing — and make sure the recipient is properly authenticated. ### AI Installer & CLI Integrate AuthKit with one command, manage resources, provision environments, and equip your coding agents — all from the WorkOS CLI. ## Introduction The WorkOS CLI is a comprehensive tool for integrating and managing WorkOS from the terminal. Its headline feature is the **AI Installer** — run one command and it handles framework detection, SDK installation, route creation, environment setup, and build validation. Beyond the installer, the CLI also manages resources, provisions environments, and equips your coding agents with WorkOS knowledge. --- ## AI Installer Run one command, the CLI handles the rest. Your app goes from zero auth to full AuthKit integration in about two minutes. ```bash $ npx workos@latest install ◆ Detected Next.js 15.3.1 (App Router) │ ◇ Opening browser for WorkOS authentication... │ Authenticated as nick@example.com │ ◇ Configuring your WorkOS dashboard... │ ✓ Redirect URI set to http://localhost:3000/callback │ ✓ Homepage URL set to http://localhost:3000 │ ◇ Installing @workos-inc/authkit-nextjs... │ ✓ Package installed │ ◇ Analyzing project structure... │ ✓ Created /app/callback/route.ts │ ✓ Created proxy.ts │ ✓ Updated /app/layout.tsx with AuthKitProvider │ ✓ Created .env.local │ ◇ Validating integration... │ ✓ Build completed successfully │ ◆ AuthKit is ready. Run `npm run dev` to get started. ``` > **Prefer to configure things yourself?** Follow one of our [framework-specific guides](/authkit/landing/or-install-using-your-preferred-stack) instead. ### What the installer handles The installer takes care of everything you would normally do manually: 1. **Detects your framework** — Identifies your framework and version from your project's dependencies and file structure 2. **Authenticates your account** — Opens your browser for secure WorkOS sign-in 3. **Configures your dashboard** — Sets redirect URIs, CORS origins, and homepage URL automatically 4. **Installs the right SDK** — Adds the correct AuthKit package for your framework 5. **Analyzes your project** — Reads your project structure to understand routing, existing middleware, and configuration 6. **Creates routes and middleware** — Writes OAuth callback routes, auth middleware/proxy, and provider wrappers 7. **Sets up environment variables** — Writes API keys and configuration to `.env.local` 8. **Validates the integration** — Runs your build to verify everything compiles without errors The installer understands framework-specific nuances — like Next.js App Router vs Pages Router, Vite vs Create React App, and React Router nuances — and generates the appropriate code for your setup. If you have existing middleware or configuration, it composes with it rather than replacing it. ### Supported frameworks | Framework | SDK | | ----------------------- | ------------------------------------ | | **Next.js** | `@workos-inc/authkit-nextjs` | | **React** | `@workos-inc/authkit-react` | | **React Router** | `@workos-inc/authkit-react-router` | | **TanStack Start** | `@workos-inc/authkit-tanstack-start` | | **SvelteKit** | `@workos-inc/authkit-sveltekit` | | **Node.js / Express** | `@workos-inc/node` | | **Vanilla JS** | `workos` | | **Python / Django** | `workos` (pip) | | **Ruby / Rails** | `workos` (gem) | | **Go** | `github.com/workos/workos-go` | | **PHP** | `workos/workos-php` | | **PHP / Laravel** | `workos/workos-php-laravel` | | **.NET / ASP.NET Core** | `WorkOS.net` | | **Kotlin** | `com.workos:workos-kotlin` | | **Elixir / Phoenix** | `workos` (hex) | ### How the installer works The CLI uses an AI agent with restricted permissions to integrate AuthKit into your project: 1. **Local analysis** — The agent reads your project files locally to detect frameworks and understand your project structure. 2. **Restricted execution** — The agent can only run a limited set of commands: package installation, builds, type-checking, and formatting. It cannot run arbitrary shell commands. 3. **File modifications** — The agent creates and edits files in your project to set up the AuthKit integration. Use `git diff` after installation to review every change. 4. **Dashboard configuration** — The CLI configures your WorkOS dashboard settings (redirect URIs, CORS) using your authenticated session. ### Install options | Flag | Description | | ---------------------- | --------------------------------------------------------------------- | | `--integration ` | Skip auto-detection and specify your framework manually | | `--redirect-uri ` | Custom OAuth callback URI (default: `http://localhost:3000/callback`) | | `--no-validate` | Skip post-install build validation | | `--debug` | Verbose logging for troubleshooting | --- ## Coding agent skills Install WorkOS knowledge directly into your AI coding agent so it understands AuthKit when helping you write code. Skills give agents context about WorkOS APIs, SDKs, and integration patterns — so they produce correct integration code without you having to explain WorkOS concepts. ```bash $ workos skills install Installing skills... ✓ Installed 2 skill(s): workos-authkit → Claude Code workos-authkit → Cursor Done! ``` Supported agents: | Agent | Skills directory | | --------------- | ------------------------ | | **Claude Code** | `~/.claude/skills` | | **Codex** | `~/.codex/skills` | | **Cursor** | `~/.cursor/skills` | | **Goose** | `~/.config/goose/skills` | Use `workos skills list` to see available and installed skills, and `workos skills uninstall` to remove them. --- ## Manage resources The CLI provides full CRUD operations for WorkOS resources directly from the terminal — organizations, users, roles, permissions, connections, directories, webhooks, vault secrets, feature flags, and more. ```bash $ workos org create "Acme Corp" acme.com Created organization { "id": "org_01J...", "name": "Acme Corp", "domains": ["acme.com"] } ``` ```bash $ workos role list Slug Name Type Permissions Created ───────────────────────────────────────────────────────── admin Admin environment 8 3/16/2026 viewer Viewer environment 2 3/16/2026 ``` All resource commands support `--json` for scripting and CI pipelines. In non-TTY environments (pipes, CI runners, coding agents), JSON output is enabled automatically. --- ## Workflow commands Compound commands that compose multiple API calls for common tasks. ### Declarative provisioning with `seed` Define your permissions, roles, organizations, and config in a YAML file and provision them in one command. The CLI tracks state so you can tear everything down cleanly with `--clean`. ```yaml title="workos-seed.yaml" permissions: - name: 'Read Users' slug: 'read-users' - name: 'Write Users' slug: 'write-users' roles: - name: 'Admin' slug: 'admin' permissions: ['read-users', 'write-users'] - name: 'Viewer' slug: 'viewer' permissions: ['read-users'] organizations: - name: 'Acme Corp' domains: ['acme.com'] config: redirect_uris: ['http://localhost:3000/callback'] cors_origins: ['http://localhost:3000'] homepage_url: 'http://localhost:3000' ``` ```bash $ workos seed Created permission: read-users Created permission: write-users Created role: admin Set permissions on admin: read-users, write-users Created role: viewer Set permissions on viewer: read-users Created org: Acme Corp (org_01J...) Seed complete. State saved to .workos-seed-state.json ``` ### Other workflow commands | Command | Description | | --------------------------------- | ---------------------------------------------------------------------------------------- | | `workos setup-org ` | Create an org with optional domain verification, roles, and Admin Portal link | | `workos onboard-user ` | Send an invitation with optional role assignment — use `--wait` to poll until acceptance | | `workos debug-sso ` | Inspect SSO connection state and recent auth event history | | `workos debug-sync ` | Inspect directory sync state, user/group counts, and detect stalls | --- ## Environments Manage multiple WorkOS environments, switch between them, and authenticate — all from the terminal. ```bash $ workos auth login Starting authentication... Open this URL in your browser: https://dashboard.workos.com/... Waiting for authentication... Authentication successful! Logged in as nick@example.com ``` ```bash $ workos env list Name Type ──────────────────────────────── ▸ production Production staging Sandbox local Sandbox ``` Use `workos env switch` to change environments and `workos env add` to configure new ones. Run `workos doctor` to diagnose integration issues in the current project — it checks your SDK version, environment configuration, connectivity, dashboard settings, and auth patterns. --- ## Prerequisites - Node.js 20+ - A [WorkOS account](https://dashboard.workos.com) - A project using one of the [supported frameworks](#supported-frameworks) (for the AI installer) --- ## Troubleshooting ### The installer didn't detect my framework Use the `--integration` flag to specify your framework manually: ```bash npx workos@latest install --integration nextjs ``` ### Build validation failed Run the installer with `--debug` for detailed output. Make sure your project builds cleanly before running the installer — pre-existing build errors will cause validation to fail. ```bash npx workos@latest install --debug ``` ### I want to see what changed After the installer completes, use `git diff` to review all the files it created or modified: ```bash git diff ``` ### Something else went wrong Run `workos doctor` to diagnose common issues. If the problem persists, [open an issue on GitHub](https://github.com/workos/cli/issues) with the output from `--debug` mode. --- ## What's next - [Sessions](/authkit/sessions) — Understand session management - [Branding](/authkit/branding) — Customize the AuthKit UI - [Example Apps](/authkit/example-apps) — View complete working examples - [Quick Start](/authkit) — Manual integration guide for full control ### CLI Auth Quickly add authentication to your command-line application. ## Introduction CLI Auth enables your command-line applications to authenticate users through the web via your WorkOS app. Based on the [OAuth 2.0 Device Authorization Flow](https://datatracker.ietf.org/doc/html/rfc8628), this flow is optimized for devices that lack a web browser or have limited input capabilities. With CLI Auth, your command-line app requests a device authorization from WorkOS, which includes a code for the user and a code for your app. After the user confirms the code, your app can exchanges its device code for tokens. ## (1) Request device authorization To begin the authentication flow, your CLI application makes a request to the `/authorize/device` endpoint to obtain the necessary codes and URLs for user authentication. After you get a response, your app can provide next steps to the user. ![Screenshot of a command-line application showing login information](https://images.workoscdn.com/images/89680848-5c40-4ba1-860f-a7212cfbb47b.png?auto=format&fit=clip&q=50) Your application should display the `user_code` from the response, along with the `verification_uri` in the terminal. If you offer the ability to open in a browser easily like in this screenshot, we suggest using the `verification_uri_complete` for that. Never display the `device_code` to the user. That is only for the device to poll the token endpoint. ## (2) User confirms the code Next the user needs to confirm the code in their browser. ### (A) Manual code entry If the user navigates to the `verification_uri`, they'll be presented with a form to enter the code manually. If they are not logged in they'll be prompted to do that first and then returned to the code entry screen. ![Screenshot of the manual-code-entry form in AuthKit](https://images.workoscdn.com/images/03c1961a-547a-4886-bb9a-2f080dd31ca9.png?auto=format&fit=clip&q=50) ### (B) One-click confirmation If the user goes to the `verification_uri_complete`, (for example, `https:///device?user_code=ABCD-EFGH`, they'll instead need to confirm that the code matches what is displayed in the terminal. ![Screenshot of the pre-filled code-confirmation form in AuthKit](https://images.workoscdn.com/images/3e02f36c-0dea-4ff4-9dc5-a2f2fa964114.png?auto=format&fit=clip&q=50) ## (3) Request tokens While the user is completing authentication in their browser, your CLI application should poll the token endpoint to check for authorization completion. Make requests to the token endpoint using `device_code` from the authorization response from step 1: ### Polling best practices - Poll at the interval specified in the authorization response (every 5 seconds) - Respect `slow_down` errors by increasing your polling interval - Stop polling when you receive `access_denied` or `expired_token` errors - Implement a reasonable timeout to avoid infinite polling ## Connect CLI Auth is available for [Connect](/authkit/connect/oauth) applications, allowing you and third-party developers to build CLI tools that integrate with your app's credentials. The flow is the same but uses Connect endpoints: - **Authorization**: `https:///oauth2/device_authorization` - **Token**: `https:///oauth2/token` Since command-line applications are distributed to end users, you should avoid embedding the client secret in the app. To make this work, set up your Connect app as a [_Public_ application](/authkit/connect/oauth/public-applications). Third-party Connect applications will require users to [grant consent](/authkit/connect/oauth/first-party-vs-third-party-applications) to the third-party app. ### Branding Customize AuthKit to fit natively with your app's unique design. ## Introduction You can customize the look and feel of AuthKit via the _Branding_ section of the [WorkOS Dashboard](https://dashboard.workos.com/branding). The brand editor allows you to: - Upload logos and favicons - Set brand colors for buttons, links, and backgrounds - Manage visual properties such as page layouts, corner radius, and dark mode appearance - Include custom copy, images, and links to your app's terms-of-service and privacy policy - Preview auth screens and emails in various languages, and translate custom text into every supported locale The AuthKit preview will update in real-time as you make changes and accurately reflect the available authentication methods, giving you a clear picture of the authentication experience with AuthKit. ![Branding in the dashboard](https://images.workoscdn.com/images/b97f7b25-9c67-42b1-8c7d-f4c5a34b1a4e.png?auto=format&fit=clip&q=50) ## Environment scope Branding is configured per environment, so each environment has its own logo, colors, and theme. A staging environment can look different from production, and each [project](/authkit/projects) (a grouping of environments for one product) can present its own brand. ### Copy branding between environments To avoid setting up branding from scratch in a new environment, copy it from an existing one. WorkOS loads the copied logo, colors, theme, and other settings into the brand editor before saving, so you can adjust anything before it goes live. This is useful for testing a branding change in staging before applying it to production. ![Copy from environment action highlighted in the brand editor](https://images.workoscdn.com/images/04d501f8-9d99-4ab5-8126-f85c0f30d532.png?auto=format&fit=clip&q=50) ![Copy branding diff dialog open in the brand editor](https://images.workoscdn.com/images/3e3c9195-3003-4908-93a6-3a47d3485576.png?auto=format&fit=clip&q=50) ## Global styles Global styles define your brand's visual identity and apply across AuthKit, transactional emails, and the [Admin Portal](/admin-portal). ### Display name The display name controls the product name shown to your users. It defaults to your team name, but can be customized to more accurately reflect your product name. It appears in the following surfaces (may not be an exhaustive list): - **AuthKit**: User invitation acceptance and [Waitlist](/authkit/waitlist) pages - **Transactional emails**: User invitation, Magic Auth, email change, Waitlist confirmation, [Radar](/authkit/radar) notification, and Radar challenge emails - **[Admin Portal](/admin-portal)**: Organization setup page and Domain Verification, Single Sign-On, Directory Sync, Log Streams, and Bring Your Own Key setup flows ![Display name highlighted in the brand editor](https://images.workoscdn.com/images/7a40e26e-080a-4b29-bb4b-4675a61b0dc4.png?auto=format&fit=clip&q=50) ### Corner radius The corner radius applied to UI elements can be configured; a lower value results in a more formal aesthetic while a higher value has a more rounded, playful feel. ### Assets There are three types of assets you can upload: 1. **Logo:** Your full size brand logo, styles vary but this would typically include the wordmark. Must be at least 160x160 px (JPG, PNG, or SVG. 100 KB max size) 2. **Logo icon:** A smaller, square version of the logo. This is often simply the logomark. Must be at least 160x160 px with a 1:1 aspect ratio (JPG, PNG, or SVG. 100 KB max size) 3. **Favicon:** A small icon that serves as branding for your website. It is often displayed in the browser tab alongside the address bar. Must be at least 32x32 px with a 1:1 aspect ratio (JPG, PNG, GIF, SVG, WebP, AVIF, or ICO. 100 KB max size) ![Asset options highlighted in the brand editor](https://images.workoscdn.com/images/4c6de40f-f53f-467f-812d-61bb8133f1b9.png?auto=format&fit=clip&q=50) ### Color You can control four colors across light and dark mode: - Page background color - Button background colors - Button text color - Link color Other colors used in the UI, like the focus outline, hover styles, or borders, are created automatically based on the four colors you provide, ensuring a consistent look and feel. ![Color options in the brand editor](https://images.workoscdn.com/images/ba598fe5-ca6e-4c31-bb43-f5f1ba7541fe.png?auto=format&fit=clip&q=50) ## AuthKit styles The following settings apply to AuthKit only. ### Preferred appearance AuthKit supports both light and dark mode; each brand configuration option is split across both so that they can be configured independently. You can enforce a specific appearance, or allow the user's OS system settings to determine which to use. ### Font family You can customize the font family used across AuthKit pages to match your brand's typography. The font family selector allows you to choose from a wide variety of Google Fonts to align with your product's brand. Only Google Fonts are supported for font family customization. This ensures optimal loading performance and reliability across all devices and browsers. ### Logo display AuthKit can display your full logo, just the logo icon, or no logo at all, selected from the _Logo display_ dropdown. Showing the logo or logo icon requires the corresponding [asset](#assets) to be uploaded. ![Logo display select open in the brand editor](https://images.workoscdn.com/images/b669888e-6054-4a89-a5ad-790b828935ca.png?auto=format&fit=clip&q=50) ### Custom copy The page title, sign-in link text, and sign-up link text on the sign-in and sign-up pages can be customized to fit your brand's tone of voice. They can be edited directly inside the AuthKit preview pane. > The sign-in and sign-up links are what users click to switch between the two pages. For example, a user on the sign-in page who doesn't yet have an account clicks the sign-up link to reach the signup page. Start by selecting the page you want to edit. Then, click on the text you want to change from the preview pane. ![AuthKit page selector in the brand editor](https://images.workoscdn.com/images/3c36aba4-94e5-4622-8c51-4cfdd2c4c373.png?auto=format&fit=clip&q=50) ![Text customization highlighted in the brand editor](https://images.workoscdn.com/images/34083f85-324e-494b-8c82-0c6516e49946.png?auto=format&fit=clip&q=50) When you edit copy in English, it automatically gets translated into [every supported language](/authkit/hosted-ui/localization). A loading indicator appears next to the language picker during this process. After you save, your users will be served the translation that closest matches their locale. ### Page layout The layout for sign-in and sign-up pages can be customized to fit your brand's needs. Choose a layout in the _Page Settings_ panel: a centered, one-column layout, or a two-column split layout with a secondary content panel you customize using [custom HTML and CSS](#content-panel-details-and-limitations). ![Page layout in the brand editor](https://images.workoscdn.com/images/b1c540c0-ef8e-484e-a675-eef96c04341f.png?auto=format&fit=clip&q=50) The split layout's content panel is useful for marketing content or decorative elements. To set one up, select the page you want to customize and choose the _Split_ option. The panel can be positioned to the left or right of the primary panel, and optionally hidden on mobile devices. ![Split layout content panel setting in the brand editor](https://images.workoscdn.com/images/338b8624-7e6f-46ec-ad5b-5c9d6eba2044.png?auto=format&fit=clip&q=50) Click the content panel in the preview pane to open a dialog where you can enter your HTML and CSS. > Note: content in the content panel will not automatically be [localized](/authkit/hosted-ui/localization). ![Content panel editor dialog in the brand editor](https://images.workoscdn.com/images/cc404828-cf7d-4af5-9ee2-b7245b91ce3e.png?auto=format&fit=clip&q=50) #### Content panel details and limitations Any HTML and CSS entered into the content panel dialog will only be applied to the content panel on the selected page. This allows you a high level of flexibility without impacting content elsewhere on the page. For security purposes, all code input is sanitized and stripped of any potentially harmful elements. This means that you can't use JavaScript or any other dynamic content in your HTML. This includes `script`, `iframe`, `form`, and `object` elements—as well as inline event handlers for any elements. For example, the following code will be sanitized from this: ```html

Welcome to SuperApp

``` …to this: ```html

Welcome to SuperApp

``` HTML `style` elements will also be removed to prevent overriding any content outside of the content panel. All custom CSS should be entered into the CSS editor. CSS selectors will be scoped to the content panel via [CSS nesting](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting/Using_CSS_nesting). For compatibility with older browsers, we use a light transform step to convert the nested CSS to a flat structure. For example, the following CSS will be transformed from this: ```css h1 { color: var(--primary-color); } ``` …to this: ```css :where([data-hak-custom-html]) h1 { color: var(--primary-color); } ``` ### Sign-up fields The sign-up form can optionally include first and last name fields, toggled in the _Page Settings_ panel. ![Sign-up fields in the brand editor](https://images.workoscdn.com/images/da97a746-513c-421b-8886-faff7079f374.png?auto=format&fit=clip&q=50) ### Last used sign-in badge The sign-in page can optionally display a _Last used_ badge on an authentication method. This will indicate the most recent sign-in method for the user. The badge is shown by default and only shown when multiple sign-in methods are available. ![AuthKit Last used sign-in badge](https://images.workoscdn.com/images/2f0e3778-08f3-4eb4-b590-0b39ff92e0d7.png?auto=format&fit=clip&q=50) ### Legal links The sign-in and sign-up pages can optionally display a link to your app's privacy policy and/or terms-of-service, shown below the authentication form. This can be configured in the _Page Settings_ panel. ![Terms of service and privacy policy links in the brand editor](https://images.workoscdn.com/images/4df58a8e-4677-4453-9e15-4daed3a79f4d.png?auto=format&fit=clip&q=50) ## AuthKit custom CSS For more granular control over AuthKit branding, element styles can be overridden using custom CSS. Custom CSS applies globally across all AuthKit pages to ensure consistency across the entire authentication experience. It does not affect emails or Admin Portal. > AuthKit is powered by [Radix](https://www.radix-ui.com/) which has built-in accessibility and dark mode. If overriding styles, please make sure to test thoroughly, especially if removing original element styles. ![AuthKit Custom CSS in the brand editor](https://images.workoscdn.com/images/0f48c7f3-b99c-417a-bee9-2e54780515df.png?auto=format&fit=clip&q=80) ### Customize a specific page Target specific pages using the `data-hak-page` attribute selector: ```css .ak-Header { /* focus-start */ [data-hak-page='sign-up'] & { .ak-Heading { font-size: 3rem; line-height: 1; } } /* focus-end */ } ``` **`device/denied`** : Device connection denied **`application-authorization`** : App consent/authorization page **`default-redirect`** : Default redirect after successful auth **`not-found`** : 404 error page **`auth-disabled`** : Authentication disabled message ### Light and dark theme Use the [light-dark](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark) CSS function to easily target both light and dark themes with a single declaration: ```css .ak-PrimaryButton { /* focus-start */ color: light-dark(#333333, #f0f0f0); /* focus-end */ } ``` For more control, target the parent theme selectors directly: ```css .ak-Background { /* focus-start */ .dark-theme & { background: linear-gradient(0deg, #333, #111); } .light-theme & { background: linear-gradient(0deg, #fff, #ccc); } /* focus-end */ } ``` > Media queries targeting `prefers-color-scheme` are not supported – use only the `.dark-theme` and `.light-theme` selectors. ### Nested selectors AuthKit provides intelligent autocomplete support for CSS selectors. When you type a period (`.`) in the custom CSS editor, a popover will automatically appear showing available nested selectors for AuthKit elements, making it easier to target specific components and their child elements. ![Nested CSS selectors](https://images.workoscdn.com/images/e8e41033-9e08-40c5-bfc9-0e223b1bd890.png?auto=format&fit=clip&q=80) ### Examples #### Custom background image You can use external images as background images by specifying the URL in the `background-image` property. ```css .ak-Background { /* focus-start */ background-image: url('https://i.imgur.com/HO2EBgR.jpeg'); background-size: cover; /* focus-end */ } ``` #### Reorder OAuth buttons You can target an individual provider button by its `data-method` attribute. ```css .ak-AuthButton { /* focus-start */ /* Display Microsoft OAuth button first */ &[data-method='microsoft'] { order: -1; } /* focus-end */ } ``` #### Adding custom text Use CSS pseudo-elements to add custom text content. Custom text content in CSS cannot be [localized](/authkit/hosted-ui/localization). To learn how to automatically localize the text of your custom headings and links, read the [custom copy](#custom-copy) section. ```css .ak-Header { /* focus-start */ &::after { content: 'Sub heading'; display: block; } /* focus-end */ } ``` > Some elements may already style the `::before` and `::after` pseudo-elements, so test your changes carefully. ## Localization You can preview how your auth pages and emails appear in various different languages. AuthKit is [localized](/authkit/hosted-ui/localization) in many languages by default, and users are served in their preferred language automatically. To preview your brand in different languages, use the language picker in the AuthKit preview pane. ![A preview of a user-facing email, translated in Spanish](https://images.workoscdn.com/images/663ee483-a14c-420b-9ba5-5c4c1f277b2c.png?auto=format&fit=clip&q=50) ## Custom domains WorkOS supports custom domains for both email and [ACS URLs](/glossary/acs-url). For information, see the [custom domains documentation](/custom-domains). ### Applications Manage authentication across every surface your product runs on with a shared identity layer. ## Introduction ### Single Application A default application is automatically generated for each environment. If your product only has one client, no action is needed. You can see and set your application's API keys, Redirects and Sessions configuration in the Applications section of the [WorkOS Dashboard](https://dashboard.workos.com/get-started). ### Multiple Applications Multiple Applications lets developers define each client as its own application object within an environment in the [WorkOS Dashboard](https://dashboard.workos.com/get-started). Each application gets its own client ID, session configuration, redirect URIs, and credentials, while sharing the same underlying user base. Users and organizations are shared across applications with a unified login experience, without duplicate accounts or fragmented identity data. ## Use cases **One product spanning multiple client surfaces** : Web app + mobile app + desktop client: model all three surfaces explicitly, each with platform-appropriate behavior. **Multiple products with a shared user base** : App A + App B + App C: define each as its own application with appropriate session lifetimes and redirect URIs. ## Caveats Multiple Applications is not the right fit for every scenario. Two common cases where a different approach is better: ### Separate user bases If you need entirely separate user bases, use separate environments instead. Each environment maintains its own isolated set of users and organizations. For a fully separate setup — with its own branding, configuration, and staging and production environments — use a separate [project](/authkit/projects). ### Separate branding If your goal is to present a different look and feel on the AuthKit login screen, that's a branding concern rather than an application modeling one. [Branding](/authkit/branding) for the hosted AuthKit UI is configured in the Branding section of the WorkOS Dashboard and applies to all applications in the environment. Because branding is configured per environment, a separate [environment](/authkit/environments) gives you separate branding. If you need different branding while keeping a single user base, WorkOS supports the option to [self-host your UI](/authkit/hosted-ui/integrating) and manage authentication with the AuthKit API. ## Getting started Applications are created and managed in the Applications section of the [WorkOS Dashboard](https://dashboard.workos.com/get-started). Once created, each application exposes its own configuration surface: - **Client ID** — a unique identifier for this application, used when initiating authentication flows. - **Redirect URIs** — the endpoints AuthKit will return users to after authentication. Password resets, sign-in flows, and invitation links automatically route to the correct destination for the application. - **Session policy** — configure session lifetimes appropriate for the platform. A mobile app can stay signed in longer; a web app can follow a shorter expiration window. Each application behaves according to platform expectations without affecting the others. - **Credentials and API keys** — each application manages its own credentials, making it easier to isolate client configuration while keeping all applications connected to the same identity layer. ### Default application The first application listed in the Applications section of the [WorkOS Dashboard](https://dashboard.workos.com/get-started) is the application that was automatically generated for the environment. You can think of this first application as the default application. > The default application is used for IdP-initiated SSO. ## Invitations Invitations sent via the WorkOS Dashboard are always associated with the environment's default application. Invitations sent via the API or User Management widget will preserve the application context of the API key/widget so that the invited user lands in the right place. ## Access token claims `iss` : The `iss` claim is the same for all applications in the environment. It will reference the default application's client id. `client_id` : The `client_id` claim will reflect the `client_id` for the current application context. Claims from the application context can be surfaced in the [JWT Template](/authkit/jwt-templates). ### API Keys Provide secure, self-service API key management to your customers. ## Introduction API keys provide a secure way for your application's users to authenticate with your API. With the [API Keys Widget](/widgets/api-keys), your customers can create and revoke [organization](/authkit/users-organizations/organizations)-scoped and user-scoped API keys with a simple component. The WorkOS API and SDKs provide functions for your API code to validate keys. API keys are one of two ways WorkOS enables you to issue credentials to your customers that they use to programmatically access your application. The other is [M2M applications](/authkit/connect/m2m). The [API Keys vs M2M Applications guide](https://workos.com/blog/api-keys-vs-m2m-applications) can help you decide which is best for your use case. ## Configuring API keys Before your users can manage API keys, you need to configure your WorkOS environment. ### Setting up role permissions To enable organization-scoped API key management for your users, ensure at least one role includes the `widgets:api-keys:manage` permission. To enable user-scoped API key management, use `widgets:user-api-keys:manage-self` for a user's own API keys or `widgets:user-api-keys:manage-all` for API keys across the organization. You can [assign permissions to roles](/authkit/roles-and-permissions/configure-roles-and-permissions/assign-permissions-to-roles) in the WorkOS Dashboard under _Authorization_. ### Configuring available permissions You can control which permissions your users can assign to API keys by configuring API key permissions in your environment. For example, you might create permissions like: - `posts:read` - Read access to posts - `posts:write` - Write access to posts - `users:read` - Read access to user data By configuring only `posts:read` and `posts:write` as available API key permissions, your users can create API keys with granular access controls, such as read-only keys that only have the `posts:read` permission. You can configure API key permissions in the WorkOS Dashboard under _Authorization > Configuration > Organization API key permissions_. User-scoped API keys can only use permissions that are enabled for user API keys. ## API key management in your application ### Using the API Keys Widget The easiest way to enable API key management for your users is through the [API Keys Widget](/widgets/api-keys). This widget provides a complete interface for creating, viewing, and revoking API keys. Use the default `scope="organization"` mode when users should manage API keys owned by their organization. Use `scope="user"` when users should manage API keys owned by individual users. The widget allows your users to: - Create new API keys with custom names - Select specific permissions for each key - View existing API keys (with obfuscated values for security) - Revoke API keys when they're no longer needed The widget interacts with the WorkOS API and renders the user interface in your app, so your customers get full control over their API keys in just a few lines of code. ### Managing API keys via the API You can also manage API keys programmatically using the WorkOS API. This is useful for building custom API key management interfaces or automating key lifecycle operations. - [List API keys](/reference/authkit/api-keys/list-for-organization) for an organization - [Create an API key](/reference/authkit/api-keys/create-for-organization) for an organization - [List API keys](/reference/authkit/api-keys/list-for-user) for a user - [Create an API key](/reference/authkit/api-keys/create-for-user) for a user - [Delete an API key](/reference/authkit/api-keys/delete) The full API key value is only returned in the create response. Store it securely when the key is created; subsequent list, validate, and object responses only include an obfuscated value. API key ownership is available on the `owner` field. Organization-owned keys have `owner.type: "organization"` and an organization ID in `owner.id`. User-owned keys have `owner.type: "user"`, a user ID in `owner.id`, and the organization the key can access in `owner.organization_id`. User-owned API keys are tied to the user's organization membership. If that membership is deleted, any user-owned API keys for that membership are revoked. ## Validating API keys Once API keys have been created, your application needs to validate these keys when they're used to authenticate API requests. When an API request includes an API key (typically in the `Authorization` header), your application should validate it with WorkOS to ensure it's legitimate and retrieve the associated permissions. The [validate API key endpoint](/reference/authkit/api-keys/validate) returns the complete [API key object](/reference/authkit/api-keys), including: - The organization or user that owns the key - The permissions assigned to the key - Usage metadata like creation and last-used timestamps This information allows your application to not only authenticate the request but also authorize it based on the specific permissions granted to that API key. ## Viewing API keys in the WorkOS Dashboard You can view your customers' API keys through the WorkOS Dashboard or via the API. To view organization-owned API keys: 1. Navigate to the **Organizations** section in your WorkOS Dashboard 2. Click on the organization you want to view 3. Select the **API Keys** tab To view user-owned API keys: 1. Navigate to the **Users** section in your WorkOS Dashboard 2. Click on the user you want to view 3. Select the **API keys** tab From these views, you can see API key details including names, obfuscated key values, creation dates, and last usage information. User-owned API keys also show the organization each key can access. You can also [list organization-owned API keys](/reference/authkit/api-keys/list-for-organization) and [list user-owned API keys](/reference/authkit/api-keys/list-for-user) via the API. ## Auditing API key usage API key lifecycle changes are tracked via the [`api_key.created`](/events/api-key), [`api_key.updated`](/events/api-key), and [`api_key.revoked`](/events/api-key) events. You can view these events in the [events page](https://dashboard.workos.com/environment/events) or listen for them in your application via the [events API](/events). ### Agent Registration How agents obtain identity and credentials from an AuthKit-powered service. > Agent Registration must be enabled for your environment. Contact your WorkOS account team if it is not yet available. ## Introduction Agent Registration enables AI agents and LLM-based clients to obtain identity credentials from your AuthKit-powered service. Unlike traditional OAuth flows designed for users in a browser, Agent Registration is purpose-built for programmatic clients that need machine-readable instructions, minimal interaction, and secure credential management. Agents discover the registration surface through your service's [`.well-known/oauth-authorization-server`](#discovery) metadata, register with one of several identity types, optionally bind to a user via a claim ceremony, and exchange the resulting identity assertion for an access token or API key. ## How it works ### Identity types Agent Registration supports three identity types, selected by the agent based on its context: | Type | When to use | Claim ceremony | |------|-------------|----------------| | `anonymous` | The agent has no user identity and wants to trial the service | Optional | | `service_auth` | The agent knows the user's email and needs trusted access | Required | | `refresh` | The agent's current assertion is expiring and needs rotation | Not applicable | ### Choosing identity types Your choice of identity type depends on your application's data model: - **If entities are owned by users** (e.g. a user's documents, personal settings), enable only `service_auth`. This ensures every agent is bound to a specific user through the claim ceremony before it can act on their behalf. - **If the resource owner is an organization** (e.g. shared team resources, org-wide data), `anonymous` registrations work well — agents can begin interacting with organization-scoped resources immediately and optionally bind to a user later. When enabling `anonymous`, assign it a restricted set of untrusted permissions suitable for exploration only. Sensitive operations should require trusted (post-claim) permissions so that anonymous agents cannot perform them. See [Trust levels and scopes](#trust-levels-and-scopes) for details. ### Registration flow ``` Agent AuthKit User │ │ │ │─── POST /agent/identity ─────────────────────►│ │ │ (type: service_auth) │ │ │◄── claim.token + attempt ─────────────────────│ │ │ (includes verification_uri) │ │ │ │ │ │─── "Open this link and read back the code" ──────────────────────────────►│ │ │◄── signs in, views code ──│ │◄── user reads code back ──────────────────────────────────────────────────│ │ │ │ │─── POST /agent/identity/claim/complete ──────►│ │ │ (user_code) │ │ │◄── identity.assertion ────────────────────────│ │ │ │ │ │─── POST /oauth2/token ───────────────────────►│ │ │ (assertion exchange) │ │ │◄── access_token / api_key ────────────────────│ │ │ │ │ ``` > **Note:** The registration response includes the initial `verification_uri`. The separate `POST /agent/identity/claim` endpoint is only needed if the initial attempt expires and the agent needs to start a new one. ## Discovery Agents discover your registration endpoints through a standards-based chain defined by [RFC 9728](https://workos.com/blog/introducing-rfc-9728-say-hello-to-standardized-oauth-2-0-resource-metadata): 1. Your API returns a `WWW-Authenticate` header with a `resource_metadata` parameter pointing to your Protected Resource Metadata document. 2. The agent fetches `/.well-known/oauth-protected-resource` and reads the `authorization_servers` array. 3. The agent fetches the Authorization Server metadata, which includes an `agent_auth` block with registration endpoints. ```bash # Step 1 — Your API challenges with resource_metadata WWW-Authenticate: Bearer resource_metadata="https://example.com/.well-known/oauth-protected-resource" # Step 2 — Protected Resource Document points to the AS curl https://example.com/.well-known/oauth-protected-resource { "resource": "https://example.com", "authorization_servers": ["https://authkit_domain"] } # Step 3 — AS metadata includes agent_auth curl https://authkit_domain/.well-known/oauth-authorization-server | jq .agent_auth { "skill": "https://authkit_domain/agent/auth.md", "identity_endpoint": "https://authkit_domain/agent/identity", "claim_endpoint": "https://authkit_domain/agent/identity/claim", "identity_types_supported": ["anonymous", "service_auth"] } ``` Set up the link between your protected resource and your authorization server in the WorkOS Dashboard under **Authentication → Agents → Configuration → OAuth well-known discovery**. The `skill` field in the AS metadata points to a generated `auth.md` document — a step-by-step guide with curl commands tailored to your environment's configuration. Agents can follow it directly without needing to parse this documentation. ### Hosting auth.md For agents to discover your service, host the `auth.md` file at the root of your domain (e.g. `https://example.com/auth.md`). The recommended approach is to reverse-proxy the WorkOS-hosted version so it always reflects your current configuration. Find the source URL in the WorkOS Dashboard under **Authentication → Agents → Configuration → Host auth.md**, then configure your server: ```js title="next.config.js" async rewrites() { return [{ source: '/auth.md', destination: 'https://authkit_domain/agent/auth.md', }]; } ``` ```json title="vercel.json" { "rewrites": [ { "source": "/auth.md", "destination": "https://authkit_domain/agent/auth.md" } ] } ``` ```nginx title="nginx.conf" location = /auth.md { proxy_pass https://authkit_domain/agent/auth.md; proxy_set_header Host authkit_domain; proxy_ssl_server_name on; } ``` ```js title="Cloudflare Worker" export default { async fetch(request) { const url = new URL(request.url); if (url.pathname === "/auth.md") { return fetch("https://authkit_domain/agent/auth.md"); } return fetch(request); } } ``` For Cloudflare Enterprise, skip the worker and use a [URL rewrite rule](https://developers.cloudflare.com/rules/origin-rules/tutorials/change-uri-path-and-host-header/) instead. Replace `authkit_domain` with your environment's AuthKit domain. The Dashboard provides the exact source URL and configuration snippets for your environment. > **Tip:** The hosted `auth.md` URL is public — agents can access it directly without a reverse proxy. You can test the full registration flow without setting up hosting first. ## Registering ### Anonymous registration Anonymous registration creates an identity with no user binding. The agent receives an identity assertion immediately and can optionally bind to a user later via the claim ceremony. ```bash curl -X POST https://authkit_domain/agent/identity \ -H "Content-Type: application/json" \ -d '{"type": "anonymous"}' ``` The response includes: - `identity.assertion` — a signed JWT the agent uses for credential exchange - `claim.token` — used to start a claim ceremony later (optional) - `scopes.pre_claim` — permissions available before claiming (untrusted) - `scopes.post_claim` — permissions available after claiming (trusted) ### Service auth registration When the agent knows the user's email, `service_auth` registration initiates a mandatory claim ceremony: ```bash curl -X POST https://authkit_domain/agent/identity \ -H "Content-Type: application/json" \ -d '{"type": "service_auth", "login_hint": "user@example.com"}' ``` The response includes a `claim.token` and `claim.attempt.verification_uri` — the agent presents this URI to the user to start the claim ceremony. ### Refresh When an assertion is nearing expiry, the agent rotates it using the refresh token from a previous registration or claim: ```bash curl -X POST https://authkit_domain/agent/identity \ -H "Content-Type: application/json" \ -d '{"type": "refresh", "refresh_token": ""}' ``` ## The claim ceremony The claim ceremony binds an agent registration to a user, similar to the [OAuth 2.0 Device Authorization Flow](https://datatracker.ietf.org/doc/html/rfc8628). It's required for `service_auth` and optional for `anonymous` registrations. ### (1) Start an attempt The agent mints a claim attempt using the claim token from registration: ```bash curl -X POST https://authkit_domain/agent/identity/claim \ -H "Content-Type: application/json" \ -d '{ "type": "service_auth", "claim_token": "", "login_hint": "user@example.com" }' ``` The response includes `attempt.verification_uri` — a URL for the user. ### (2) User confirms The agent presents the `verification_uri` to the user. When they open it: 1. They sign in to AuthKit (if not already authenticated) 2. The page reveals a short `user_code` 3. The user reads this code back to the agent ### (3) Complete the claim The agent submits the code along with its claim token: ```bash curl -X POST https://authkit_domain/agent/identity/claim/complete \ -H "Content-Type: application/json" \ -d '{ "claim_token": "", "user_code": "" }' ``` On success, the response contains `identity.assertion` and `identity.refresh_token` — the agent's trusted credentials. ## Credential exchange After obtaining an identity assertion (from registration or claim completion), the agent exchanges it at the token endpoint for an access token or API key: ```bash curl -X POST https://authkit_domain/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \ --data-urlencode "assertion=" ``` The credential type (access token or API key) and its lifetime are configured per environment in the WorkOS Dashboard. ### Access token claims Agent access tokens include the following claims: | Claim | Description | |-------|-------------| | `iss` | The issuer URL for the environment | | `aud` | The audience — the environment's `client_id`, or the `resource` URI if one was requested | | `sub` | The agent registration ID (e.g. `agent_reg_01ABC...`) | | `org_id` | The organization the agent is acting within | | `scope` | Space-separated list of granted permissions | | `act` | Delegation claim identifying the user who authorized the agent (e.g. `{"sub": "user_01DEF..."}`) | | `jti` | Unique token identifier | | `iat` | Issued-at timestamp | | `exp` | Expiration timestamp | The `act` claim follows the [RFC 8693 delegation pattern](https://datatracker.ietf.org/doc/html/rfc8693#section-4.1) and is present only after a successful claim ceremony binds a user to the registration. ## Validating credentials Once an agent has exchanged its assertion for a credential, your application needs to validate that credential on incoming requests. **Access tokens** — For short-lived access tokens, you can validate the JWT locally by verifying the signature and checking expiration. This avoids a network round-trip on every request. If you need to check whether a token has been revoked before expiry, call the [validate credential endpoint](/reference/agents/validate-credential). **API keys** — API keys must be validated server-side. Use the [validate credential endpoint](/reference/agents/validate-credential) to confirm the key is still active and retrieve its associated registration. ### Inspecting a registration To see full details about the agent behind a credential — its identity, organization, claim status, and timestamps — use the [get registration endpoint](/reference/agents/get-registration) with the registration ID from the access token's `sub` claim. ## Trust levels and scopes Agent Registration uses two trust levels to control API access: - **Untrusted** (pre-claim) — the default for anonymous registrations before a claim ceremony. Grants limited scopes suitable for exploration. - **Trusted** (post-claim) — granted after a successful claim ceremony. Grants full scopes. Configure which scopes map to each trust level in the WorkOS Dashboard under your environment's agent auth settings. ## Dashboard setup Configure Agent Registration in the [WorkOS Dashboard](https://dashboard.workos.com/environment/authentication/agents) under **Authentication → Agents**: ### Registrations The Registrations tab lists all agent registrations created against your environment, including their current status (`unverified`, `verified`, `expired`, `revoked`), the associated user, and the organization. ### Methods Enable the identity types agents can use to register: - **Service auth** — agents register on behalf of a user, confirming identity through a claim ceremony - **Anonymous** — agents register instantly with no credentials; users claim ownership when ready Each method can be independently enabled or disabled. ### Configuration #### Credential settings Set the credential type and lifetime for all agent registrations: - **Credential type** — choose whether the token exchange mints an **access token** (short-lived, re-mintable) or an **API key** (durable, persisted by the agent) - **Credential expiration** — the lifetime of issued credentials #### Trust level permissions Define which permissions are available at each trust level: - **Trusted permissions** — granted after a successful claim ceremony. These are the full set of permissions for verified agents. - **Untrusted permissions** — granted to anonymous registrations before a claim. Use these for limited, exploratory access. Only permissions that are [enabled for organization API keys](/authkit/api-keys/configuring-api-keys/configuring-available-permissions) appear here. To add a permission to the list, enable it under _Authorization > Configuration > Organization API key permissions_ in the Dashboard. #### Discovery The Discovery section shows: - **Host auth.md** — the source URL for your environment's generated `auth.md` skill document, with a configuration dialog showing reverse-proxy setup for Nginx, Next.js, Vercel, and Cloudflare (see [Hosting auth.md](#hosting-auth-md) above) - **OAuth well-known discovery** — the authorization server metadata URL that agents use to locate your registration endpoints ## Testing Once your environment is configured, test the full flow by prompting any AI agent: ``` Can you follow this guide to set me up with this service? https://example.com/auth.md ``` The agent will follow the instructions in `auth.md` to register and exchange its identity assertion for credentials it can use to call your API. The agent will also guide the user through the claim flow if necessary. ### Actions Customize authentication flows with your own logic. ## Introduction Actions allow you to change the behavior of various flows within the WorkOS platform including user registration and authentication using your own custom logic. When an action is configured for a particular request type, WorkOS synchronously calls the associated action endpoint and waits for a response that allows or denies the operation. When WorkOS calls an actions endpoint, the request includes contextual metadata such as the profile of the user performing the operation, the organization associated with the operation, or the IP address, all of which you can use for decisioning within the endpoint. ### Action types WorkOS allows you to configure actions that execute during various user operations: - **Authentication**: Authentication actions run after a user completes Email + Password, Magic Auth authentication, SSO, or Social Login and before they are redirected to your application. - **User registration**: User registration actions run after a user attempts to register for your application using Email + Password, Magic Auth sign up, SSO, or Social Login and before they are provisioned. ## Configuring actions To configure actions, you'll need to: - Host an actions endpoint that receives requests from WorkOS - Register your endpoints with WorkOS - Implement the custom logic of your endpoint - Test your endpoints ## Set up your endpoint Create a public endpoint that WorkOS can make requests to. This endpoint should use HTTPS and should accept POST requests with the `workos-signature` header. This header is used for verifying the request's authenticity from WorkOS. > WorkOS sends the header as `WorkOS-Signature`, but many web servers normalize HTTP request headers to their lowercase variants. --- ## Register your endpoint Set the actions endpoint URL in the [WorkOS Dashboard](https://dashboard.workos.com/). Set _Enable action_ and choose **Save changes**. ![WorkOS Dashboard Actions UI](https://images.workoscdn.com/images/84c8a62b-d8bc-4c46-8ccd-eda4c245645e.png?auto=format&fit=clip&q=80) ### Choosing error handling behavior Each actions endpoint must specify its error handling behavior. By default, if there is an issue reaching your endpoint or validating the response, WorkOS will deny the operation. If this is not the desired behavior for your use case, you can choose a different behavior depending on the action endpoint type; for example, for authentication actions, you can choose _Allow authentication_. --- ## Implement your endpoint Upon receiving a request, you should respond with an `HTTP 200 OK` as well as a valid response body to signal to WorkOS that the request was successfully handled. ### (A) Validate the requests using the SDK Before processing the request payload, verify the request was sent by WorkOS and not an unknown party. WorkOS includes a unique signature in each actions request that it sends, allowing you to verify the authenticity of the request. In order to verify this signature, you must obtain the secret that is generated for you when you set up your actions endpoint in the WorkOS dashboard. Ensure that this secret is stored securely on your actions endpoint server as an environment variable. The SDKs provide a method to validate the timestamp and signature of an actions. Examples using these methods are included below. The parameters are the payload (raw request body), the request header, and the actions secret. There is an optional parameter, tolerance, that sets the time validation for the actions request in seconds. The SDK methods have default values for tolerance, usually 3–5 minutes. ### (B) Validate the requests manually If implementing actions request validation yourself, you'll need to use the following steps: First, extract the timestamp and signature from the header. There are two values to parse from the `WorkOS-Signature` header, delimited by a `,` character. | Key | Value | | ------------------ | ----------------------------------------------------------------------------------------------- | | `issued_timestamp` | The number of milliseconds since the epoch time at which the event was issued, prefixed by `t=` | | `signature_hash` | The HMAC SHA256 hashed signature for the request, prefixed by `v1=` | To avoid replay attacks, we suggest validating that the `issued_timestamp` does not differ too much from the current time. Next, 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 actions secret as the key. The expected signature will be the hex digest of the hash. Finally, compare signatures to make sure the actions request is valid. Once you've determined the event request is validly signed, it's safe to use the event payload in your application's business logic. ### Create an IP allowlist WorkOS sends actions requests from a fixed set of IP addresses. It's recommended to restrict access to your actions endpoint to only these IP addresses: ```plain title="WorkOS IP addresses" 3.217.146.166 23.21.184.92 34.204.154.149 44.213.245.178 44.215.236.82 50.16.203.9 52.1.251.34 52.21.49.187 174.129.36.47 ``` --- ## Build the endpoint response The endpoint must respond with a signed JSON object indicating a `verdict` of `Allow` or `Deny` as well as an optional `error_message` in the event the `verdict` is `Deny`. Based on the payload data received, you can determine whether to allow or deny the operation. Each action type receives a different payload model, so be sure to handle the appropriate data in your handler. ### (A) Respond using the SDK The SDK provides a method to create the signed response. ### (B) Respond manually If implementing the construction of the actions response yourself, you'll need to use the following steps: First, store the current epoch timestamp to a variable. Next, construct the JSON response. The JSON response must contain the following: - `timestamp`: The epoch timestamp you recorded - `verdict`: Indicates whether to allow or deny the action. Allowed values: `'Allow' | 'Deny' | 'allow' | 'deny'` - `error_message`: An optional, 500 character maximum string. This should only be provided with a `verdict` of `deny` or `Deny` Next, construct the signature. The expected signature is computed from the concatenation of: 1. The current epoch timestamp 2. The `.` character 3. The JSON response body as a utf-8 encoded string Hash the string using HMAC SHA256, using the actions secret as the key. The expected signature will be the hex digest of the hash. Finally, the endpoint should respond with a JSON object containing the following properties: - `object`: `'authentication_action_response' | 'user_registration_action_response'` - `payload`: The JSON response you formed above - `signature` The hex digest of the hash you created above ## Test your endpoint From the dashboard, you can send test actions after configuring an endpoint. Go to the actions _Test_ tab and click the **Send test action** button. ![A screenshot showing how to send a test action in the WorkOS dashboard.](https://images.workoscdn.com/images/8d998ae0-2efa-435a-9818-6873fcdc73ac.png?auto=format&fit=clip&q=80) If you would like to test against your local development environment, we recommend using a tool like [ngrok](https://ngrok.com) to create a secure tunnel to your local machine, and sending test webhooks to the public endpoint generated with ngrok. See our [blog post](https://workos.com/blog/test-workos-webhooks-locally-ngrok) to get more details on how you may want to test webhooks locally with ngrok. --- ### AuthKit Easy to use authentication platform designed to provide a flexible, secure, and fast integration. ## Introduction Integrating AuthKit into your app can be done in less than ten minutes. In this guide, we'll walk you through adding a hosted authentication flow to your application using AuthKit. In addition to this guide, there are a variety of [example apps](/authkit/example-apps) available to help with your integration. ## Before getting started To get the most out of this guide, you'll need: - A [WorkOS account](https://dashboard.workos.com/) - Your WorkOS [API Key](/glossary/api-key) and [Client ID](/glossary/client-id) --- ## (1) Configure your project Let's add the necessary dependencies and configuration in your WorkOS Dashboard. ### Install dependencies First, install the WorkOS gem. ```bash title="Install Ruby SDK" gem install workos ``` For CSRF protection on state-changing routes like logout, also install `rack-csrf`: ```bash title="Install CSRF protection" gem install rack_csrf ``` ### Configure a redirect URI A redirect URI is a callback endpoint that WorkOS will redirect to after a user has authenticated. This endpoint will exchange the authorization code returned by WorkOS for an authenticated [User object](/reference/authkit/user). We'll create this endpoint in the next step. You can set a redirect URI in the **Redirects** section of the [WorkOS Dashboard](https://dashboard.workos.com). We recommend using `http://localhost:3000/callback` as the default here. WorkOS supports using wildcard characters in Redirect URIs, but not for the default Redirect URI. More information about wildcard characters support can be found in the [Redirect URIs](/sso/redirect-uris/wildcard-characters) guide. ![Dashboard redirect URI](https://images.workoscdn.com/images/a7525cf3-ae4e-4dcd-91dd-27965b005472.png?auto=format&fit=clip&q=80) When users sign out of their application, they will be redirected to your app's [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) location which is configured in the same dashboard area. ### Configure sign-in endpoint Sign-in requests should originate from your application. In some instances, requests may not begin at your app. For example, some users might bookmark the hosted sign-in page or they might be led directly to the hosted sign-in page when clicking on a password reset link in an email. In these cases, AuthKit will detect when a sign-in request did not originate at your application and redirect to your application's sign-in endpoint. This is an endpoint that you define at your application that redirects users to sign in using AuthKit. We'll create this endpoint in the next step. You can configure the sign-in endpoint from the **Redirects** section of the WorkOS dashboard. ![Sign-in endpoint](https://images.workoscdn.com/images/25b53ea7-95ba-48cc-b6e7-ccd1b1bc35eb.png?auto=format&fit=clip&q=80) ### Set secrets To make calls to WorkOS, provide the API key and the client ID. Store these values as managed secrets and pass them to the SDKs either as environment variables or directly in your app's configuration depending on your preferences. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' ``` > The code examples use your staging API keys when [signed in](https://dashboard.workos.com) --- ## (2) Add AuthKit to your app Let's integrate the hosted authentication flow into your app. ### Set up the frontend To demonstrate AuthKit, we only need a simple page with links to logging in and out. Clicking the "Sign in" and "Sign out" links should invoke actions on our server, which we'll set up next. ### Add a sign-in endpoint We'll need a sign-in endpoint to direct users to sign in (or sign up) using AuthKit before redirecting them back to your application. This endpoint should generate an AuthKit authorization URL server side and redirect the user to it. You can use the optional state parameter to encode arbitrary information to help restore application `state` between redirects. For this guide we'll be using the `sinatra` web server for Ruby. This guide won't cover how to set up a Sinatra app, but you can find more information in the [Sinatra documentation](https://sinatrarb.com/intro.html). > WorkOS will redirect to your [Redirect URI](/glossary/redirect-uri) if there is an issue generating an authorization URL. Read our [API Reference](/reference) for more details. ### Add a callback endpoint Next, let's add the callback endpoint (referenced in [Configure a redirect URI](/authkit/1-configure-your-project/configure-a-redirect-uri)) which will exchange the authorization code (valid for 10 minutes) for an authenticated User object. ## (3) Handle the user session Session management helper methods are included in our SDKs to make integration easy. For security reasons, sessions are automatically "sealed", meaning they are encrypted with a strong password. ### Create a session password The SDK requires you to set a strong password to encrypt cookies. This password must be 32 characters long. You can generate a secure password by using the [1Password generator](https://1password.com/password-generator/) or the `openssl` library via the command line: ```bash title="Generate a strong password" openssl rand -base64 32 ``` Then add it to the environment variables file. ```plain title=".env" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' # +diff-start WORKOS_COOKIE_PASSWORD='' # +diff-end ``` ### Save the encrypted session Next, use the SDK to authenticate the user and return a password protected session. The refresh token is considered sensitive as it can be used to re-authenticate, hence why the session is encrypted before storing it in a session cookie. We should also present some of the user information on our frontend. Let's update the default route to read the session cookie and display user information: And, we should make sure to update the index page to present this info. ### Protected routes Then, use a helper method to specify which routes should be protected. If the session has expired, use the SDK to attempt to generate a new one. Call the helper method in the route that should only be accessible to logged in users. ### Ending the session Finally, ensure the user can end their session by redirecting them to the logout URL. After successfully signing out, the user will be redirected to your app's [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) location, which is configured in the WorkOS dashboard. > If you haven't configured a [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) in the WorkOS dashboard, users will see an error when logging out. ## Validate the authentication flow To test all of this out, start your server with `ruby server.rb`, navigate to `localhost:3000`, and sign up for an account. You can then sign in with the newly created credentials and see the user listed in the **Users** section of the [WorkOS Dashboard](https://dashboard.workos.com). ![Dashboard showing newly created user](https://images.workoscdn.com/images/54fa6e6c-4c6f-4959-9301-344aeb4eeac8.png?auto=format&fit=clip&q=80) ### AuthKit Easy to use authentication platform designed to provide a flexible, secure, and fast integration. ## Introduction Integrating AuthKit into your app can be done in less than ten minutes. In this guide, we'll walk you through adding a hosted authentication flow to your application using AuthKit. In addition to this guide, there are a variety of [example apps](/authkit/example-apps) available to help with your integration. ## Before getting started To get the most out of this guide, you'll need: - A [WorkOS account](https://dashboard.workos.com/) - Your WorkOS [API Key](/glossary/api-key) and [Client ID](/glossary/client-id) --- ## (1) Configure your project Let's add the necessary dependencies and configuration in your WorkOS Dashboard. ### Install dependencies First, install the Python SDK. ```bash title="Install Python SDK" pip install workos ``` For CSRF protection on state-changing routes like logout, also install `Flask-WTF`: ```bash title="Install CSRF protection" pip install Flask-WTF ``` ### Configure a redirect URI A redirect URI is a callback endpoint that WorkOS will redirect to after a user has authenticated. This endpoint will exchange the authorization code returned by WorkOS for an authenticated [User object](/reference/authkit/user). We'll create this endpoint in the next step. You can set a redirect URI in the **Redirects** section of the [WorkOS Dashboard](https://dashboard.workos.com). We recommend using `http://localhost:3000/callback` as the default here. WorkOS supports using wildcard characters in Redirect URIs, but not for the default Redirect URI. More information about wildcard characters support can be found in the [Redirect URIs](/sso/redirect-uris/wildcard-characters) guide. ![Dashboard redirect URI](https://images.workoscdn.com/images/a7525cf3-ae4e-4dcd-91dd-27965b005472.png?auto=format&fit=clip&q=80) When users sign out of their application, they will be redirected to your app's [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) location which is configured in the same dashboard area. ### Configure sign-in endpoint Sign-in requests should originate from your application. In some instances, requests may not begin at your app. For example, some users might bookmark the hosted sign-in page or they might be led directly to the hosted sign-in page when clicking on a password reset link in an email. In these cases, AuthKit will detect when a sign-in request did not originate at your application and redirect to your application's sign-in endpoint. This is an endpoint that you define at your application that redirects users to sign in using AuthKit. We'll create this endpoint in the next step. You can configure the sign-in endpoint from the **Redirects** section of the WorkOS dashboard. ![Sign-in endpoint](https://images.workoscdn.com/images/25b53ea7-95ba-48cc-b6e7-ccd1b1bc35eb.png?auto=format&fit=clip&q=80) ### Set secrets To make calls to WorkOS, provide the API key and the client ID. Store these values as managed secrets and pass them to the SDKs either as environment variables or directly in your app's configuration depending on your preferences. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' ``` > The code examples use your staging API keys when [signed in](https://dashboard.workos.com) --- ## (2) Add AuthKit to your app Let's integrate the hosted authentication flow into your app. ### Set up the frontend To demonstrate AuthKit, we only need a simple page with links to logging in and out. Clicking the "Sign in" and "Sign out" links should invoke actions on our server, which we'll set up next. ### Add a sign-in endpoint We'll need a sign-in endpoint to direct users to sign in (or sign up) using AuthKit before redirecting them back to your application. This endpoint should generate an AuthKit authorization URL server side and redirect the user to it. You can use the optional state parameter to encode arbitrary information to help restore application `state` between redirects. For this guide we'll be using the `flask` web server for Python. This guide won't cover how to set up a Flask app, but you can find more information in the [Flask documentation](https://flask.palletsprojects.com/en/stable/). > WorkOS will redirect to your [Redirect URI](/glossary/redirect-uri) if there is an issue generating an authorization URL. Read our [API Reference](/reference) for more details. ### Add a callback endpoint Next, let's add the callback endpoint (referenced in [Configure a redirect URI](/authkit/1-configure-your-project/configure-a-redirect-uri)) which will exchange the authorization code (valid for 10 minutes) for an authenticated User object. ## (3) Handle the user session Session management helper methods are included in our SDKs to make integration easy. For security reasons, sessions are automatically "sealed", meaning they are encrypted with a strong password. ### Create a session password The SDK requires you to set a strong password to encrypt cookies. This password must be 32 characters long. You can generate a secure password by using the [1Password generator](https://1password.com/password-generator/) or the `openssl` library via the command line: ```bash title="Generate a strong password" openssl rand -base64 32 ``` Then add it to the environment variables file. ```plain title=".env" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' # +diff-start WORKOS_COOKIE_PASSWORD='' # +diff-end ``` ### Save the encrypted session Next, use the SDK to authenticate the user and return a password protected session. The refresh token is considered sensitive as it can be used to re-authenticate, hence why the session is encrypted before storing it in a session cookie. We should also present some of the user information on our frontend. Let's update the default route to read the session cookie and display user information: And, we should make sure to update the index page to present this info. ### Protected routes Then, use a decorator to specify which routes should be protected. If the session has expired, use the SDK to attempt to generate a new one. Use the decorator in the route that should only be accessible to logged in users. ### Ending the session Finally, ensure the user can end their session by redirecting them to the logout URL. After successfully signing out, the user will be redirected to your app's Sign-out redirect location, which is configured in the WorkOS dashboard. > If you haven't configured a [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) in the WorkOS dashboard, users will see an error when logging out. ## Validate the authentication flow To test all of this out, start your server with `python server.py`, navigate to `localhost:3000`, and sign up for an account. You can then sign in with the newly created credentials and see the user listed in the **Users** section of the [WorkOS Dashboard](https://dashboard.workos.com). ![Dashboard showing newly created user](https://images.workoscdn.com/images/54fa6e6c-4c6f-4959-9301-344aeb4eeac8.png?auto=format&fit=clip&q=80) ### AuthKit Easy to use authentication platform designed to provide a flexible, secure, and fast integration. ## Introduction Integrating AuthKit into your app can be done in less than ten minutes. In this guide, we'll walk you through adding a hosted authentication flow to your application using AuthKit. In addition to this guide, there are a variety of [example apps](/authkit/example-apps) available to help with your integration. ## Before getting started To get the most out of this guide, you'll need: - A [WorkOS account](https://dashboard.workos.com/) - Your WorkOS [API Key](/glossary/api-key) and [Client ID](/glossary/client-id) --- ## (1) Configure your project Let's add the necessary dependencies and configuration in your WorkOS Dashboard. ### Install dependencies First, install the required Node SDK via `npm`. ```bash title="Install Node SDK" npm install @workos-inc/node ``` For CSRF protection on state-changing routes like logout, also install `csrf-csrf`: ```bash title="Install CSRF protection" npm install csrf-csrf cookie-parser ``` ### Configure a redirect URI A redirect URI is a callback endpoint that WorkOS will redirect to after a user has authenticated. This endpoint will exchange the authorization code returned by WorkOS for an authenticated [User object](/reference/authkit/user). We'll create this endpoint in the next step. You can set a redirect URI in the **Redirects** section of the [WorkOS Dashboard](https://dashboard.workos.com). We recommend using `http://localhost:3000/callback` as the default here. WorkOS supports using wildcard characters in Redirect URIs, but not for the default Redirect URI. More information about wildcard characters support can be found in the [Redirect URIs](/sso/redirect-uris/wildcard-characters) guide. ![Dashboard redirect URI](https://images.workoscdn.com/images/a7525cf3-ae4e-4dcd-91dd-27965b005472.png?auto=format&fit=clip&q=80) When users sign out of their application, they will be redirected to your app's [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) location which is configured in the same dashboard area. ### Configure sign-in endpoint Sign-in requests should originate from your application. In some instances, requests may not begin at your app. For example, some users might bookmark the hosted sign-in page or they might be led directly to the hosted sign-in page when clicking on a password reset link in an email. In these cases, AuthKit will detect when a sign-in request did not originate at your application and redirect to your application's sign-in endpoint. This is an endpoint that you define at your application that redirects users to sign in using AuthKit. We'll create this endpoint in the next step. You can configure the sign-in endpoint from the **Redirects** section of the WorkOS dashboard. ![Sign-in endpoint](https://images.workoscdn.com/images/25b53ea7-95ba-48cc-b6e7-ccd1b1bc35eb.png?auto=format&fit=clip&q=80) ### Set secrets To make calls to WorkOS, provide the API key and the client ID. Store these values as managed secrets and pass them to the SDKs either as environment variables or directly in your app's configuration depending on your preferences. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' ``` > The code examples use your staging API keys when [signed in](https://dashboard.workos.com) --- ## (2) Add AuthKit to your app Let's integrate the hosted authentication flow into your app. ### Set up the frontend To demonstrate AuthKit, we only need a simple page with links to logging in and out. Clicking the "Sign in" and "Sign out" links should invoke actions on our server, which we'll set up next. ### Add a sign-in endpoint We'll need a sign-in endpoint to direct users to sign in (or sign up) using AuthKit before redirecting them back to your application. This endpoint should generate an AuthKit authorization URL server side and redirect the user to it. You can use the optional state parameter to encode arbitrary information to help restore application `state` between redirects. For this guide we'll be using the `express` web server for Node. This guide won't cover how to set up an Express app, but you can find more information in the [Express documentation](https://expressjs.com/en/starter/installing.html). > WorkOS will redirect to your [Redirect URI](/glossary/redirect-uri) if there is an issue generating an authorization URL. Read our [API Reference](/reference) for more details. ### Add a callback endpoint Next, let's add the callback endpoint (referenced in [Configure a redirect URI](/authkit/1-configure-your-project/configure-a-redirect-uri)) which will exchange the authorization code (valid for 10 minutes) for an authenticated User object. ## (3) Handle the user session Session management helper methods are included in our SDKs to make integration easy. For security reasons, sessions are automatically "sealed", meaning they are encrypted with a strong password. ### Create a session password The SDK requires you to set a strong password to encrypt cookies. This password must be 32 characters long. You can generate a secure password by using the [1Password generator](https://1password.com/password-generator/) or the `openssl` library via the command line: ```bash title="Generate a strong password" openssl rand -base64 32 ``` Then add it to the environment variables file. ```plain title=".env" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' # +diff-start WORKOS_COOKIE_PASSWORD='' # +diff-end ``` ### Save the encrypted session Next, use the SDK to authenticate the user and return a password protected session. The refresh token is considered sensitive as it can be used to re-authenticate, hence why the session is encrypted before storing it in a session cookie. We should also present some of the user information on our frontend. Let's update the default route to read the session cookie and display user information: And, we should make sure to update the index page to present this info. ### Protected routes Then, use middleware to specify which routes should be protected. If the session has expired, use the SDK to attempt to generate a new one. Add the middleware to the route that should only be accessible to logged in users. ### Ending the session Finally, ensure the user can end their session by redirecting them to the logout URL. After successfully signing out, the user will be redirected to your app's [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) location, which is configured in the WorkOS dashboard. > If you haven't configured a [Sign-out redirect](/authkit/sessions/configuring-sessions/sign-out-redirect) in the WorkOS dashboard, users will see an error when logging out. ## Validate the authentication flow To test all of this out, start your server with `node server.js`, navigate to `localhost:3000`, and sign up for an account. You can then sign in with the newly created credentials and see the user listed in the **Users** section of the [WorkOS Dashboard](https://dashboard.workos.com). ![Dashboard showing newly created user](https://images.workoscdn.com/images/54fa6e6c-4c6f-4959-9301-344aeb4eeac8.png?auto=format&fit=clip&q=80) ### Standalone Connect Integrate Connect's OAuth API with your existing authentication stack. ## Overview Standalone Connect allows applications with existing authentication systems to use AuthKit as their OAuth authorization server. You maintain your existing authentication stack while leveraging AuthKit's OAuth infrastructure for token issuance and management. Unlike standard AuthKit integration, Standalone Connect delegates authentication to your application, then handles the OAuth flow and token issuance for OAuth clients. This feature works with [OAuth applications](/authkit/connect/oauth) only—[M2M applications](/authkit/connect/m2m) use the `client_credentials` flow which doesn't involve user authentication. ## When to use Standalone Connect Use Standalone Connect when you: - Have an existing authentication stack in your application. - Need to enable OAuth-based integrations, like a [CLI](/authkit/cli-auth) app or [MCP](/authkit/mcp) server. - Want to support third-party applications accessing your users' resources. ## Getting started ### Create an OAuth application Before testing your Standalone Connect integration, you'll need to [create an OAuth application](/authkit/connect/oauth) in the WorkOS Dashboard. If you need to support MCP auth, you'll need to enable Client ID Metadata Document (CIMD), which you can read more about in the [MCP guide](/authkit/mcp). ### Configure your Login URI Navigate to _Connect_ → _Configuration_ in the [WorkOS Dashboard](https://dashboard.workos.com) and provide your **Login URI**. The **Login URI** is where AuthKit will redirect users to authenticate with your existing system. You can only configure one Login URI per environment. Your Login URI must: - Use HTTPS in production. - Accept an `external_auth_id` query parameter. - Authenticate users with your existing system. - Call the AuthKit completion API after successful authentication. More on that below. Example: `https://your-app.example.com/auth/login` ## Authentication flow ### (1) OAuth client initiates flow OAuth clients start the authorization flow by redirecting users to the [`/oauth2/authorize`](/reference/workos-connect/authorize) endpoint on your AuthKit domain following standard OAuth 2.0. This could be a third-party application, partner integration, or any OAuth-enabled client. ### (2) AuthKit redirects to your application AuthKit redirects users to your Login URI with an `external_auth_id` parameter: ```txt https://your-app.example.com/auth/login?external_auth_id=01J3X4Y5Z6A7B8C9D0E1F2G3H4 ``` The `external_auth_id` is a temporary identifier used to complete the flow with AuthKit. ### (3) Authenticate the user Your application authenticates users with your existing system. If users have an active session, skip to the next step. AuthKit handles OAuth consent separately, so your application doesn't need to display any consent screens. ### (4) Complete authentication with AuthKit Call the [AuthKit completion API](/reference/workos-connect/standalone/complete) after authenticating the user, passing the `external_auth_id` that your Login URI originally received: ```js const response = await fetch('https://api.workos.com/authkit/oauth2/complete', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.WORKOS_API_KEY}`, }, body: JSON.stringify({ external_auth_id: externalAuthId, user: { id: user.id, email: user.email, first_name: user.firstName, last_name: user.lastName, metadata: { department: user.department }, }, }), }); const { redirect_uri } = await response.json(); ``` ### (5) Return control to AuthKit Redirect users to the `redirect_uri` from the API response. AuthKit displays a consent screen if needed, then redirects back to the OAuth client's `redirect_uri` with an authorization code. The OAuth client exchanges this code for tokens via the [`/oauth2/token`](/reference/workos-connect/token/authorization-code-grant) endpoint on your AuthKit domain. ## Integrating via the API ### Dynamic consent options You can provide `user_consent_options` to display options during the OAuth consent screen. This is useful when users need to choose specific resources or contexts (like a parent resource in your application) to grant access to. Each consent option must include: - `claim`: The name of the access token claim that will hold the user's selected value. - `type`: The format of the option. Only `enum` is supported currently. - `label`: Display text for the option. - `choices`: Array of choices (can be flat or grouped). ```js const response = await fetch('https://api.workos.com/authkit/oauth2/complete', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.WORKOS_API_KEY}`, }, body: JSON.stringify({ external_auth_id, user: { id: user.id, email: user.email }, user_consent_options: [ { claim: 'urn:example:tenant', type: 'enum', label: 'Environment', choices: [ { group: 'Production', choices: [ { value: 'prod_us', label: 'US-East' }, { value: 'prod_eu', label: 'EU-West' }, ], }, { group: 'Development', choices: [ { value: 'dev_main', label: 'Development' }, { value: 'staging', label: 'Staging' }, ], }, ], }, ], }), }); ``` The selected values appear as custom claims in the issued tokens. For example, if the user selects one of the above options, the token will include: ```json { "sub": "user_123", "email": "user@example.com", "urn:example:tenant": "prod_us" // ... } ``` ### Error handling If the `external_auth_id` is invalid, the call to the AuthKit completion API will fail. Your application is free to choose how to handle this case, but redirecting to your application's homepage is recommended. ### Token verification Resource servers verify tokens issued by AuthKit using standard Connect token verification: ```js import { jwtVerify, createRemoteJWKSet } from 'jose'; const JWKS = createRemoteJWKSet(new URL('https://authkit_domain/oauth2/jwks')); async function verifyToken(token) { const { payload } = await jwtVerify(token, JWKS, { audience: 'client_123456789', issuer: 'https://authkit_domain', }); return payload; } ``` See the [Connect documentation](/authkit/connect/oauth/verifying-tokens) for details on token expiration, refresh tokens, and revocation. ### OAuth Applications Integrate OAuth applications with WorkOS Connect for web and mobile authentication. ## Overview OAuth applications are designed for applications where the actor being authenticated is a [User](/reference/authkit/user). These include web applications, mobile, desktop, and CLI tools. OAuth applications use the underlying `authorization_code` OAuth flow which is supported by many libraries and frameworks out of the box. > For server-to-server requests from a third-party without user interaction, use [M2M applications](/authkit/connect/m2m) instead. ## First-party vs Third-party Applications When creating OAuth applications, you choose the level of trust: first-party or third-party. ### First-party applications Select first-party when the application is one that your team controls, such as supporting services that are deployed separately from your main application but still need access to your users' identities. Examples include community forums or customer support portals. ### Third-party applications Select third-party when the application is one built by your customers or partners, but you do not directly control the integrating application. For this reason, you must also associate third-party applications with an [Organization](/reference/organization) that represents the customer or partner. A third-party OAuth application will generally have a "Sign in with \[your application]" button on their login page, in the same way many sites have a "Sign in with Google" button, allowing you to offer similar functionality to your customers or partners. Unlike first-party applications, your users will be prompted in AuthKit to explicitly authorize the application before their identity is shared. ![Screenshot of the application authorization screen in AuthKit.](https://images.workoscdn.com/images/afde561f-9378-4aa6-995c-cda8f3ec0a63.png) AuthKit shows the consent page the first time a user authorizes a third-party OAuth application. After the user grants consent, subsequent authorization requests for the same user and application skip the consent page unless the application requests additional scopes or organization access. ## Receiving Tokens After an application has been issued credentials from a Connect Application, it can receive identity and access tokens using the OAuth 2.0 `authorization_code` flow. Many OAuth and OIDC libraries support Connect applications out of the box, needing only configuration: ## Public Applications By default, OAuth applications are confidential and must authenticate with a client secret when exchanging authorization codes for tokens. However, certain types of applications cannot securely store client secrets, such as command-line tools or mobile applications. For these use cases, you can configure an OAuth application as **Public**. Public applications: - Cannot securely store client secrets - Must use [Proof Key for Code Exchange (PKCE)](https://datatracker.ietf.org/doc/html/rfc7636) in order to authenticate with the [Token Endpoint](/reference/workos-connect/token) OAuth applications can be set as _Public_ during creation in the WorkOS Dashboard. ## Verifying Tokens Your application must verify the tokens sent by OAuth applications using the JWKS for your environment. User information in the token can be used to look up related resources and perform further access control checks. In addition to fast stateless verification, you can use the [Token Introspection API](/reference/workos-connect/introspection) to synchronously check whether a token is still valid. ## Organization Access When a user who is a member of multiple Organizations authorizes an OAuth Application, they will be prompted to select one of their Organizations to grant access to. Or, if the user only has a single Organization membership, that Organization will be automatically selected. The selected Organization will be made available as the `org_id` claim in the issued [access token](/reference/workos-connect/token/authorization-code-grant/access-token), which your app can use to scope the access of requests made using the token. ## Configuration OAuth applications require the following configuration: ### Redirect URI This is the final location users will be redirected to after successful authentication. Clients should use the [Token Endpoint](/reference/workos-connect/token) to exchange the `code` for tokens at this location. ### Name and Logo For third-party OAuth applications, the name and logo will be displayed to your users when they are prompted to authorize access. Both light and dark-mode logos are supported. ### Credentials OAuth applications use the `client_id` and `client_secret` from a credential to authenticate to the [OAuth-based Connect APIs](/reference/workos-connect). ## Next Steps - [Connect API Reference](/reference/workos-connect) - Complete API documentation ### M2M Applications Implement machine-to-machine authentication with WorkOS Connect. ## Overview Machine-to-machine (M2M) applications are designed for use-cases where clients are other services, such as one of your customer's applications. M2M applications use the underlying `client_credentials` flow for authentication. M2M access tokens will contain an `org_id` claim which represents the third-party you are granting access to via the M2M application. > M2M applications can only be configured as third-party. M2M applications are one of two ways WorkOS enables you to issue credentials to your customers that they use to programmatically access your application. The other is [API keys](/authkit/api-keys). The [API Keys vs M2M Applications guide](https://workos.com/blog/api-keys-vs-m2m-applications) can help you decide which is best for your use case. ## Common Use Cases M2M applications are commonly used to provide API access credentials to customers or partners, allowing them to programmatically access your APIs and integrate your services into their applications. They're also ideal for partner integrations that run server-to-server without user interaction, where you need to track and control access on a per-organization basis. ## Receiving Tokens Machine-to-machine applications can use the `client_credentials` grant type with the [Token Endpoint](/reference/workos-connect/token) to obtain an `access_token` to authenticate calls to your API. ## Organization-Based Access Control M2M applications are always associated with a specific [Organization](/reference/organization), which represents the customer or partner. Since machine-to-machine applications are associated with a particular organization, issued access tokens contain an `org_id` claim that your application's API can use to control access. This association provides several benefits: 1. **Scoped Access**: Access tokens contain an `org_id` claim that identifies which organization the client is acting on behalf of 2. **Resource Isolation**: Your API can use the `org_id` to ensure clients only access resources they're authorized for 3. **Audit Trail**: All API calls can be attributed to a specific organization for auditing purposes ## Verifying Tokens Your application can verify the tokens sent by external M2M applications for the purpose of authenticating requests using the JWKS for your environment. The process is similar to validating the access token JWT provided by an AuthKit login. In addition to fast stateless verification, you can use the [Token Introspection API](/reference/workos-connect/introspection) to synchronously check whether a token is still valid. ## Configuration M2M applications require the following configuration: ### Credentials M2M applications use the `client_id` and `client_secret` from a credential to authenticate to the [Connect APIs](/reference/workos-connect) using the client credentials flow. ### Name and Description While not displayed to users (since M2M apps don't have user interaction), the name and description help you manage and identify different M2M applications in your dashboard. ## Next Steps - [Connect API Reference](/reference/workos-connect) - Complete API documentation ### Stripe Connect your WorkOS account to Stripe to automatically provision access tokens with entitlements and sync organization seat counts. ## Introduction WorkOS provides two powerful Stripe integrations that help you manage billing and access control for your B2B application: - **Stripe Entitlements**: Automatically provision access tokens with subscription-based entitlements from Stripe - **Stripe Seat Sync**: Automatically sync organization member counts to Stripe billing meters for usage-based billing Both features use [Stripe Connect](https://stripe.com/connect) to connect your WorkOS account to your Stripe account, allowing WorkOS to manage these integrations on your behalf. --- ## Connect to Stripe To use either Stripe Entitlements or Stripe Seat Sync, you'll first need to connect your WorkOS account to Stripe using Stripe Connect. Navigate to the _Authentication_ section of the [WorkOS Dashboard](https://dashboard.workos.com/) and click _Add-ons_. From that page, find the Stripe Add-on and click _Enable_. ![Authentication Add-ons page](https://images.workoscdn.com/images/75c987b7-d946-4e37-b46d-043fa994cfb4.png?auto=format&fit=clip&q=80) This will open a Dialog to pick the Stripe features you would like to use. When clicking _Continue_ you'll be directed to Stripe where you can approve the connection. Once that's complete, close the tab. > WorkOS does not currently support connecting to a Stripe Sandbox account. Connect WorkOS to a standard Stripe account, and use Stripe's test mode for development and testing your integration. ![Stripe Dialog](https://images.workoscdn.com/images/5953bd10-b966-4b1f-8d9f-7cd490bc19d3.png?auto=format&fit=clip&q=80) In the connection dialog, you can choose to enable one or both features: - **Use Stripe entitlements**: Include entitlement data in access tokens - **Sync organization seat counts**: Send member counts to Stripe billing meters If you decide to disconnect your Stripe account later or toggle features on and off, you can do so from the same section. Click the _Manage_ button to disable features or disconnect entirely. --- ## Set Stripe Customer IDs To use either of these features, you'll need to set the Stripe customer ID on each WorkOS organization. Once you have a WorkOS organization ID and a Stripe customer ID, you can set the Stripe customer ID for the organization. One way to handle this is to create a Stripe customer and then set the created Stripe customer ID on the WorkOS organization. This can be done via the WorkOS API or SDK. Here's an example using the SDK: --- ## Stripe Entitlements Entitlements are a way to provision an account in your application with specific features or functionality based on the subscription plan a user is on. For example, you might have an "Enterprise" plan that allows users to access certain features like [Audit Logs](/audit-logs), and a "Basic" plan that does not. The WorkOS Entitlements integration makes it easy to get Stripe's entitlement information into your application without needing to listen to Stripe webhooks or explicitly track them in your application. ### Use the entitlements in your application The access token will now include the `entitlements` claim, containing the user's entitlements. You can use this information to gate access to features in your application. > Entitlements added mid-cycle will appear in the next Stripe billing cycle or when a new subscription is created, per Stripe's billing logic. Entitlements will show up in the access token the next time the user logs in or the session is refreshed. You can manually [refresh the session](/reference/authkit/authentication/refresh-token) after the user has completed their subscription purchase. Here's an example in Express: --- ## Stripe Seat Sync Stripe Seat Sync automatically sends active organization member counts to Stripe as billing meter events under [Usage-based billing](https://docs.stripe.com/billing/subscriptions/usage-based), enabling usage-based billing based on the number of seats (members) in each organization. ### How it works When Stripe Seat Sync is enabled: - WorkOS creates a billing meter in your Stripe account called **"User Seat Count"** with the event name `workos_seat_count` - Whenever a member is added, removed, deactivated, or activated from an organization, WorkOS automatically sends a meter event to Stripe with the updated seat count - You can use this meter in Stripe to create usage-based pricing based on the number of active seats The meter uses Stripe's ["last" aggregation method](https://docs.stripe.com/billing/subscriptions/usage-based/meters/configure), which means Stripe will bill based on the most recent seat count reported during each billing period. ### Using the seat count meter in Stripe Once enabled, WorkOS will automatically send meter events to Stripe whenever organization memberships change. You can: - View the meter events in your Stripe Dashboard under **Billing → Meters** - Create pricing models that bill based on the `workos_seat_count` meter - Use the meter in subscription items to charge customers based on their current seat count The meter event includes: - **Event name**: `workos_seat_count` - **Customer ID**: The Stripe customer ID associated with the organization - **Value**: The current number of active members in the organization No additional code is required in your application—WorkOS handles all meter event reporting automatically as members join or leave organizations. ### Segment Send AuthKit events to your Segment destinations. ## Introduction The Segment AuthKit Add-on allows you to register AuthKit as a Segment source and receive events about logins, sign ups, and many other AuthKit activities. You can forward that data to your Segment destinations, allowing you to better understand the effectiveness of your marketing campaigns and your users' full journeys across your website and AuthKit. --- ## Configuring the Add-on ### (1) Confirm your domain To use the Add-on, your [Authentication API Domain](/custom-domains/auth-api) must share the same root as the domain where you set up Segment through Analytics.js. This gives the Add-on access to your users' anonymous IDs, which the Add-on uses to identify users. For example, if your Segment Analytics.js script lives at www.example.com: - **Valid:** auth.example.com is a valid Authentication API Domain - **Invalid:** auth.workos.com is not a valid Authentication API Domain ### (2) Visit the Add-ons page In the WorkOS Dashboard, click the _Authentication_ icon in the sidebar. Then click _Add-ons_. ![Add-ons page in the Authentication section of the WorkOS Dashboard](https://images.workoscdn.com/images/d5b867bb-8f04-440b-8443-4f9a1026a0cb.png?auto=format&fit=clip&q=50) ### (3) Enable the Add-on Click _Enable_ next to _Segment._ ![Segment modal containing a Write Key field in the WorkOS Dashboard](https://images.workoscdn.com/images/18d3da6b-0b59-4973-8a71-851e1ad4e5dc.png?auto=format&fit=clip&q=50) In another browser tab, visit Segment to get your credentials. Click _Connections_ in the left sidebar. ![Connections link in Segment](https://images.workoscdn.com/images/78899ff2-be15-4fc0-a9d4-1482af04703e.png?auto=format&fit=clip&q=50) Next to _Sources_, click _Add more_. ![Add more link on the Connections page in Segment](https://images.workoscdn.com/images/5feab1ce-89d3-4998-b16e-9ffdb48b4b0f.png?auto=format&fit=clip&q=50) Under _Choose a Source_, search "HTTP API." Below, click _HTTP API_. Then, in the lower right corner, click _Next._ ![HTTP API source in Segment](https://images.workoscdn.com/images/c6be5d31-307f-4371-82de-9486a034f478.png?auto=format&fit=clip&q=50) Under _Create your source_, give your source a name, like _WorkOS AuthKit Add-on_. Click _Create Source_. Under _Configure this source in your HTTP API codebase_, find your _Write Key_, and click the _Copy_ button next to it. ![Copy button next to a new Write Key for an HTTP API source in Segment](https://images.workoscdn.com/images/82093be1-5a27-4985-bdef-ce3899832ee6.png?auto=format&fit=clip&q=50) Paste your write key in the _Write Key_ field in the WorkOS Dashboard. Click _Save changes_. The Segment AuthKit Add-on is enabled and will begin sending AuthKit events to Segment. --- ## Events sent to Segment The Add-on sends events to Segment when certain [WorkOS Events](/events) occur: - _Authentication_ events - _Email verification_ events - _Magic Auth_ events - _Password reset_ events - `session.created` - `user.created` All names of events in Segment will match the names of the [WorkOS Events](/events). --- ## Verifying events After enabling the Add-on, visit your website, click your sign in button, and sign in to your application. Visit Segment and click _Connections_ in the sidebar. Click the source you created. Then click the _Debugger_ tab. You should see an identify call including your anonymous ID and a track call with an authentication event. If you do not see an authentication event, visit the Add-ons page in the WorkOS Dashboard to verify your Write Key matches the value from Segment. If after confirming the values match you still need support, please reach out to us in Slack. ### Google Analytics Track user activity on AuthKit pages in Google Analytics. ## Introduction The Google Analytics AuthKit Add-on gives you data about logins, sign ups, and many other AuthKit activities inside of Google Analytics. You can use that data to better understand the effectiveness of your marketing campaigns and your users' full journeys across your website and AuthKit. --- ## Configuring the Add-on ### (1) Confirm your domain To use the Add-on, your [Authentication API Domain](/custom-domains/auth-api) must share the same root as the domain where you set up Google Analytics through Google Tag Manager or gtag.js. This gives the Add-on access to your users' Google Analytics client IDs, which the Add-on uses to associate events in AuthKit with users from your website. For example, if your Google Analytics script lives at www.example.com: - **Valid:** auth.example.com is a valid Authentication API Domain - **Invalid:** auth.workos.com is not a valid Authentication API Domain ### (2) Visit the Add-ons page In the WorkOS Dashboard, click the _Authentication_ icon in the sidebar. Then click _Add-ons_. ![Add-ons page in the Authentication section of the WorkOS Dashboard](https://images.workoscdn.com/images/d5b867bb-8f04-440b-8443-4f9a1026a0cb.png?auto=format&fit=clip&q=50) ### (3) Enable the Add-on Click _Enable_ next to _Google Analytics._ ![Google Analytics modal with Measurement ID and Measurement Protocol API Secret fields in the WorkOS Dashboard](https://images.workoscdn.com/images/40f61f05-32d2-4439-ae68-3c3b8f8aaf87.png?auto=format&fit=clip&q=50) In another browser tab, visit Google Analytics to get your credentials. Click the _Admin_ icon in the bottom left corner. ![Admin icon on the Google Analytics website](https://images.workoscdn.com/images/21267275-4fde-431b-95d6-8e1ec3cc8190.png?auto=format&fit=clip&q=50) Under _Data collection and modification_, click _Data streams._ ![Data steams link on the Google Analytics website](https://images.workoscdn.com/images/8f967c62-d63f-4130-8510-dc97a249d0b4.png?auto=format&fit=clip&q=50) Click the data stream that you used to set up Google Analytics on your website. Under _Measurement ID_, click the copy icon. Paste your Measurement ID in the Measurement ID field in the WorkOS Dashboard. ![Measurement ID on the Google Analytics website](https://images.workoscdn.com/images/68dbf576-dae1-4940-b3d4-6840086f94b5.png?auto=format&fit=clip&q=50) Under _Events_, click _Measurement Protocol API secrets_. ![Measurement Protocol API Secrets section on the Google Analytics website](https://images.workoscdn.com/images/cdf958e3-6714-4700-9c77-71e46af96bc5.png?auto=format&fit=clip&q=50) Click _Create_. Give your new secret a name, like _WorkOS AuthKit_ _Add-on_. Copy the _Secret value._ The secret value may be cut off on narrower windows, so try double clicking the value before copying it to ensure you have selected the full value. ![Measurement Protocol API Secret value on the Google Analytics website](https://images.workoscdn.com/images/8bd84bdf-eb85-4987-97a2-c13c863508a3.png?auto=format&fit=clip&q=50) Paste the secret value in the API Secret field in the WorkOS Dashboard. Click _Save changes_. The Google Analytics AuthKit Add-on is enabled and will begin sending AuthKit events to Google Analytics. ![Google Analytics AuthKit Add-on enabled in the WorkOS Dashboard](https://images.workoscdn.com/images/0e47d2b4-29ad-4a47-9ab6-470dee7cc63c.png?auto=format&fit=clip&q=50) --- ## Events sent to Google Analytics The Add-on sends events to Google Analytics when certain [WorkOS Events](/events) occur: - `user.created` sends Google a [`sign_up` recommended event](https://developers.google.com/analytics/devguides/collection/ga4/reference/events?client_type=gtag#sign_up) - `authentication.magic_auth_succeeded`, `authentication.mfa_succeeded`, `authentication.oauth_succeeded`, `authentication.passkey_succeeded`, `authentication.password_succeeded`, and `authentication.sso_succeeded` send Google a [`login` recommended event](https://developers.google.com/analytics/devguides/collection/ga4/reference/events?client_type=gtag#login) including a `method` parameter matching the login method - The remaining _Authentication_ events, _Email verification_ events, _Magic Auth_ events, _Password reset_ events, and `session.created` send Google events based on the WorkOS event name, with underscores replacing periods - `authentication.email_verification_succeeded` is shortened to `auth_email_verification_succeeded` to meet Google's requirement that event names be 40 characters or shorter --- ## Verifying events After enabling the Add-on, visit your website, click your sign in button, and sign in to your application. Visit Google Analytics and click _Reports_ in the sidebar. Then click _Realtime overview_. Within five minutes, you should see a `login` event under _Event count by Event name_. If you do not see a login event, visit the Add-ons page in the WorkOS Dashboard to verify your Measurement ID and API Secret match the values from Google Analytics. If after confirming the values match you still need support, please reach out to us in Slack. ## Audit Logs {#audit-logs} ### Audit Logs Ingest and export Audit Log Events from your application. ## Introduction Audit Logs are a collection of events that contain information relevant to notable actions taken by users in your application. Every event in the collection contains details regarding what kind of action was taken (`action`), who performed the action (`actor`), what resources were affected by the action (`targets`), and additional details of when and where the action took place. ```json { "action": "user.signed_in", "occurred_at": "2022-08-29T19:47:52.336Z", "actor": { "type": "user", "id": "user_01GBNJC3MX9ZZJW1FSTF4C5938" }, "targets": [ { "type": "team", "id": "team_01GBNJD4MKHVKJGEWK42JNMBGS" } ], "context": { "location": "123.123.123.123", "user_agent": "Chrome/104.0.0.0" } } ``` These events are similar to application logs and analytic events, but are fundamentally different in their intent. They aren't typically used for active monitoring/alerting, rather they exist as a paper trail of potentially sensitive actions taken by members of an organization for compliance and security reasons. ## What you'll build This guide will show you how to: 1. Configure and emit Audit Log Events 2. Export Audit Log Events 3. Create custom metadata schemas for Audit Log Events 4. Create new versions of Audit Log Event schemas ## Before getting started To get the most out of this guide, you'll need: - A [WorkOS account](https://dashboard.workos.com/) ## API object definitions [Audit Log Event](/reference/audit-logs/event/create) : An individual event that represents an action taken by an actor within your app. [Audit Log Export](/reference/audit-logs/export) : A collection of Audit Log Events that are exported from WorkOS as a CSV file. [Organization](/reference/organization) : Describes a customer where Audit Log Events originate from. ## Emit an Audit Log Event ### Install the WorkOS SDK WorkOS offers native SDKs in several popular programming languages. Choose a language below to see instructions in your application's language. ### Set secrets To make calls to WorkOS, provide the API key and, in some cases, the client ID. Store these values as managed secrets, such as `WORKOS_API_KEY` and `WORKOS_CLIENT_ID`, and pass them to the SDKs either as environment variables or directly in your app's configuration based on your preferences. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' ``` ### Sign in to your WorkOS Dashboard account and configure Audit Log Event schemas Before you can emit any Audit Log Events you must configure the allowed event schemas. To start, click "Create an event" and enter `user.signed_in` for action, `team` for targets, and click "Save event". ![A screenshot showing how to create an audit log event in the WorkOS dashboard.](https://images.workoscdn.com/images/7658a3b2-1467-4c38-a98f-f99f933c5969.png?auto=format&fit=clip&q=50) ### Get an Organization ID All events are scoped to an Organization, so you will need the ID of an Organization in order to emit events. ![A screenshot showing where to find an Organization ID in the WorkOS dashboard.](https://images.workoscdn.com/images/b76c7593-1d85-4f28-951e-24f177b8c233.png?auto=format&fit=clip&q=50) ### Emit Events Using the ID from the Organization, emit an Audit Log Event with the `action` and `targets` previously configured. #### Idempotency WorkOS Audit Logs supports idempotency to ensure events are not duplicated when retrying requests. You can provide an `idempotency-key` header with your event creation request. If you don't provide one, WorkOS will automatically generate one based on the event content. When you provide an idempotency key: - WorkOS creates a hashed key combining your provided key with the event data - Subsequent requests with the same idempotency key and event data will return the same response - This prevents duplicate events from being created due to network retries or other issues When you don't provide an idempotency key: - WorkOS automatically generates one using the event content - This provides basic duplicate protection based on event data alone ### View ingested events in the Dashboard Once you have successfully emitted events with the WorkOS SDK, you can view them in the Dashboard under the Organization that the events are associated with. ![A screenshot showing Audit Log events for an organization in the WorkOS dashboard.](https://images.workoscdn.com/images/b03dfaa4-c76a-4d08-a322-53458ba8b24d.png?auto=format&fit=clip&q=50) ### Metadata Schema Define strict JSON Schema for validating event metadata. ## Metadata Schema Audit Log Events can contain arbitrary metadata for adding additional details to your events. Normally this data can take any shape. However, custom metadata schemas can be defined when configuring the event for additional type safety and data consistency. When an event is emitted that does not match the provided schema, an error will be returned. When first creating an event schema, check the "Require metadata schema validation" checkbox. You will then be navigated to the schema editor where you can modify the underlying [JSON Schema](https://json-schema.org/) for all `metadata` objects. ![A screenshot showing how to require metadata schema validation in the WorkOS Dashboard.](https://images.workoscdn.com/images/24a410e1-72aa-4f5b-8854-98a4307602ff.png?auto=format&fit=clip&q=50) There are `metadata` objects located at the root of the event, and within `actor` and `targets` objects. Each can contain a unique JSON Schema. To add to a `metadata` object, click the "+" sign. > Metadata objects have a limit of 50 keys. Key names can be up to 40 characters long, and values can be up to 500 characters long. ![A screenshot showing the schema editor in the WorkOS Dashboard.](https://images.workoscdn.com/images/7d9e37a3-2e8d-4910-b85d-34c224e375be.png?auto=format&fit=clip&q=50) ### Log Streams Stream Audit Log Events to your customers' SIEM providers. ## Understanding Log Streams Log Streams allow your customers to stream Audit Logs directly to their Security Incident and Event Management (SIEM) providers like Datadog or Splunk, data warehouses like Snowflake, and object storage solutions like AWS S3 or Google Cloud Storage. There is also a generic provider (HTTP POST) available to stream logs to any configured endpoint. This gives your customers greater control over their Audit Logs by allowing them to apply custom indexing and monitoring of their events in the SIEM provider along with events from other cloud services they use. Log Streams can be created by either configuring the Log Stream through your WorkOS Dashboard or by allowing your customers' IT contacts to configure it themselves through the WorkOS Admin Portal. ### IP allowlist WorkOS streams audit logs from a fixed set of IP addresses. If audit logs are being streamed to a host that restricts access based on IP address, the following IP addresses should be allowed: ```plain title="WorkOS IP addresses" 3.217.146.166 23.21.184.92 34.204.154.149 44.213.245.178 44.215.236.82 50.16.203.9 52.1.251.34 52.21.49.187 174.129.36.47 ``` ## Dashboard To configure a Log Stream through the WorkOS Dashboard, navigate to an organization and click "Configure". ![A screenshot showing where to find "Configure" in the WorkOS Dashboard.](https://images.workoscdn.com/images/b555ad16-fce2-4014-997d-3d75b85f7860.png?auto=format&fit=clip&q=50) You will be prompted to select a destination from a dropdown, click "Save connection". You will then be prompted to provide specific configuration for the selected destination. ![A screenshot showing "Save connection" in the WorkOS Dashboard.](https://images.workoscdn.com/images/75ced694-5dbd-48c3-9784-5fdaf81e0420.png?auto=format&fit=clip&q=50) ## Admin Portal The Admin Portal can be accessed via a Setup Link found in the Organization page within the Dashboard. Click "Generate" and select "Log Streams". Copy the link and send it to the organization's IT contacts who will be configuring Log Streams. ![A screenshot showing where the "Generate" button is located in the WorkOS Dashboard.](https://images.workoscdn.com/images/f6410460-40e4-478c-b663-5920ac15b8a8.png?auto=format&fit=clip&q=50) You can also guide users to the Admin Portal by redirecting them to a programmatically generated Admin Portal link directly from your application. Once redirected to the Admin Portal, the user will be prompted to select a destination and will be provided with step-by-step configuration instructions for the selected destination. ![A screenshot showing log stream destination options in the WorkOS Admin Portal.](https://images.workoscdn.com/images/a6249873-d221-49eb-9c6a-c7706b2b4f77.png?auto=format&fit=clip&q=50) ## Streaming Destinations and Payload Formats WorkOS supports streaming audit log events to seven different types of destinations, each with its own payload format and configuration requirements: ### Datadog Events are sent to Datadog's HTTP Log Intake API with regional endpoint support. **Example Payload:** ```json [ { "message": { "id": "01HY123456ABCDEFGHIJK", "action": "user.signed_in", "targets": [ { "id": "user_123", "type": "user" } ], "actor": { "id": "user_456", "type": "user" }, "context": { "location": "192.168.1.1", "user_agent": "Chrome/91.0" }, "occurred_at": "2024-01-15T10:30:00.000Z" }, "ddsource": "team-name", "service": "audit-logs" } ] ``` **Configuration:** - API Key authentication - Regional endpoints (US1, US3, US5, EU1, US1-FED, AP1) - Optional team name as source identifier ### Splunk Events are sent to Splunk's HTTP Event Collector (HEC) endpoint. **Example Payload:** ```json [ { "event": { "id": "01HY123456ABCDEFGHIJK", "action": "user.signed_in", "targets": [ { "id": "user_123", "type": "user" } ], "actor": { "id": "user_456", "type": "user" }, "context": { "location": "192.168.1.1", "user_agent": "Chrome/91.0" }, "occurred_at": "2024-01-15T10:30:00.000Z" }, "time": 1705314600000, "source": "team-name" } ] ``` **Configuration:** - HEC Token authentication - Custom Splunk instance URL - Optional source identifier ### AWS S3 Events are stored as individual JSON files in an S3 bucket. We use a cross-account IAM role with an external ID ([details](https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html)) to authenticate to the destination bucket. We upload S3 objects with a `ContentMD5` header to support [uploading objects to Object Lock enabled buckets](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock-managing.html#object-lock-put-object). | Property | Description | | ------------------- | -------------------------------------------------------------- | | File Format | Individual JSON files per event with pretty-printed formatting | | File Naming Pattern | `YYYY-MM-DD/{timestamp}_{keySuffix}.json` | | Example Filename | `2024-01-15/2024-01-15T10:30:00.123Z_abc123def456.json` | **Example File Content:** ```json { "id": "01HY123456ABCDEFGHIJK", "action": "user.signed_in", "targets": [ { "id": "user_123", "type": "user" } ], "actor": { "id": "user_456", "type": "user" }, "context": { "location": "192.168.1.1", "user_agent": "Chrome/91.0" }, "occurred_at": "2024-01-15T10:30:00.000Z" } ``` **Configuration:** WorkOS authenticates to the destination S3 bucket using an AWS cross-account IAM role delegation with an external ID for enhanced security. This requires the following configuration: | Field Name | Code | Description | | -------------- | ------------ | ------------------------------------------------------------------------ | | AWS Account ID | `accountId` | Destination AWS account ID where the S3 bucket is located | | AWS Region | `region` | The AWS region for the destination S3 bucket (defaults to `us-east-1`) | | IAM Role Name | `roleName` | The name of the IAM role WorkOS will assume to access destination bucket | | S3 Bucket Name | `bucketName` | The name of the destination S3 bucket | | Bucket Path | `bucketPath` | Optional path prefix within the bucket where logs will be stored | **Authentication Flow:** 1. WorkOS uses AWS Security Token Service (STS) to assume a role in the destination AWS account 2. The role must be configured to trust WorkOS' AWS account ID (`workosAccountId`) as an external trusted entity 3. The role must require an External ID (`externalId`) that matches the unique value provided by WorkOS 4. The role must have an attached IAM policy granting `s3:PutObject` permissions on the bucket (and optional path prefix) 5. WorkOS receives temporary credentials from STS and uses them to upload audit log events to the destination S3 bucket **IAM Policy Requirements:** The IAM role must include a policy that allows `s3:PutObject` actions on the destination bucket. The policy resource should target destination bucket and optional path prefix: `arn:aws:s3:::bucket-name/optional-path/*`. Example policy that you need to create in the destination AWS account: ```json { "Version": "2012-10-17", "Statement": [ { "Sid": "LogStreamBucketPolicy", "Effect": "Allow", "Action": ["s3:PutObject"], "Resource": ["arn:aws:s3:::bucket-name/optional-path/*"] } ] } ``` ### Google Cloud Storage Events are stored as individual JSON files using Google Cloud Storage's S3-compatible API. | Property | Description | | ------------------- | --------------------------------------------------- | | File Format | Individual JSON files per event (same format as S3) | | File Naming Pattern | `{timestamp}_{keySuffix}.json` | **Example File Content:** ```json { "id": "01HY123456ABCDEFGHIJK", "action": "user.signed_in", "targets": [ { "id": "user_123", "type": "user" } ], "actor": { "id": "user_456", "type": "user" }, "context": { "location": "192.168.1.1", "user_agent": "Chrome/91.0" }, "occurred_at": "2024-01-15T10:30:00.000Z" } ``` **Configuration:** - Access Key ID and Secret Access Key are required when configuring a log stream to GCS - GCS bucket with S3-compatible access ### Microsoft Sentinel Events are sent to Microsoft Sentinel via the Azure Monitor Logs Ingestion API. **Example Payload:** ```json [ { "TimeGenerated": "2024-01-15T10:30:00.000Z", "id": "01HY123456ABCDEFGHIJK", "event_type": "user.signed_in", "organization_id": "org_01ABC123", "data": { "id": "01HY123456ABCDEFGHIJK", "action": "user.signed_in", "targets": [ { "id": "user_123", "type": "user" } ], "actor": { "id": "user_456", "type": "user" }, "context": { "location": "192.168.1.1", "user_agent": "Chrome/91.0" }, "occurred_at": "2024-01-15T10:30:00.000Z" } } ] ``` **Configuration:** | Property | Description | | ---------------------------- | ------------------------------------------------------ | | Tenant ID | Azure Active Directory tenant ID | | Client ID | Application (client) ID from Azure AD app registration | | Client Secret | Client secret from Azure AD app registration | | Data Collection Endpoint URL | The URL of the Data Collection Endpoint (DCE) | | Data Collection Rule ID | The immutable ID of the Data Collection Rule (DCR) | | Stream Name | The name of the Logs Stream | ### Snowflake Events are inserted as rows into a table in the customer's Snowflake data warehouse via the Snowflake SQL API. WorkOS authenticates with RSA key-pair authentication: you provide a private key and WorkOS signs a short-lived JWT that Snowflake verifies against the public key registered on your Snowflake user. No Snowflake password is shared. **Table schema:** Each event is written as one row. The target table must define these columns: | Column | Type | Description | | ----------------- | -------------- | ------------------------------------------------ | | `event_id` | `VARCHAR` | Unique identifier for the event | | `event_type` | `VARCHAR` | The event action (for example, `user.signed_in`) | | `occurred_at` | `TIMESTAMP_TZ` | When the event occurred | | `organization_id` | `VARCHAR` | The organization the event belongs to | | `data` | `VARIANT` | The full event payload as JSON | **Configuration:** | Property | Description | | ---------------------- | ---------------------------------------------------------------------------- | | Account URL | Your Snowflake account URL (e.g. `https://.snowflakecomputing.com`) | | Username | The Snowflake user the public key is registered on | | Private Key | The RSA private key WorkOS uses to sign authentication JWTs | | Private Key Passphrase | Optional. Required only if the private key is encrypted | | Warehouse | The warehouse that runs the inserts | | Database | The database containing the target table | | Schema | The schema containing the target table | | Table | The table that audit log events are written to | ### Generic HTTPS Events are sent to custom HTTP endpoints with configurable authentication and format options. **JSON Format Example:** ```json [ { "event": { "id": "01HY123456ABCDEFGHIJK", "action": "user.signed_in", "targets": [ { "id": "user_123", "type": "user" } ], "actor": { "id": "user_456", "type": "user" }, "context": { "location": "192.168.1.1", "user_agent": "Chrome/91.0" }, "occurred_at": "2024-01-15T10:30:00.000Z" }, "keySuffix": "abc123def456", "timestamp": "2024-01-15T10:30:00.123Z", "source": "team-name" } ] ``` **NDJSON Format Example:** ```json {"event":{"id":"01HY123456ABCDEFGHIJK","action":"user.signed_in",...},"keySuffix":"abc123def456","timestamp":"2024-01-15T10:30:00.123Z"} ``` **Configuration:** - Custom HTTP endpoint - Configurable authentication headers - Support for JSON or NDJSON formats - Content-Type handling (application/json or application/x-ndjson) ## Stream States and Management Audit log streams can be in one of four states that determine their operational status: ### Stream States | State | Description | | ------------ | --------------------------------------------------------- | | **Active** | Stream is functioning normally and delivering events | | **Inactive** | Stream is incomplete, manually disabled or paused | | **Error** | Stream encountered a retry-able error and will be retried | | **Invalid** | Stream has invalid credentials or configuration | ### State Transitions Streams automatically transition between states based on delivery outcomes: - **Active → Error**: When a retry-able error occurs during event delivery - **Active → Invalid**: When authentication or authorization fails - **Error → Active**: When retry succeeds after a previous error - **Invalid → Active**: When credentials are fixed and validation succeeds - **Any → Inactive**: When manually disabled through Dashboard or Admin Portal ### Updating Stream Configuration Stream configurations can be updated through: 1. **WorkOS Dashboard**: Navigate to the organization and modify the log stream configuration 2. **Admin Portal**: Generate a setup link for the organization's IT contacts to update settings ### Exporting Events Export Audit Log Events through the WorkOS Dashboard and API. ## Exporting Events You may need to export Audit Log Events in large chunks. WorkOS supports exporting events as CSV files through both the Dashboard and API. Exports are scoped to a single organization within a specified date range. Events from the past three months can be included in the export. You may define additional filters such as `actions`, `actors`, and `targets`. ### Creating an export through the Dashboard Exports can be manually created under the Organization page when viewing Audit Log Events by selecting "Export CSV" from the "Actions" dropdown. Set your filters and select "Generate CSV file". ![A screenshot showing how to generate an Audit Log export in the WorkOS Dashboard.](https://images.workoscdn.com/images/a5386939-652f-4cbb-aa88-7159e2ffc1dd.png?auto=format&fit=clip&q=50) ### Creating an export through the API Once the export has been created, fetch the export at a later time to access the `url` of the generated CSV file. > The URL will expire after 10 minutes. If the export is needed again at a later time, refetching the export will regenerate the URL. If the `state` of the export is still `pending`, poll the export until it is ready for download. ### Editing Events Modify existing event configuration with backwards compatibility. ## Editing Events Once you've successfully configured Audit Logs in the WorkOS Dashboard and begun emitting events, how do you go about modifying an event schema without breaking your existing integrations? This is where versioning comes into place. When you make a modification to an existing schema it will create a new version rather than overwriting the existing schema. The reason for this behavior is to ensure backwards compatibility. Schema configuration is immutable to prevent you from accidentally making changes that are incompatible with events that are already being emitted from your application. Rather you must first create a new version of the schema, and then explicitly emit events for that version leveraging the event `version` field. ### Creating a new event version In the WorkOS Dashboard navigate to the Audit Logs configuration page. Locate the event that you would like to modify the schema for and click the "Edit Event" item under the context menu. ![A screenshot showing the "Edit Event" option in the WorkOS Dashboard.](https://images.workoscdn.com/images/8ee56828-fc59-4c18-ae64-008a754cd2a6.png?auto=format&fit=clip&q=50) You will be navigated to a page where you can edit both the `targets` associated with the event, and optionally the metadata JSON schema. Once you're done making changes, clicking save will create a new version of the event schema. ![A screenshot showing the "Save as new version" button in the schema editor in the WorkOS Dashboard.](https://images.workoscdn.com/images/65d234a3-f530-4051-95a0-0162cfef122e.png?auto=format&fit=clip&q=50) ### Emitting event with version Now that a schema exists with a new version, the `version` field must be provided when emitting an event so that WorkOS knows which version to use for validation. ### Admin Portal View Audit Log events for an organization in the WorkOS Admin Portal. ## Creating Admin Portal Link Audit Log events can be viewed in the WorkOS [Admin Portal](/admin-portal). Links can be generated through the WorkOS API and sent to your customers for viewing events associated with their Organization. When creating a link for an Admin Portal session, you must provide the Organization ID whose events will be displayed in the Admin Portal, and specify the intent as `audit_logs`. Navigating to the provided link will result in the following view. Users will be able to view and export Audit Log events just as can be done through the WorkOS Dashboard. ![A screenshot showing Audit Log events in the WorkOS Admin Portal.](https://images.workoscdn.com/images/e08a07dd-4539-4c5a-9802-63d7c774b2c9.png?auto=format&fit=clip&q=50) ## Admin Portal {#admin-portal} ### Admin Portal A first-class Single Sign-On and Directory Sync onboarding experience for IT contacts. ## Introduction The Admin Portal provides an out-of-the-box UI for IT contacts to verify domains, configure SSO and Directory Sync connections, and more. Designed to remove friction, custom walk-through documentation for each identity provider means that IT contacts can onboard their organizations without high-touch support from your team. Easy to integrate and fully maintained and hosted by WorkOS, the Admin Portal makes Domain Verification, SSO, and Directory Sync setup simple, fast, and secure. ![A screenshot showing the IdP selection in the WorkOS Admin Portal.](https://images.workoscdn.com/images/dd00d92d-2810-484a-a3c7-4e0fdb8703a7.png?auto=format&fit=clip&q=50) ## Workflow Options There are two main workflows for initiating an Admin Portal session for IT contacts. You can either share a link to the Admin Portal from the WorkOS dashboard, or you can seamlessly integrate Admin Portal into your application through WorkOS SDKs or APIs. ![A screenshot showing the different workflows for creating an Admin Portal shareable link.](https://images.workoscdn.com/images/33851982-5baf-4ffe-8b41-71054b95948b.png?auto=format&fit=clip&q=50) If you want to provide IT contacts with a link to the Admin Portal, in an email for example, then you would need to create that link in the WorkOS dashboard. However, if you are adding a button to open the Admin Portal from within your application, then you would need to use the API. | Workflow | Use cases | Security | Return URL and Success URLs | | ------------------------------- | :--------------------------- | :------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------- | | Share a link from the dashboard | Setup only | Can be revoked; Automatically revoked on setup completion; Expires after 30 days | Not applicable | | Generate a link via the API | Setup and post-configuration | Cannot be revoked; Expires after 5 minutes | Can be configured on the [Redirects](https://dashboard.workos.com/redirects) page in the dashboard or specified as a parameter for the API | --- ## Before getting started To get the most out of these guides, you'll need: - A [WorkOS account](https://dashboard.workos.com/) ## API object definitions [Connection](/reference/sso/connection) : Represents the method by which users of an organization sign in to your application. [Organization](/reference/organization) : Describes an organization whose users sign in with an SSO connection, or whose users are synced with a Directory Sync connection. [Portal link](/reference/admin-portal/portal-link) : A temporary link to initiate an Admin Portal session. ## (A) Setup link from WorkOS dashboard The Admin Portal setup link gives your customer access to a guided configuration experience through our Admin Portal. It instructs them how to verify a domain, configure their identity or directory provider, and more. If successfully configured, no other action is required and you'll see verified domains and/or active connections appear under the organization. First decide whether your customer will be configuring Domain Verification, Single Sign-On, Directory Sync, Log Streams, or all of the above. Once you generate a link, the customer will have access for 30 days or until configured. You'll need a [WorkOS dashboard account](https://dashboard.workos.com/) to create an organization that will represent the enterprise you are onboarding. ### Create organization Sign in to your WorkOS dashboard account and create a new organization. ![WorkOS dashboard UI showing organization creation](https://images.workoscdn.com/images/1c69fd98-01be-491d-9255-58363bc6a983.png?auto=format&fit=clip&q=50) ### Generate a setup link Click the "Invite IT contact" button, select the features to include and then click "Next." Enter the emails of the IT contacts for the organization to automatically send them a setup link, or click "Copy setup link." Only one link can be active at a time. After creating the initial link, you can click the "Manage" button to revoke the existing link before creating a new one. ### Sharing a setup link If you chose to copy the setup link you can share it over email, Slack or direct message. We also recommend including details on what the link does and how long the link is active. ## (B) Integrate with your app In this guide, we'll walk you through the full end-to-end integration of the Admin Portal into your application. > [Sign in](https://dashboard.workos.com/) to your WorkOS dashboard account to see code examples pre-filled with your test API keys and resource IDs. ### Configure Admin Portal redirect links In order to integrate, you must configure your app's default return URI in the production environment. A button in the Admin Portal will use this value to allow users to return to your app unless otherwise specified when generating the Admin Portal link. ![A screenshot showing the Admin Portal Redirect Links tab to set redirect URIs in the WorkOS dashboard.](https://images.workoscdn.com/images/9df0f214-0350-466c-b54b-8a1e0be6b678.png?auto=format&fit=clip&q=50) Additionally, you can configure success URIs to redirect users upon successfully setting up Single Sign-On, Directory Sync, or Log Streams. ![A screenshot showing the Admin Portal redirect URI variations in the WorkOS dashboard.](https://images.workoscdn.com/images/3d75975c-b36a-4bfc-b05d-d745b8ba916b.png?auto=format&fit=clip&q=50) > All redirect links must use HTTPS. You can configure these links on the [Redirects](https://dashboard.workos.com/redirects) page in the dashboard. ### Install the WorkOS SDK WorkOS offers native SDKs in several popular programming languages. Choose a language below to see instructions in your application's language. ### Set secrets To make calls to WorkOS, provide the API key and, in some cases, the client ID. Store these values as managed secrets, such as `WORKOS_API_KEY` and `WORKOS_CLIENT_ID`, and pass them to the SDKs either as environment variables or directly in your app's configuration based on your preferences. ```plain title="Environment variables" WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' ``` ### Create a new organization 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 customer 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 customer. ### Redirect IT contacts to the Admin Portal A Portal link is your enterprise user's gateway to accessing the Admin Portal, where they can set up and manage resources scoped to their organization. To generate a Portal link using the API, you must provide the organization ID and specify one of the following intents: [`sso`](/admin-portal/c-using-admin-portal/managing-sso-connections), [`dsync`](/admin-portal/c-using-admin-portal/managing-directories), [`audit_logs`](/audit-logs/admin-portal/creating-admin-portal-link), [`log_streams`](/audit-logs/log-streams/admin-portal), [`domain_verification`](/domain-verification/admin-portal-domain-verification), or [`certificate_renewal`](/sso/signing-certificates/saml-response-signing-certificate/renewing-certificates). 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 contacts. An [optional return\_url parameter](/reference/admin-portal/portal-link/generate) 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 success URL configured on the [Redirects](https://dashboard.workos.com/redirects) page of the dashboard will be used. ### Add IT contacts programmatically When generating a Portal link via the API, emails can be added as IT contacts for the organization at the same time by passing the optional `it_contact_emails` parameter. This mirrors the behavior of the "Invite IT contact" flow in the WorkOS dashboard. IT contacts receive future organization notifications, such as alerts for expiring SSO certificates. ```bash title="Generate a Portal link and add IT contacts" curl --request POST \ --url "https://api.workos.com/portal/generate_link" \ --header "Authorization: Bearer sk_example_123456789" \ --header "Content-Type: application/json" \ -d '{ "organization": "org_01EHZNVPK3SFK441A1RGBFSHRT", "intent": "sso", "it_contact_emails": ["it-contact@example.com", "it-lead@example.com"] }' ``` Any email that isn't already an IT contact for the organization will be added; existing IT contacts remain unchanged, so the same call can be made repeatedly with the full list of contacts without creating duplicates. Email matching is case-insensitive. An organization can have up to 20 IT contacts at a time. A request that would exceed this limit is rejected and no IT contacts from the request are created. Invalid email addresses are rejected without creating any IT contacts. Adding an email via `it_contact_emails` does not restrict who can use the Portal link, and it does not send a notification to the IT contact. The Portal link must still be delivered by the calling application—typically by redirecting the current authenticated user immediately. See the [Generate a Portal Link reference](/reference/admin-portal/portal-link/generate) for the full request schema. ## (C) Using Admin Portal In this guide, we'll review some of the features of Admin Portal from an IT contact's perspective. ### Verifying a domain In the Admin Portal [Domain Verification](/domain-verification/admin-portal-domain-verification) flow, you can view instructions on adding a DNS TXT record to prove ownership of your organization's domain(s). > Unless an organization [allows any domain](/sso/domains/allowing-any-domain), a verified domain is required in order to activate SSO. Domains can also be [manually verified](/authkit/domain-verification/self-serve-domain-verification) outside of the self-serve Admin Portal flow if the IT contact has already proven domain ownership in another context. ### Managing SSO connections On the Admin Portal SSO screen, you can view the identity provider details and connection status, metadata configuration details, and a list of recent connection sessions. You may test your SSO connection from the Admin Portal by using the "Test sign-in" button. ![A screenshot showing the Admin Portal SSO screen and where to click the "Test Single Sign-On" button.](https://images.workoscdn.com/images/b9ab3cc1-c524-4eae-9a25-f4c6a4059683.png?auto=format&fit=clip&q=50) You may also edit your metadata configuration from the Admin Portal. ![A screenshot showing the Admin Portal SSO screen and where to "Edit Metadata Configuration".](https://images.workoscdn.com/images/2ada73aa-dfa4-45c8-afc8-2e69a3a9b4fc.png?auto=format&fit=clip&q=50) The Sessions section displays a list of recent sessions by timestamp, and can be sorted by `state`. ![A screenshot showing the Admin Portal SSO screen and how to sort "Sessions" by "state".](https://images.workoscdn.com/images/0b1b05a0-8c18-4c99-8d02-22f2b4f2bf46.png?auto=format&fit=clip&q=50) Click on a session in the list to see session details, such as the request made to the IdP, and the response. ![A screenshot showing the "Session Details" within the Admin Portal SSO screen.](https://images.workoscdn.com/images/6655ae75-c0c2-4b0c-be7b-b21dbfb6aadd.png?auto=format&fit=clip&q=50) If you wish to reset your SSO connection and set it up from scratch, select "Reset Connection" and follow the prompts. ![A screenshot showing how to "Reset Connection" within the Admin Portal SSO screen.](https://images.workoscdn.com/images/b0f2919d-07f2-457d-8499-1b617235c485.png?auto=format&fit=clip&q=50) ### Managing directories On the Admin Portal Directory Sync screen, you can view the directory provider details and connection status, user and group counts, and last sync time. There is also an option to reset the directory. ![A screenshot showing Admin Portal Directory Sync screen details.](https://images.workoscdn.com/images/13be17b8-46da-4c2c-801f-029be3686101.png?auto=format&fit=clip&q=50) You may also view and edit the attribute map from the synced directory by clicking "Edit Attribute Map". ![A screenshot showing editing the attribute map in the Admin Portal Directory Sync screen.](https://images.workoscdn.com/images/c6dd347f-15dc-4918-9820-946f38361c2e.png?auto=format&fit=clip&q=50) If you wish to update the groups that are being synced, select "Edit groups sync" and follow the prompts on the next page. ![A screenshot showing editing user groups in the Admin Portal Directory Sync screen.](https://images.workoscdn.com/images/05fc69da-3688-4c90-873b-505be64779b9.png?auto=format&fit=clip&q=50) You can also view a complete list of users from all selected groups in your synced directory. ![A screenshot showing the user list in the Admin Portal Directory Sync screen.](https://images.workoscdn.com/images/f581e97e-2052-4635-805c-fad3c47f792e.png?auto=format&fit=clip&q=50) ### Bearer token rotation Create and revoke SCIM bearer tokens from the WorkOS Dashboard or Admin Portal. ## Overview SCIM bearer tokens authenticate the requests an identity provider sends to your directory sync endpoint. Tokens can now be created and revoked on demand from two places: - The **WorkOS Dashboard** — on the directory details page, replacing the static bearer token field. - The **Admin Portal** — on the post-configuration page for an existing directory, so IT contacts can manage tokens themselves without contacting your team. Up to two tokens can be active on a directory at the same time, which makes it possible to rotate tokens with no downtime. ## Why this matters - **Customer self-service.** IT contacts can rotate a leaked or expiring token from the Admin Portal without filing a support ticket or waiting on your engineering team. - **Zero-downtime rotation.** Because two tokens can be active at once, you can roll a new token out to the identity provider and confirm SCIM traffic is healthy before revoking the old one. - **Better hygiene.** Newly generated tokens are revealed exactly once at creation time which limits the impact of a leaked dashboard or admin portal session. ## Managing tokens in the Dashboard Sign in to the [WorkOS Dashboard](https://dashboard.workos.com/) and open the directory you want to manage. The **Bearer tokens** card on the directory details page lists every active token along with when it was created and last used. ![The WorkOS Dashboard showing the bearer tokens card on the directory details page.](https://images.workoscdn.com/images/2b438d96-e5a4-4102-bb2d-a6d8324d2278.png) To generate a token, click **Generate token**. The new token is shown once. Copy it immediately and store it somewhere secure; you will not be able to view it again. To revoke a token, click on the revoke action for the row you are removing and confirm the revocation. Any SCIM requests still using that token will start failing immediately after it is revoked, so make sure the identity provider has been updated to use a different active token first. ## Managing tokens in the Admin Portal When an IT contact opens the Admin Portal post-configuration page for a SCIM directory, they see the same **Bearer tokens** card with the same generate and revoke actions. ![The Admin Portal post-configuration page showing the bearer tokens card.](https://images.workoscdn.com/images/50777e5f-0dca-4153-b960-445c6ed5d836.png) After clicking **Generate token**, the IT contact is shown the secret once and prompted to copy it into their identity provider. Once both tokens are active, a callout reminds them to update their identity provider and revoke the older token when they are done. ## Zero-downtime rotation The recommended flow for rotating a token without dropping SCIM traffic: 1. From the Dashboard or the Admin Portal, click **Generate token** to create a second token. Copy the secret. 2. Update the identity provider's SCIM connector with the new token. 3. Trigger or wait for a SCIM request and confirm the new token's **Last used** timestamp updates. 4. Revoke the old token. A directory can have at most two active tokens at any time. If you already have two, revoke one before generating another. ## Migration There is nothing to do for existing integrations. - **No code changes.** Your application continues to consume the same SCIM endpoint, and existing webhook payloads, SDK calls, and event types are unchanged. - **No breaking changes.** Tokens currently displayed in the Dashboard keep working until they are explicitly revoked. - **New tokens are managed in the new UI.** Tokens generated from the Dashboard or Admin Portal are only viewable at creation time and only manageable through the new token UI in either surface. ### Example Apps View sample Admin Portal apps for each SDK. You can view minimal example apps that demonstrate how to use the WorkOS SDKs to power the Admin Portal: ### Custom Branding Use your own logo and colors in the Admin Portal. ## Introduction You can customize the look and feel of the Admin Portal from the WorkOS Dashboard. Go to [Branding settings](https://dashboard.workos.com/branding) where you can: - Upload your logos - Set your brand color - View your custom domains ![A screenshot showing the WorkOS Dashboard branding settings page.](https://images.workoscdn.com/images/fc67ec10-44e1-467c-a094-32ed3ff5bd92.png?auto=format&fit=clip&q=80) ## Logos and icons You can upload custom branding assets which will be used in the Admin Portal as well as emails. ### Logo Image with your company's logo and wordmark. - **Usage:** Shown in the top left corner of the Admin Portal. - **Requirements:** At least 160x160 px (JPG, PNG, or SVG. 100 KB max size) ![A screenshot showing the WorkOS Admin Portal and highlighting the custom logo.](https://images.workoscdn.com/images/ca579b3c-6a50-41aa-ad3e-62b32740b6c8.png?auto=format&fit=clip&q=50) ### Logo icon A smaller, square version of the logo. This is often simply the logomark. ![A screenshot showing an email from WorkOS and highlighting the custom logo icon.](https://images.workoscdn.com/images/df8b54e6-a3fc-431b-8086-a01fb03388c7.png?auto=format&fit=clip&q=50) ![A screenshot showing the WorkOS Admin Portal and highlighting the custom logo icon download.](https://images.workoscdn.com/images/d07c701e-a051-4444-ae66-fc35eecb6791.png?auto=format&fit=clip&q=50) ### Favicon A small icon that serves as branding for your website. - **Usage:** Displayed in the address bar of the Admin Portal website. - **Requirements:** At least 32x32 px with a 1:1 aspect ratio (JPG, PNG, GIF, SVG, WebP, AVIF, or ICO. 100 KB max size) ![A screenshot showing the WorkOS Admin Portal and highlighting the custom favicon.](https://images.workoscdn.com/images/15dd6370-961d-4d8b-97b1-6bfc3ef80143.png?auto=format&fit=clip&q=50) ### Brand color Hex value used as the background color for buttons in the Admin Portal and emails. ![A screenshot showing the WorkOS Admin Portal and highlighting the custom button color.](https://images.workoscdn.com/images/080c0c45-08ee-44c4-b153-7b419174fc5e.png?auto=format&fit=clip&q=50) ![A screenshot showing an email from WorkOS and highlighting the custom button color.](https://images.workoscdn.com/images/6da61ac8-82f1-44e6-ab55-33d699841739.png?auto=format&fit=clip&q=50) ## Custom domains WorkOS allows you to customize the domain you send API calls to, the domain used by the Admin Portal, and the from address used in emails sent to your customers' IT contacts. ![A screenshot showing the WorkOS Dashboard branding settings page highlighting the custom domains section](https://images.workoscdn.com/images/b6afe130-219c-4e0e-8209-49b1a0fb6098.png?auto=format&fit=clip&q=80) ### Auth link domain Controls the domain you send API calls to and the domain used in URLs that face your customers' IT contacts such as ACS URL and SP Entity ID. ### Admin Portal domain Controls the domain of Admin Portal setup links and Admin Portal sessions opened by your customers' IT contacts. ### Email domain Controls the from address for emails sent to your customers' IT contacts. To configure custom domains, please reach out to [customer support](mailto:support@workos.com) for assistance. ## Display name The [display name](/authkit/branding) set in your branding is visible in the Admin Portal and in the emails received by your customers' IT contacts. It's configured per environment, so each environment can present its own name. ![A screenshot showing the WorkOS Admin Portal and highlighting the page title.](https://images.workoscdn.com/images/0fd29434-3a5a-43ed-a446-45aec90f75da.png?auto=format&fit=clip&q=50) ![A screenshot showing an email by WorkOS and highlighting the sender name.](https://images.workoscdn.com/images/8d679e97-ceaa-4b94-bb75-290619c94085.png?auto=format&fit=clip&q=50) ## Support email address Add a support email in the Dashboard to streamline communication with your customers' IT contacts. This email will be included in the footer of messages sent to them and set as the reply-to address, making it easy for IT contacts to reach out with any questions. ![A screenshot showing an email with a custom support email address](https://images.workoscdn.com/images/8eb036ab-5fd0-44fe-81f3-6a69a8c38530.png?auto=format&fit=clip&q=50)