How to Use Node.js, Fastify and Auth0 to protect REST API

With authentication, calling the API has to follow these steps:

  1. Before the workflow client can access the API of the workflow engine, it has to have an access token. If Auth0 authenticates the workflow client, it generates and returns an access token.
  2. The workflow client calls the workflow engine API and passes the access token. The workflow client adds the access token to the HTTP authorization header.
  3. The workflow engine validates the presented access token. If correctly validated, it performs the requested API method. The workflow engine returns the result to the workflow client.

OAuth 2.0 supports several different ways to retrieve an access token. Each of these ways — or flows — have a specific use case. OAuth 2.0 calls the flow from the example, the Client Credentials Flow. The workflow client uses a Client ID and Client Secret to request the access token.

For the next requests, the workflow client doesn’t have to request an access token. It can reuse the existing access token. For access tokens, we’re going to use JSON Web Tokens (JWT). JWT is a standard method for creating JSON-based access tokens.

Implementing OAuth 2.0 Using Auth0 in the Workflow Engine

To be able to add authentication in the workflow engine, we need the following:

  • An Auth0 account — they have a free plan for up to 7,000 active users
  • A registered application with Auth0
  • The npm package fastify-auth0-verify, a Fastify plugin for verifying JSON Web Tokens that are issued by Auth0.

Create an Auth0 account

To use Auth0, you have to create an account and application so you can integrate authentication into the API. Here, you can sign up for a free account. If you’ve added the account, you add the application by clicking on "+ Create Application.”

First, you have to enter the name of your application. Then, select “Machine to Machine Applications” as the application type. The application type defines which flow you can use to retrieve an access token. By choosing machine to machine, we can use the Client Credentials Flow.

Retrieve the domain and client secret

You need the domain and Client Secret to configure the[fastify-auth0-verify](https://github.com/nearform/fastify-auth0-verify) plugin. You can find both the Domain and Client Secret on the Settings tab of the application. See below.

This is image title

Installing and configuring fastify-auth0-verify

Inside the workflow engine, I install fastify-auth0-verify using the standard npm command:

npm i fastify-auth0-verify

Then in server.js, add the following to register the plugin:

fastify.register(require('fastify-auth0-verify'), {
  domain: config.authprovider.domain,
  secret: config.authprovider.secret
});

fastify.addHook("onRequest", async (request, reply) => {
  try {
    await request.jwtVerify()
  } catch (err) {
    reply.send(err)
  }
});

Don’t put sensitive information in source control

The domain and secret are sensitive information that you shouldn’t put in source control. Instead, you should retrieve this information from the environment.

const constants = require('./constants');

// Container for all environments
const environments = {};

environments.production = {
  httpPort: process.env.HTTP_PORT,
  httpAddress: process.env.HOST,
  envName: 'production',
  log: {
    level: process.env.LOG_LEVEL,
  },
  database: {
    url: process.env.STORAGE_HOST,
    name: 'workflow-db',
    connectRetry: 5, // seconds
  },
  workflow: {
    pollingInterval: 10, // Seconds
  },
  authprovider: {
    domain: process.env.AUTH_DOMAIN,
    secret: process.env.AUTH_SECRET
  }
};

// Determine which environment was passed as a command-line argument
const currentEnvironment = typeof process.env.NODE_ENV === 'string' ? process.env.NODE_ENV.toLowerCase() : '';

// Check that the current environment is one of the environment defined above,
// if not default to prodution
const environmentToExport = typeof environments[currentEnvironment] === 'object' ? environments[currentEnvironment] : environments.production;

// export the module
module.exports = environmentToExport;

I prefer having a single configuration object that contains all settings instead of referencing process.env.* everywhere in my source-code.

Using a central configuration object makes managing settings more maintainable. The configuration object also gives an overview of all the configuration settings of the application.

Putting settings in your environment

Configuring a lot of settings in environment variables can become cumbersome. The library dotenv makes it easier by reading environment variables from an .env file. The library stores the variables from the file in process.env.

After installing the dotenv npm module, the command below reads the environment variables from the .env file and stores them in process.env. Make sure you execute this command as soon as possible in your Node.js application.

require('dotenv').config()

Testing the Authentication Using Postman

With the plugin fastify-auth0-verify registered and the domain and secret filled, we’re ready to test the authentication. Instead of using the workflow client, we’ll use Postman for testing.

Sending an unauthorized request

First, to verify the health endpoint is secured, I execute an HTTP GET request to the health endpoint ([http://localhost:8181/api/health](http://localhost:8181/api/health)). After clicking Send, the workflow engine responds with an HTTP response: 401 Unauthorized. The 401 indicates the API can’t be accessed. So our authentication is working.

This is image title

Sending an authorized request

To perform an authorized request, we first have to request an access token from Auth0.

We request an Access Token by sending an HTTP POST to the token endpoint of the Auth0 subdomain. The body of your request should contain a JSON object with the client_id, client_secret, audience, and grant_type. You can find this information on the Settings tab of the application page. With "grant_type": "client credentials”, we state to Auth0 that we want to use the Client Credentials Flow.

This is image title

If you have entered all the information, Auth0 returns a JSON object as a response that includes the access token. This is the access token we need to be able to call the API of the workflow engine. Copy the value of the access_token without the double quotes.

Now, we go back to the original request in Postman. Go to the Health endpoint of the workflow engine, and use the Access Token. You need to click on the Authorization tab in Postman and select Bearer Token for the TYPE. Paste the access token you got from the previous request in the Token field.

This is image title

When you click Send, you’ll see you can call the Health endpoint. The Health API returns an HTTP status 200 OK. The body of the response contains the current date and time, indicating the API is working.

If you followed along, you’ll agree it’s easy to add authentication to your API when using an external authentication provider, such as Auth0.

I Don’t Want to Use an External Authentication Provider!

Not everyone can or wants to use an external authentication provider like Auth0. Instead, they want to use an on-premise authentication provider.

Luckily there are several other options, such as oidc-provider. oidc-provider is an OAuth 2.0-compatible authorization server for Node.js. For installation and configuration, I refer you to the documentation page. As we’re using open standards, it’s simple to replace Auth0 with this authorization server.

Conclusion

Thank you for reading. I hope this helps you to add authentication to your own Fastify REST API.

#node-js #fastify #auth0 #REST API

How to Use Node.js, Fastify and Auth0 to protect REST API
18.80 GEEK