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.
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:
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
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 redirect URIs
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.
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:
The JWT secret is also stored in
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.
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.
Using authentication hooks
With a completed
/authentication service and using the
authenticate hook provided with
@feathersjs/authentication, existing services can now be secured.
/items service utilizing the
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:
/auth/google starts the OAuth process to verify a user and create a corresponding JWT:
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:
Using this JWT, a request can now be made to the
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.
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.
The full working example used for this article can be found here.
This example was built on Node v9.x with the following dependencies:
If you want to check out what I’m working on or have web development needs, visit Aquil.io.
Originally published at aquil.io.