@brainhubeu/hadron-oauth
v1.0.2
Published
Hadron module for authorisation from OAuth2 providers.
Downloads
4
Readme
Installation
npm install --save @brainhubeu/hadron-oauth
Overview
hadron-oauth
is a Hadron utility package to simplify working with OAuth providers, such as Google and Facebook. It provides several utility functions that you can use to make writing OAuth2 authentication quicker and more streamlined.
Tutorial
Understanding OAuth flow
The plan for our authentication flow is as follows:
- The client makes a
GET
request to/auth/{provider}
to begin the process of authentication. - The server redirects the client to a provider consent site.
- The client receives an auth code.
- The client makes a
POST
request to/auth/{provider}/token
to exchange the auth code for an access token.
We can then use the access token to make further request to the provider's API in order to fetch data about the user (such as their name or email).
Configuration
We will need to provide certain information to hadron-oauth
before we can proceed with the auth process. This information exists in Hadron's config file.
// oauth.js
module.exports = {
google: {
clientID: 'keyboard-cat',
clientSecret: 'shhh',
scope: ['https://www.googleapis.com/auth/userinfo.profile'],
redirectUri: 'http://localhost:8081/',
},
};
The clientID
and clientSecret
fields need to be the same as these given to you by your provider (such as the Google API Console). The redirectUri
must be exactly the same as the one given to your provider.
scope
is an array of strings defining the scopes your app requires from the user. See the Google scopes and Facebook scopes for details. These can be used later to retrieve relevant data from your provider's APIs about the user.
In this case, we'll also pretend that there is a front-end dev server at http://localhost:8081
, however we can just as well redirect the calls back to our own server.
It's recommended that you exclude this file from your version control or supply the specific config fields through environment variables as this file contains sensitive information.
Registration
Now that our config is created, we need to create our Hadron app entry point.
// index.js
const hadron = require('@brainhubeu/hadron-core').default;
const hadronExpress = require('@brainhubeu/hadron-express');
const hadronOauth = require('@brainhubeu/hadron-oauth');
const express = require('express');
const oauthConfig = require('./oauth.js');
const app = express();
const config = {
oauth: oauthConfig,
routes: {
root: {
path: '/',
methods: ['GET'],
callback: () => 'Hello!',
},
},
};
hadron(app, [hadronExpress, hadronOauth], config).then(() => {
app.listen(8080, () => {
console.log('Hadron/Express listening on 8080.');
});
});
We now have access to the OAuth methods through the container.
Auth code route
Let's create a separate file to store the logic for our route endpoints. We'll first create a route to redirect to the consent screen.
// routes.js
const routes = {
googleAuthRequest: {
path: '/auth/google',
methods: ['GET'],
callback: (req, { oauth }) => ({
redirect: oauth.google.redirect(),
}),
},
};
module.exports = routes;
// index.js
const oauthRoutes = require('./routes');
// ...
const config = {
routes: {
root: {
// ...
},
...oauthRoutes,
},
};
Now, whenever a client calls the /auth/google
endpoint, he or she will be redirected to the Google auth consent page.
Handling the auth code
Now, we'll delve into the client side here for a minute, because we need to send the auth code that the client receives back to the server.
In the oauth.js
config file we defined a redirect to our front-end dev server. We now need to send the authorization code from that server back to our app.
We can do it like this:
// client side javascript
const url = new URL(window.location);
const params = new URLSearchParams(url.search);
const code = params.get('code');
if (!code) return;
fetch('http://localhost:8080/auth/google/token', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ code }),
}).then((res) => {
// ...
});
Exchanging the code for an access token.
We'll define another route to exchange the auth code for an access token.
// routes.js
const routes = {
googleAuthRequest: {
// ...
},
googleTokenRequest: {
path: '/auth/google/token',
methods: ['POST'],
callback: (req, { oauth }) => {
oauth.google.token(req.body.code).then((res) => {
console.log(res.access_token);
// do things with the token...
});
},
},
};
module.exports = routes;
Now that we have the access token we can implement other features, such as our own authentication. We can also call the Google API in the name of the user to pull any relevant information we need.
Reference
Config
google.
clientID: string
- your app id as provided by the Google API Console.clientSecret: string
- your app secret from the Google API Consolescope: string[]
- an array of strings listing the scope URLs you need for your app.redirectUri: string
- redirect URI for your app, must be exactly the same as the one you chose in Google API Console.authUrl: ?string
- an optional parameter to provide a different auth URL to Google (for instance if the current one was to stop working). Defaults tohttps://accounts.google.com/o/oauth2/v2/auth
.tokenUrl: ?string
- an optional parameter to provide a different token exchange Google API endpoint. Defaults tohttps://www.googleapis.com/oauth2/v4/token
.responseType: ?string
- if Google was to support a different kind of OAuth authentication flow, we could specify the response type here. Currently, it only supportscode
and so it defaults to that.grantType: ?string
- similarly to the point above, if Google was to support a different kind of OAuth authentication flow, we could specify the grant type here. Defaults toauthorization_code
.
facebook.
clientID: string
- your app id as provided by the App Dashboard.clientSecret: string
- your app secret from the App Dashboard.scope: string[]
- an array of strings listing Facebook API scopes.redirectUri: string
- the redirect URI for your app, must be the same as in the App Dashboard.authUrl: ?string
- see above, defaults tohttps://www.facebook.com/v3.0/dialog/oauth
.tokenUrl: ?string
- see above, defaults tohttps://graph.facebook.com/v3.0/oauth/access_token
responseType
- see above, defaults tocode
.
github.
clientID: string
- your app id as provided in the Github Developer Settings.clientSecert: string
- your app secret from the Developer Settings.scope: string[]
- an array of strings listing Github API scopes.redirectUri: string
- the redirect URI for your app, must be the same as in the Developer Settings.authUrl: ?string
- see above, defaults tohttps://github.com/login/oauth/authorize
.tokenUrl: ?string
- see above, defaults tohttps://github.com/login/oauth/access_token
allowSignup: ?boolean
- determines whether the user will be able to sign up to Github while authorizing the app, defaults totrue
.
Methods
oauth.google.
redirect() => string
- parses the config options and returns a redirect URL to the user consent screen.token(code: string) => Promise
- exchanges the auth code in the first argument for an access token. Returns a promise which resolves to the response from Google.
oauth.facebook.
redirect(state: ?string) => string
- parses the config and returns a redirect URL to the user consent screen. You can provide a state string to secure your app against CSRF (see here for details).token(code: string) => Promise
- exchanges the auth code in the first argument for an access token. Returns a promise which resolves to the repsonse from Facebook.
oauth.github.
redirect(state: ?string) => string
- parses the config and returns a redirect URL to the user consent screen. You can provide a state string to secure your app against CSRF.token(code: string, state: ?string) => Promise
- exchanges the auth code in the first argument for an access token. Returns a promise which resolves to the repsonse from Facebook.