Skip to main content

Provider

What is a Provider?

Providers are an essential part of Gatekeeper. They abstract the complexities involved in managing authentication (such as handling tokens, callbacks, etc.) and offer a clean, easy-to-use way to authenticate users.

Providers accept three parameters:

Options

Allow you to pass additional data for a Provider to work, or to customize it to your needs. Each provider has its own options, so be sure to check out our Providers page and look for the providers you want to implement.

Example #1

import gatekeeper from 'gatekeeper-authentication';
import GoogleProvider from '@sharifvelasquesz/gatekeeper/providers/google';

export const GoogleAuth = new GoogleProvider({
clientId: '<GOOGLE CLIENT ID>',
clientSecret: '<GOOGLE CLIENT SECRET>',
// The OAuth2 callback/redirect url you registered
// (the URL in which this provider will be used)
callbackURL: 'https://www.example.com/auth/google'
}, handler, errorHandler);

Example #2

import gatekeeper from 'gatekeeper-authentication';
import GithubProvider from '@sharifvelasquesz/gatekeeper/providers/github';

export const GithubAuth = new GithubProvider({
clientId: '<GITHUB CLIENT ID>',
clientSecret: '<GITHUB CLIENT SECRET>',
// The OAuth2 callback/redirect url you registered
// (the URL in which this provider will be used)
callbackURL: 'https://www.example.com/auth/google',

scope: ['user', 'repo', 'project']
}, handler, errorHandler);

Handler

A provider processes a user's request to obtain data that is then passed to the handler, which is responsible for utilizing this data to generate and return a user object. This user object is then stored in the session (in req.session.user).

Example #1

import gatekeeper from 'gatekeeper-authentication';
import GoogleProvider from 'gatekeeper-authentication/providers/google';

export const GoogleAuth = new GoogleProvider(options, (refresh_token, access_token, profile) => {
/*
For example, you can use the Google user's id (that is inside
the `profile` variable provided by the Google Provider) to get
the user from your database
*/
const user = User.findOne({ externalServiceId: profile.id });
return user;
});

Example #2

import gatekeeper from 'gatekeeper-authentication';
import GithubProvider from 'gatekeeper-authentication/providers/github';

export const MyGithubProvider = new GithubProvider(options, (refresh_token, access_token, profile) => {
const user = User.findOne({ id: profile.id });
/*
The handler must ALWAYS return something that will be saved
as the user inside req.session.user
*/
return { id: user.id, createdByProvider: 'github', someProperty: 123 };
});

What happens if I cannot return a user?

Maybe the user that is trying to log in doesn't exist, or perhaps its credentials are invalid. Whatever the reason is, you may not always be able to retrieve a user. In these cases, you can throw an error that can later be handled by the error handler (we'll look at that in a moment). Most providers have predefined errors you can use, but you can also create your own.

Example #1 -- Predefined errors

import gatekeeper from 'gatekeeper-authentication';
import LocalProvider, { IncorrectCredentials } from 'gatekeeper-authentication/providers/local'

export const LocalAuth = new LocalProvider(options, (username, password) => {
const user = User.findOne({ username, password });
if (user.password !== password) {
throw new IncorrectCredentials();
}
return user;
}, errorHandler));

Or, as mentioned before, you can also define your own custom errors:

Example #2

import gatekeeper from 'gatekeeper';
import LocalProvider, { IncorrectCredentials } from 'gatekeeper-authentication/providers/local'

class BannedUser extends Error {
constructor(message = '') {
super(message);
}
}

export const Local = new LocalProvider(options, (username, password) => {
const user = User.findOne({ username, password });

if (user.username == 'Mr.Angry') {
throw new BannedUser();
}

return user;
}, errorHandler);

This way unexpected/incorrect behavior becomes clearer and predictable.

Error handler (optional)

The error handler allows you to manage and handle the errors that might be thrown during the execution of the handler (in case you don't specify one, Gatekeeper will pass the errors on to Express).

Example #1

import gatekeeper from 'gatekeeper';
import LocalProvider, { IncorrectCredentials } from 'gatekeeper-authentication/providers/local'

class BannedUser extends Error {
constructor(message = '') {
super(message);
}
}

export const LocalAuth = new LocalProvider(options, (username, password) => {
const user = User.findOne({ username, password });

if (user.username == 'Mr.Angry') {
throw new BannedUser();
}

return user;
}, (error, req, res, next) => {
if (error instanceof BannedUser)
res.redirect('/bannedusers');

if (error instanceof Error)
res.send('There was an error while trying to log in').status(500);
/*
Don't forget to call the `next` function in case this is an error we
cannot/don't want to handle, as it will pass the error on to Express.
Doing this is heavily recommended
*/
next(error);
});

And here is another example:

Example #2

import gatekeeper from 'gatekeeper';
import LocalProvider, { IncorrectCredentials } from 'gatekeeper-authentication/providers/local'

class BannedUser extends Error {
constructor(message = '') {
super(message);
}
}

export const localMyProvider = new LocalProvider(options, (username, password) => {
const user = User.findOne({ username, password });

if (user.username == 'Mr.Angry')
throw new BannedUser();

return user;
}, (error, req, res, next) => {
if (error instanceof IncorrectCredentials)
return res.json({ message: 'Your credentials are incorrect', success: false });

if (error instanceof BannedUser)
return res.redirect('/bannedusers');

next(error);
});

More Examples

After you learn how to use the providers you just created, we recommend you visit the Local Provider example or the Google Provider example, or you can visit the Providers page to see how to implement your favorite providers.

Now that we know what a provider is, we will start using them in the next section.