Skip to main content

Google Auth Hook

You can also find the complete source code for this guide in the unleash-examples project.

This part of the tutorial shows how to create a sign-in flow for users and integrate with Unleash server project. The implementation assumes that I am working in localhost with 4242 port.

This is a simple index.js server file.

const unleash = require('unleash-server');
unleash.start(options).then(unleash => {
console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`);
});

Creating a web application client ID#

  1. Go to the credentials section in the Google Cloud Platform Console.

  2. Click OAuth consent screen. Type a product name. Fill in any relevant optional fields. Click Save.

  3. Click Create credentials > OAuth client ID.

  4. Under Application type, select Web Application.

  5. Type the Name.

  6. Under Authorized redirect URIs enter the following URLs, one at a time.

http://localhost:4242/api/auth/callback
  1. Click Create.

  2. Copy the CLIENT ID and CLIENT SECRET and save them for later use.

Add dependencies#

Add two dependencies @passport-next/passport and @passport-next/passport-google-oauth2 inside index.js file

const unleash = require('unleash-server');
const passport = require('@passport-next/passport');
const GoogleOAuth2Strategy = require('@passport-next/passport-google-oauth2')
.Strategy;

Configure the Google strategy for use by Passport.js#

OAuth 2-based strategies require a verify function which receives the credential (accessToken) for accessing the Google API on the user's behalf, along with the user's profile. The function must invoke cb with a user object, which will be set at req.user in route handlers after authentication.

const GOOGLE_CLIENT_ID = '...';
const GOOGLE_CLIENT_SECRET = '...';
const GOOGLE_CALLBACK_URL = 'http://localhost:4242/api/auth/callback';
passport.use(
new GoogleOAuth2Strategy(
{
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: GOOGLE_CALLBACK_URL,
},
function(accessToken, refreshToken, profile, cb) {
// Extract the minimal profile information we need from the profile object
// and connect with Unleash to get name and email.
cb(
null,
new unleash.User({
name: profile.displayName,
email: profile.emails[0].value,
}),
);
},
),
);

Add googleAdminAuth() function and other options

function googleAdminAuth(app) {}
let options = {
adminAuthentication: 'custom',
preRouterHook: googleAdminAuth,
};
unleash.start(options).then(instance => {
console.log(
`Unleash started on http://localhost:${instance.app.get('port')}`,
);
});

In googleAdminAuth function#

Configure passport package.

function googleAdminAuth(app) {
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((user, done) => done(null, user));
// ...
}

Implement a preRouter hook for /api/admin/login. It's necessary for login with Google.

function googleAdminAuth(app) {
// ...
app.get(
'/api/admin/login',
passport.authenticate('google', { scope: ['email'] }),
);
// ...
}

Implement a preRouter hook for /api/auth/callback. It's a callback when the login is executed.

function googleAdminAuth(app) {
// ...
app.get(
'/api/auth/callback',
passport.authenticate('google', {
failureRedirect: '/api/admin/error-login',
}),
(req, res) => {
// Successful authentication, redirect to your app.
res.redirect('/');
},
);
// ...
}

Implement a preRouter hook for /api/admin.

function googleAdminAuth(app) {
// ...
app.use('/api/admin/', (req, res, next) => {
if (req.user) {
next();
} else {
// Instruct unleash-frontend to pop-up auth dialog
return res
.status('401')
.json(
new unleash.AuthenticationRequired({
path: '/api/admin/login',
type: 'custom',
message: `You have to identify yourself in order to use Unleash. Click the button and follow the instructions.`,
}),
)
.end();
}
});
// ...
}

The complete code#

The index.js server file.

'use strict';
const unleash = require('unleash-server');
const passport = require('@passport-next/passport');
const GoogleOAuth2Strategy = require('@passport-next/passport-google-oauth2');
const GOOGLE_CLIENT_ID = '...';
const GOOGLE_CLIENT_SECRET = '...';
const GOOGLE_CALLBACK_URL = 'http://localhost:4242/api/auth/callback';
passport.use(
new GoogleOAuth2Strategy(
{
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: GOOGLE_CALLBACK_URL,
},
(accessToken, refreshToken, profile, cb) => {
cb(
null,
new unleash.User({
name: profile.displayName,
email: profile.emails[0].value,
}),
);
},
),
);
function googleAdminAuth(app) {
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((user, done) => done(null, user));
app.get(
'/api/admin/login',
passport.authenticate('google', { scope: ['email'] }),
);
app.get(
'/api/auth/callback',
passport.authenticate('google', {
failureRedirect: '/api/admin/error-login',
}),
(req, res) => {
res.redirect('/');
},
);
app.use('/api/admin/', (req, res, next) => {
if (req.user) {
next();
} else {
return res
.status('401')
.json(
new unleash.AuthenticationRequired({
path: '/api/admin/login',
type: 'custom',
message: `You have to identify yourself in order to use Unleash. Click the button and follow the instructions.`,
}),
)
.end();
}
});
}
const options = {
adminAuthentication: 'custom',
preRouterHook: googleAdminAuth,
};
unleash.start(options).then(instance => {
console.log(
`Unleash started on http://localhost:${instance.app.get('port')}`,
);
});