2018-11-22 04:07:15 +01:00
---
title: Google Auth Hook
---
2021-05-18 11:19:33 +02:00
> You can also find the complete [source code for this guide](https://github.com/Unleash/unleash-examples/tree/main/v4/securing-google-auth) in the unleash-examples project.
2018-11-22 04:07:15 +01:00
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.
2023-10-31 15:38:03 +01:00
**If you are still using Unleash v3 you need to follow the [google-auth-hook-v3 ](google-auth-v3 )**
2021-05-18 11:19:33 +02:00
2021-08-12 15:04:37 +02:00
This is a simple `index.ts` server file.
2018-11-22 11:20:28 +01:00
2018-11-22 04:07:15 +01:00
```javascript
const unleash = require('unleash-server');
2021-08-12 15:04:37 +02:00
unleash.start(options).then((unleash) => {
2018-11-22 04:07:15 +01:00
console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`);
2018-11-22 11:20:28 +01:00
});
2018-11-22 04:07:15 +01:00
```
2021-06-04 11:17:15 +02:00
### Creating a web application client ID {#creating-a-web-application-client-id}
2018-11-22 04:07:15 +01:00
1. Go to the credentials section in the [Google Cloud Platform Console ](https://console.cloud.google.com/apis/credentials?_ga=2.77615956.-1991581217.1542834301 ).
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.
2018-11-22 11:20:28 +01:00
2018-11-22 04:07:15 +01:00
```
http://localhost:4242/api/auth/callback
```
7. Click **Create** .
8. Copy the **CLIENT ID** and **CLIENT SECRET** and save them for later use.
2021-06-04 11:17:15 +02:00
### Add dependencies {#add-dependencies}
2018-11-22 04:07:15 +01:00
2021-08-12 15:04:37 +02:00
Add two dependencies [`@passport-next/passport` ](https://www.npmjs.com/package/@passport-next/passport ) and [`@passport-next/passport-google-oauth2` ](https://www.npmjs.com/package/@passport-next/passport-google-oauth2 ) inside `index.ts` file
2018-11-22 11:20:28 +01:00
2018-11-22 04:07:15 +01:00
```js
const unleash = require('unleash-server');
2019-02-01 16:13:16 +01:00
const passport = require('@passport-next/passport');
2021-08-12 15:04:37 +02:00
const GoogleOAuth2Strategy =
require('@passport-next/passport-google-oauth2').Strategy;
2018-11-22 04:07:15 +01:00
```
2018-11-22 11:20:28 +01:00
2021-05-18 11:19:33 +02:00
Add `googleAdminAuth()` function and other options. Make sure to also accept the services argument to get access to the `userService` .
2018-11-22 11:20:28 +01:00
2018-11-22 04:07:15 +01:00
```js
2021-05-18 11:19:33 +02:00
function googleAdminAuth(app, config, services) {
const { baseUriPath } = config.server;
const { userService } = services;
}
2018-11-22 04:07:15 +01:00
let options = {
2021-05-18 11:19:33 +02:00
authentication: {
type: 'custom',
customAuthHandler: googleAdminAuth,
},
2018-11-22 04:07:15 +01:00
};
2021-08-12 15:04:37 +02:00
unleash.start(options).then((instance) => {
2019-02-01 16:13:16 +01:00
console.log(
`Unleash started on http://localhost:${instance.app.get('port')}` ,
);
2018-11-22 11:20:28 +01:00
});
2018-11-22 04:07:15 +01:00
```
2021-06-04 11:17:15 +02:00
### In `googleAdminAuth` function: Configure the Google strategy for use by Passport.js {#in-googleadminauth-function-configure-the-google-strategy-for-use-by-passportjs}
2021-05-18 11:19:33 +02:00
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.
```js
const GOOGLE_CLIENT_ID = '...';
const GOOGLE_CLIENT_SECRET = '...';
const GOOGLE_CALLBACK_URL = 'http://localhost:4242/api/auth/callback';
function googleAdminAuth(app, config, services) {
const { baseUriPath } = config.server;
const { userService } = services;
passport.use(
new GoogleOAuth2Strategy(
{
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: GOOGLE_CALLBACK_URL,
},
2021-08-12 15:04:37 +02:00
async function (accessToken, refreshToken, profile, cb) {
2021-05-18 11:19:33 +02:00
// Extract the minimal profile information we need from the profile object
// and connect with Unleash
const email = profile.emails[0].value;
const user = await userService.loginUserWithoutPassword(email, true);
cb(null, user);
},
),
);
}
```
2021-06-04 11:17:15 +02:00
### In `googleAdminAuth` function {#in-googleadminauth-function}
2018-11-22 04:07:15 +01:00
Configure `passport` package.
2018-11-22 11:20:28 +01:00
2018-11-22 04:07:15 +01:00
```js
2021-05-18 11:19:33 +02:00
function googleAdminAuth(app, config, services) {
// ...
2018-11-22 04:07:15 +01:00
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((user, done) => done(null, user));
// ...
}
```
2021-10-26 23:04:44 +02:00
Implement a preRouter hook for `/auth/google/login` . It's necessary for login with Google.
2018-11-22 11:20:28 +01:00
2018-11-22 04:07:15 +01:00
```js
2021-05-18 11:19:33 +02:00
function googleAdminAuth(app, config, services) {
2018-11-22 04:07:15 +01:00
// ...
2018-11-22 11:20:28 +01:00
app.get(
2021-10-26 23:04:44 +02:00
'/auth/google/login',
2019-02-01 16:13:16 +01:00
passport.authenticate('google', { scope: ['email'] }),
2018-11-22 11:20:28 +01:00
);
2018-11-22 04:07:15 +01:00
// ...
}
```
Implement a preRouter hook for `/api/auth/callback` . It's a callback when the login is executed.
2018-11-22 11:20:28 +01:00
2018-11-22 04:07:15 +01:00
```js
2021-05-18 11:19:33 +02:00
function googleAdminAuth(app, config, services) {
2018-11-22 04:07:15 +01:00
// ...
2018-11-22 11:20:28 +01:00
app.get(
'/api/auth/callback',
2018-11-22 04:07:15 +01:00
passport.authenticate('google', {
failureRedirect: '/api/admin/error-login',
}),
(req, res) => {
// Successful authentication, redirect to your app.
res.redirect('/');
2018-11-22 11:20:28 +01:00
},
2018-11-22 04:07:15 +01:00
);
// ...
}
```
2022-06-09 13:01:15 +02:00
Implement a preRouter hook for `/api/` .
2018-11-22 11:20:28 +01:00
2018-11-22 04:07:15 +01:00
```js
2021-05-18 11:19:33 +02:00
function googleAdminAuth(app, config, services) {
2018-11-22 04:07:15 +01:00
// ...
2022-06-09 13:01:15 +02:00
app.use('/api/', (req, res, next) => {
2018-11-22 04:07:15 +01:00
if (req.user) {
next();
} else {
// Instruct unleash-frontend to pop-up auth dialog
return res
.status('401')
.json(
new unleash.AuthenticationRequired({
2021-10-26 23:04:44 +02:00
path: '/auth/google/login',
2018-11-22 04:07:15 +01:00
type: 'custom',
message: `You have to identify yourself in order to use Unleash. Click the button and follow the instructions.` ,
2018-11-22 11:20:28 +01:00
}),
)
.end();
2018-11-22 04:07:15 +01:00
}
});
// ...
}
```
2021-06-04 11:17:15 +02:00
### The complete code {#the-complete-code}
2018-11-22 11:20:28 +01:00
2021-05-18 11:19:33 +02:00
> You can also find the complete [source code for this guide](https://github.com/Unleash/unleash-examples/tree/main/v4/securing-google-auth) in the unleash-examples project.
2021-08-12 15:04:37 +02:00
The `index.ts` server file.
2018-11-22 11:20:28 +01:00
2018-11-22 04:07:15 +01:00
```js
'use strict';
const unleash = require('unleash-server');
2019-02-01 16:13:16 +01:00
const passport = require('@passport-next/passport');
const GoogleOAuth2Strategy = require('@passport-next/passport-google-oauth2');
2018-11-22 04:07:15 +01:00
const GOOGLE_CLIENT_ID = '...';
const GOOGLE_CLIENT_SECRET = '...';
const GOOGLE_CALLBACK_URL = 'http://localhost:4242/api/auth/callback';
2021-05-18 11:19:33 +02:00
function googleAdminAuth(app, config, services) {
const { baseUriPath } = config.server;
const { userService } = services;
passport.use(
new GoogleOAuth2Strategy(
{
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: GOOGLE_CALLBACK_URL,
},
async (accessToken, refreshToken, profile, cb) => {
const email = profile.emails[0].value;
const user = await userService.loginUserWithoutPassword(email, true);
cb(null, user);
},
),
);
2018-11-22 04:07:15 +01:00
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((user, done) => done(null, user));
2018-11-22 11:20:28 +01:00
app.get(
2021-10-26 23:04:44 +02:00
'/auth/google/login',
2019-02-01 16:13:16 +01:00
passport.authenticate('google', { scope: ['email'] }),
2018-11-22 11:20:28 +01:00
);
app.get(
'/api/auth/callback',
2018-11-22 04:07:15 +01:00
passport.authenticate('google', {
failureRedirect: '/api/admin/error-login',
}),
(req, res) => {
res.redirect('/');
2018-11-22 11:20:28 +01:00
},
2018-11-22 04:07:15 +01:00
);
2022-06-09 13:01:15 +02:00
app.use('/api/', (req, res, next) => {
2018-11-22 04:07:15 +01:00
if (req.user) {
next();
} else {
return res
.status('401')
.json(
new unleash.AuthenticationRequired({
2021-10-26 23:04:44 +02:00
path: '/auth/google/login',
2018-11-22 04:07:15 +01:00
type: 'custom',
message: `You have to identify yourself in order to use Unleash. Click the button and follow the instructions.` ,
2018-11-22 11:20:28 +01:00
}),
)
.end();
2018-11-22 04:07:15 +01:00
}
});
}
2019-02-01 16:13:16 +01:00
const options = {
2021-05-18 11:19:33 +02:00
authentication: {
type: 'custom',
customAuthHandler: googleAdminAuth,
},
2018-11-22 04:07:15 +01:00
};
2021-05-18 11:19:33 +02:00
unleash.start(options);
2018-11-22 04:07:15 +01:00
```