Google - Admin SSO Provider
- Properly configure Strapi for SSO
- Create your Google OAuth2 app by following the steps in the Google Console.
- Gather the required information to set as environment variables in your Strapi project:
- GOOGLE_CLIENT_ID
- GOOGLE_CLIENT_SECRET
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
- JavaScript
- TypeScript
module.exports = ({ env }) => ({
// ...
url: env('PUBLIC_URL', 'https://api.example.com'),
proxy: {
koa: env.bool('TRUST_PROXY', true),
},
// ...
});
export default ({ 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
- JavaScript
- TypeScript
module.exports = ({ env }) => ({
// ...
url: env('PUBLIC_URL', 'https://api.example.com'),
proxy: {
koa: env.bool('TRUST_PROXY', true),
global: env('GLOBAL_PROXY'),
},
// ...
});
export default ({ 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
)
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.
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
- JavaScript
- TypeScript
module.exports = ({ env }) => ({
// ...
url: env('PUBLIC_ADMIN_URL', 'https://admin.example.com'),
auth: {
domain: env("ADMIN_SSO_DOMAIN", ".example.com"),
providers: [
// ...
],
},
// ...
});
export default ({ 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.
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
- JavaScript
- TypeScript
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,
},
},
},
},
// ...
]
export default [
// ...
{
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 Google 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:
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/userinfo.profile
Profile Data
Data returned from the provider is dependent on how your Google OAuth2 application is configured. The example below assumes that the Google 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 Google 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
(request, accessToken, refreshToken, profile, done) => {
// See what is returned by the provider
console.log(profile);
done(null, {
// Map the data returned by the provider to the Strapi user object
email: profile.email,
firstname: profile.given_name,
lastname: profile.family_name,
});
}
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("google"),
In this example the redirect URL/URI used by the provider will be https://api.example.com/admin/connect/google
.
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/google
is the specific provider UID for Google
Strapi Configuration
Using: passport-google-oauth2
Install the Provider Package
- yarn
- npm
yarn add passport-google-oauth2
npm install --save passport-google-oauth2
Adding the Provider to Strapi
- JavaScript
- TypeScript
const GoogleStrategy = require("passport-google-oauth2");
module.exports = ({ env }) => ({
auth: {
// ...
providers: [
{
uid: "google",
displayName: "Google",
icon: "https://cdn2.iconfinder.com/data/icons/social-icons-33/128/Google-512.png",
createStrategy: (strapi) =>
new GoogleStrategy(
{
clientID: env("GOOGLE_CLIENT_ID"),
clientSecret: env("GOOGLE_CLIENT_SECRET"),
scope: [
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
],
callbackURL:
env('PUBLIC_URL') +
strapi.admin.services.passport.getStrategyCallbackURL("google"),
},
(request, accessToken, refreshToken, profile, done) => {
done(null, {
email: profile.email,
firstname: profile.given_name,
lastname: profile.family_name,
});
}
),
},
],
},
});
import {Strategy as GoogleStrategy } from "passport-google-oauth2";
export default ({ env }) => ({
auth: {
// ...
providers: [
{
uid: "google",
displayName: "Google",
icon: "https://cdn2.iconfinder.com/data/icons/social-icons-33/128/Google-512.png",
createStrategy: (strapi) =>
new GoogleStrategy(
{
clientID: env("GOOGLE_CLIENT_ID"),
clientSecret: env("GOOGLE_CLIENT_SECRET"),
scope: [
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
],
callbackURL:
env('PUBLIC_URL') +
strapi.admin.services.passport.getStrategyCallbackURL("google"),
},
(request, accessToken, refreshToken, profile, done) => {
done(null, {
email: profile.email,
firstname: profile.given_name,
lastname: profile.family_name,
});
}
),
},
],
},
});