Learn the differences between SP‑initiated and IdP‑initiated SSO.
The instructions in the Quick Start guide 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) 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.
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 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.
import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); const clientId = process.env.WORKOS_CLIENT_ID; const authorizationUrl = workos.sso.getAuthorizationUrl({ clientId, connection: 'connection_123', redirectUri: 'https://your-app.com/callback', state: 'dj1kUXc0dzlXZ1hjUQ==', });
If you follow the instructions in the Quick Start guide, 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.
Additionally, since IdP-initiated flows do not generate a customized authorization URL the way SP-initiated flows do, there is no way to dynamically pass the redirectURI
and state
parameters to your application’s callback. By default, users will be redirected to the default Redirect URI upon a successful login. However, IdP Administrators can customize the redirect destination by configuring a default RelayState
in the IdP, and including a redirect_uri
parameter in it. The URI must be specified in the format of a URL parameter: redirect_uri=uri
, and the URI must be one of the Redirect URIs specified in your WorkOS Dashboard. Any other values in the IdP’s RelayState
will be ignored and discarded.
Your application will also be able to retrieve the Profile object 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 to dynamically generate a redirect URI.
{ "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", "raw_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.
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 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:
idp_initiated_sso_disabled
error.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.
import type { NextApiRequest, NextApiResponse } from 'next'; import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); const clientId = process.env.WORKOS_CLIENT_ID; export default async (req: NextApiRequest, res: NextApiResponse) => { const { code, error, connection_id } = req.query; if (error === 'idp_initiated_sso_disabled') { // The callback URI WorkOS should redirect to after the authentication const redirectUri = 'https://dashboard.my-app.com/'; // The state parameter can be used to encode the current state of your app const state = 'dj1kUXc0dzlXZ1hjUQ=='; const authorizationUrl = workos.sso.getAuthorizationUrl({ clientId, redirectUri, state, connection: connection_id, }); res.redirect(authorizationUrl); } else if (!error) { const { profile } = await workos.sso.getProfileAndToken({ code, clientId, }); // Use the information in `profile` for further business logic. res.redirect('/'); } };
const express = require('express'); const { WorkOS } = require('@workos-inc/node'); const app = express(); const workos = new WorkOS(process.env.WORKOS_API_KEY); const clientId = process.env.WORKOS_CLIENT_ID; app.get('/callback', async (req, res) => { const { code, error, connection_id } = req.query; if (error === 'idp_initiated_sso_disabled') { // The callback URI WorkOS should redirect to after the authentication const redirectUri = 'https://dashboard.my-app.com/'; // The state parameter can be used to encode the current state of your app const state = 'dj1kUXc0dzlXZ1hjUQ=='; const authorizationUrl = workos.sso.getAuthorizationUrl({ clientId, redirectUri, state, connection: connection_id, }); res.redirect(authorizationUrl); } else if (!error) { const { profile } = await workos.sso.getProfileAndToken({ code, clientId, }); // Use the information in `profile` for further business logic. res.redirect('/'); } });
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 User Management, a complete authentication platform that leverages Single Sign-On functionality out of the box, following best practices.