Skip to main content

Okta - Admin SSO Provider

☑️ Prerequisites
  • Properly configure Strapi for SSO
  • Create your Okta OAuth2 app by following the steps in the Okta portal.
  • Gather the required information to set as environment variables in your Strapi project:
    • OKTA_CLIENT_ID
    • OKTA_CLIENT_SECRET
    • OKTA_DOMAIN
⚠️ Warning

When setting the OKTA_DOMAIN environment variable, make sure to include the protocol (e.g. https://example.okta.com). If you do not, you will end up in a redirect loop.

Required configuration before setting up SSO

Server Configuration

The following server configurations are required when using SSO, for more information on available options please see the Server Configuration documentation.

  • url: The public facing URL of your Strapi application. (e.g. https://api.example.com)
  • proxy.koa: Enabling trusted reverse proxy support. (true)
Admin Required Configuration Example
./config/server.js

module.exports = ({ env }) => ({
// ...
url: env('PUBLIC_URL', 'https://api.example.com'),
proxy: {
koa: env.bool('TRUST_PROXY', true),
},
// ...
});

There are also some optional configurations that you can set should it be necessary:

  • proxy.global: If you are in a restricted network environment that requires a forward proxy (e.g Squid) for all outgoing requests. (e.g. http://username:password@yourProxy:3128)
Admin Optional Configuration Example
./config/server.js

module.exports = ({ env }) => ({
// ...
url: env('PUBLIC_URL', 'https://api.example.com'),
proxy: {
koa: env.bool('TRUST_PROXY', true),
global: env('GLOBAL_PROXY'),
},
// ...
});

Admin Configuration

There are some optional configurations that you can set should it be necessary, for more information on available options please see the Admin Configuration documentation.

  • url: The public facing URL of your Strapi administration panel. (e.g. https://admin.example.com)
  • auth.domain: Setting a custom domain for cookie storage. (e.g. .example.com)
✏️ Note

When deploying the admin panel to a different location or on a different subdomain, an additional configuration is required to set the common domain for the cookies. This is required to ensure the cookies are shared across the domains.

Caution

Deploying the admin and backend on entirely different unrelated domains is not possible at this time when using SSO due to restrictions in cross-domain cookies.

Admin Optional Configuration Example
./config/admin.js

module.exports = ({ env }) => ({
// ...
url: env('PUBLIC_ADMIN_URL', 'https://admin.example.com'),
auth: {
domain: env("ADMIN_SSO_DOMAIN", ".example.com"),
providers: [
// ...
],
},
// ...
});

Middlewares Configuration

The following middleware configurations are required when using SSO, for more information on available options please see the Middlewares Configuration documentation.

  • contentSecurityPolicy: Allows you to configure the Content Security Policy (CSP) for your Strapi application. This is used to prevent cross-site scripting attacks by allowing you to control what resources can be loaded by your application.
✏️ Note

By default, Strapi security policy does not allow loading images from external URLs, so provider logos will not show up on the login screen of the admin panel unless a security exception is added or you use a file uploaded directly on your Strapi application.

Middlewares Configuration Example
./config/middlewares.js
module.exports = [
// ...
{
name: 'strapi::security',
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
'connect-src': ["'self'", 'https:'],
'img-src': [
"'self'",
'data:',
'blob:',
'market-assets.strapi.io',
'cdn2.iconfinder.com', // Base URL of the provider's logo without the protocol
],
'media-src': [
"'self'",
'data:',
'blob:',
'market-assets.strapi.io',
'cdn2.iconfinder.com', // Base URL of the provider's logo without the protocol
],
upgradeInsecureRequests: null,
},
},
},
},
// ...
]

Provider Specific Notes

Scopes

The Okta OAuth2 provider requires the following scopes, however additional scopes can be added as needed depending on your use case and the data you need returned:

Profile Data

Data returned from the provider is dependent on how your Okta OAuth2 application is configured. The example below assumes that the Okta OAuth2 application is configured to return the user's email, first name, and last name. Fields returned by the provider can change based on the scopes requested and the user's Okta account settings.

If you aren't sure what data is being returned by the provider, you can log the profile object in the createStrategy function to see what data is available as seen in the following example.

Configuration Example with Logging
(accessToken, refreshToken, profile, done) => {
// See what is returned by the provider
console.log(profile);

done(null, {
email: profile.email,
username: profile.username,
});
}

Redirect URL/URI

The redirect URL/URI will be dependent on your provider configuration however in most cases should combine your application's public URL and the provider's callback URL. The example below shows how to combine the public URL with the provider's callback URL.

callbackURL:
env('PUBLIC_URL', "https://api.example.com") +
strapi.admin.services.passport.getStrategyCallbackURL("okta"),

In this example the redirect URL/URI used by the provider will be https://api.example.com/admin/connect/okta.

This is broken down as follows:

  • https://api.example.com is the public URL of your Strapi application
  • /admin/connect is the general path for SSO callbacks in Strapi
  • /okta is the specific provider UID for Okta

Strapi Configuration

Using: passport-okta-oauth20

Install the Provider Package

yarn add passport-okta-oauth20

Adding the Provider to Strapi

./config/admin.js
const OktaOAuth2Strategy = require("passport-okta-oauth20").Strategy;

module.exports = ({ env }) => ({
auth: {
// ...
providers: [
{
uid: "okta",
displayName: "Okta",
icon: "https://www.okta.com/sites/default/files/Okta_Logo_BrightBlue_Medium-thumbnail.png",
createStrategy: (strapi) =>
new OktaOAuth2Strategy(
{
clientID: env("OKTA_CLIENT_ID"),
clientSecret: env("OKTA_CLIENT_SECRET"),
audience: env("OKTA_DOMAIN"),
scope: ["openid", "email", "profile"],
callbackURL:
env('PUBLIC_URL') +
strapi.admin.services.passport.getStrategyCallbackURL("okta"),
},
(accessToken, refreshToken, profile, done) => {
done(null, {
email: profile.email,
username: profile.username,
});
}
),
},
],
},
});