Configure the Medusa Admin for SSO
In this guide, you'll learn how to configure the Medusa Admin dashboard's SSO login, using the OIDC Auth Module Provider.
Overview#
The Medusa Admin dashboard renders a login button for every authentication provider that admin users are allowed to use, so you don't need to build the button yourself.
On the login page, the dashboard:
- Retrieves the providers allowed for the
useractor type from the List Auth Providers API route. - Renders a "Continue with" button for every provider that authenticates through a redirect, which is what the OIDC provider does. The button is labeled with the provider's
display_nameoption. - Handles the redirect back from the identity provider, creates or links the admin user of the authenticated identity, and logs the user in.
So, the sections below cover the configurations that shape that login, not the flow itself. Refer to the How SSO Works guide for a walkthrough of every request in the flow.
Set the Provider's Display Name#
The dashboard labels the button with the provider's display_name option, which defaults to OpenID Connect. Set it to the name of your identity provider so users recognize it:
module.exports = defineConfig({
// ...
modules: [
{
resolve: "@medusajs/medusa/auth",
// ...
options: {
providers: [
// ...
{
resolve: "@medusajs/medusa/auth-oidc",
id: "okta",
options: {
// ...
display_name: "Okta",
},
},
],
},
},
],
})
The dashboard then shows a "Continue with Okta" button on the login page.
Register the Dashboard's Callback URL#
The dashboard sends its own callback URL when it starts the authentication, in the following format:
For example, if you registered the provider with the ID okta, the callback URL of a Medusa application running locally is:
While in production, it uses your application's public URL instead:
So, register the URL of every environment whose dashboard authenticates with the identity provider.
Add that URL to the redirect URIs of the application you registered with your identity provider. Refer to the Identity Providers guide for where to set it in common identity providers.
If you set the allowed_callback_urls option, add the same URL to it. Otherwise, Medusa rejects the dashboard's login request.
Make the Dashboard SSO-Only#
The dashboard only renders the email and password form when admin users are allowed to use the emailpass provider. So, to require SSO for every admin user, remove emailpass from the user actor type:
module.exports = defineConfig({
projectConfig: {
http: {
// ...
authMethodsPerActor: {
user: ["okta"],
customer: ["emailpass"],
},
},
// ...
},
// ...
})
The login page then shows the SSO button only. The "Forgot password?" link is tied to the same form, so it's hidden as well.
emailpass again. Keep a way back in, such as access to the environment variables of your deployment.Set the Created User's Name#
By default, when Medusa creates an admin user through SSO, the OIDC provider stores the following metadata from the authenticated identity:
These fields are mapped from the claims in the ID token returned by the OIDC provider, such as Okta.
Then, when Medusa creates the admin user, it reads the user's first and last name from the given_name and family_name fields of the authenticated identity's metadata in case they're stored, but the OIDC provider doesn't store them by default.
To store the given_name and family_name fields from the integrated provider, use the claim_mappings option:
module.exports = defineConfig({
// ...
modules: [
{
resolve: "@medusajs/medusa/auth",
// ...
options: {
providers: [
// ...
{
resolve: "@medusajs/medusa/auth-oidc",
id: "okta",
options: {
// ...
claim_mappings: {
given_name: "given_name",
family_name: "family_name",
},
},
},
],
},
},
],
})
In this example, you map the and claims that Okta returns in the ID token to the corresponding fields in the identity's metadata. The OIDC provider will then store these fields, allowing Medusa to read the user's first and last name when creating the admin user.
Use Different Claim Names#
given_name and family_name are standard OIDC claims, so most identity providers return them under these same names. If the identity provider you're integrating returns the name under different claims, change the values instead:
module.exports = defineConfig({
// ...
modules: [
{
resolve: "@medusajs/medusa/auth",
// ...
options: {
providers: [
// ...
{
resolve: "@medusajs/medusa/auth-oidc",
id: "custom-provider",
options: {
// ...
claim_mappings: {
given_name: "first_name",
family_name: "last_name",
},
},
},
],
},
},
],
})
Map Custom Claims#
claim_mappings isn't limited to the fields that Medusa reads. Any other field you add is stored in the authenticated identity's metadata, which your customizations can then read.
For example, if your Okta users have a department attribute, add a claim for it in Okta, then map it in the provider's options:
module.exports = defineConfig({
// ...
modules: [
{
resolve: "@medusajs/medusa/auth",
// ...
options: {
providers: [
// ...
{
resolve: "@medusajs/medusa/auth-oidc",
id: "okta",
options: {
// ...
claim_mappings: {
department: "department",
},
},
},
],
},
},
],
})
In Okta, you add the claim to your authorization server, mapping the user.department profile attribute to a claim named department and including it in the ID token. Refer to Okta's documentation for the steps.
Medusa then stores the claim in the identity's metadata on every login, so you can read it in your API routes and middlewares: