FeathersJS and Google OAuth 2.0

Alexis Abril
DailyJS
Published in
5 min readMay 10, 2018

Implementing authentication may seem daunting with the number of libraries and modules available today. By understanding the purpose of each module, an OAuth 2.0 flow can be created with minimal configuration. The following is an implementation of the OAuth 2.0 authentication flow using Google and FeathersJS. The example being constructed will:

  • Expose an endpoint to begin OAuth flow;
  • Allow a user to confirm which Google account will be used;
  • Create a user based on requested Google account data;
  • Create a JWT for use in future requests.

Although a boilerplate project can be created using the FeathersJS CLI, all files in this article are created manually to illustrate each step.

Project setup

The directory hierarchy is arbitrary, however, there is a common theme in Feathers applications to assist in code organization. The directory structure for this example is as follows:

Directory structure

This article focuses on the /authentication service. To follow along, clone the full source and checkout the initial hash.

Modules

Feathers authentication is an abstraction of PassportJS. As such, Passport plugins are able to be used in Feathers applications. For this example, the below packages are needed and can be installed with npm or yarn.

> npm install @feathersjs/authentication @feathersjs/authentication-jwt \ @feathersjs/authentication-oauth2 passport-google-oauth2
yarn add @feathersjs/authentication @feathersjs/authentication-jwt \ @feathersjs/authentication-oauth2 passport-google-oauth2

Adding authentication

Register a Google OAuth application

Following the guide provided by Google for setting up OAuth applications, there are four specific fields to verify:

  • Client ID
  • Client Secret
  • Authorized JavaScript Origins
  • Authorized redirect URIs
Google developer console

The client ID and secret are provided by Google after registering a new application. The origin and redirect are specified by the author of the new application. For this example, a custom port of 9001 is used along with the default authentication route of /auth/google/callback. The callback route is utilized by Google after a user has been authenticated.

A new section, authentication, is added to /config/default.json. The newly created client ID and secret are stored here for use later.

Note: “authentication”, “google”, “clientID”, and “clientSecret” are arbitrary keys.

/config/default.json

Create a secure JWT secret

Any string can be used to sign a JWT. The larger the secret is, in relation to the JWT body, the more secure. For more information regarding JWTs, see https://jwt.io. This application will use a random, hex string, generated from the crypto library in NodeJS. From a Node console:

node> crypto.randomBytes(256).toString('hex')

The JWT secret is also stored in /config/default.json:

Note: It is recommended to hold these values in environmental variables as to not expose secure keys to source control. The key “secret” is also an arbitrary name.

/config/default.json

With the above configuration, the authentication service can be created and configured. The default path provided by Feathers is /auth/<provider> for OAuth requests and /authentication to create JWTs.

/src/services/authentication/index.js

Using authentication hooks

With a completed /authentication service and using the authenticate hook provided with @feathersjs/authentication, existing services can now be secured.

A pre-existing /items service utilizing the authenticate hook:

/src/services/items/hooks.js

Seeing authentication in action

Using Postman and Chrome, the OAuth 2.0 flow can be demonstrated.

To verify the JWT hooks are working as expected, a request is made to /items. Since no JWT is present, this request fails:

Request without JWT

Visiting /auth/google starts the OAuth process to verify a user and create a corresponding JWT:

OAuth request

Switching these same requests into Chrome, a user is able to be logged in through Google, which successfully calls the /auth/google/callback route. This call returns a newly created JWT:

Successful OAuth verification

Using this JWT, a request can now be made to the /items and /users services:

Successful /items request

Making the same request to /users displays the user created based on the information returned by the Google OAuth system. If using multiple OAuth providers, such as Google and Facebook, it may also be required to normalize user data. This can be done with a custom hook as described in the Feathers documentation.

This token can be stored at the client application’s discretion, typically in LocalStorage or a cookie, and sent as a Bearer token in the Authorization header on future requests. If FeathersJS is used on the client, the flow requires minimal integration. This will be discussed in a future article within this series.

Photo by Sagar Rana on Unsplash

Conclusion

Feathers provides a minimal API for registering services. Creating robust authentication may feel like piecing together a puzzle, however, once familiarized with the purpose of the underlying modules can be a quick, community supported solution.

Follow the FeathersJS series with Aquil.io as the client implementation and other authentication flows will be described.

Example code

The full working example used for this article can be found here.

This example was built on Node v9.x with the following dependencies:

References

If you want to check out what I’m working on or have web development needs, visit Aquil.io.

Originally published at aquil.io.

--

--

Alexis Abril
DailyJS

Engineering Manager at Paceline, writing software and riding the open road.