Add Authentication and Authorization to Next.js 8 Serverless Apps using JWT and GraphQL


Tech Stack

Let's get the backend up and running before configuring the Next.js 8 app.

Deploy Hasura

Hasura is an open-source engine that gives you realtime GraphQL APIs on new or existing Postgres databases, with built-in support for stitching custom GraphQL APIs and triggering webhooks on database changes.

Follow the instructions in the docs to deploy Hasura. Note the Heroku URL for GraphQL Endpoint. You will be configuring this in the app later.

Apply the migrations by following the instructions in this section to create the necessary database schema and permissions.

Now the backend is ready! You will be able to instantly query using Hasura GraphQL APIs. The endpoint will look like (https://myapp.herokuapp.com/v1alpha1/graphql). We will come back to this during the integration with the Next.js app.

Run JWT Server

We will now run the JWT server locally to handle signup and login requests from the Next.js app.

Now, get the database URL from Heroku by heading to the settings page of the app.

Replace DATABASE_URL with the value obtained from Heroku config.

Configure JWT with Hasura

Now that the JWT server is ready, we need to configure Hasura to use the JWT Secret. The env HASURA_GRAPHQL_JWT_SECRET should be set like this:

Where <AUTH_PUBLIC_KEY> is your RSA public key in PEM format, with the line breaks escaped with "\n". This was generated just above.

In order to configure the JWT Secret we also need to set the admin secret. Head over to docs to set this up on Heroku.

Run the Next.js App

Both the JWT server and Hasura GraphQL Engine has been setup and configured.

Now let's run the Next.js app by running the following commands:

Configure the Heroku app url in lib/init-apollo.js. Now install the dependenices, build the serverless bundle and run the app using the following commands.

Once you run the app, you should be getting a screen like the one below:

Authenticated Query

Apollo Client has been configured with an Auth Middleware which sets the Authorization header (if available).

We call a utility function called getToken() which gets the auth token stored in the cookie and returns the token.

The actual implementation of signup and login sets the cookie with the token.

In the file utils/auth.js, we handle the logic of what needs to be done once the server returns the token after successful signup/login.

Authorization using JWT

Now that the user is logged in, we would like to fetch only the articles written by the same user. The permissions have been configured in such a way that only the user who wrote the article will be able to fetch the data. 

Head to the Heroku app URL to open Hasura console and navigate to                  Data->article->Permissions to see the permissions defined for the user role.

The permission check looks like:

This means that when a request is being sent with Authorization: Bearer <token>from the client, it will look for the X-Hasura-User-Id value from the token payload and filter it for the user_id column, ensuring that only logged in users get the data and also get only their data. The user has permissions to access all columns.

Protected Routes using HOC

Though we have handled authorized queries, we would like to restrict access to pages like /articles at the route level because it is available only for logged in users. We again make use of an HOC to handle this.

When a navigation is triggered on a protected route, we call a utility helper method auth which will fetch the token from the cookie using the nextCookie module. In case the token is not available, then it will redirect to /login page.

We wrap the protected components like articles using the withAuthSync HOC which will take care of the redirects on the server. 

After logging in, when you visit the articles page, you should be seeing the articles written by you.

Don't be surprised to see data being empty. You would need to insert articles tagging your user id in the Hasura console.

Deploy on Now

We can deploy this Next.js app on now.sh with the serverless target.

Deploy it to the cloud with now (download):

Do note that, the JWT server has to be deployed as well. The JWT server url has to be configured inside the Next.js app.

I have put together a boilerplate so that you can get started quickly!

Check it out on github.




0 comments