Next.js JWT Authentication with NextAuth and Integration with Hasura
Tags: frontend, nextjs, authentication
Published: 2021-02-05 07:36:59

---
title: Next.js JWT Authentication with NextAuth and Integration with Hasura
published: true
date: 2021-02-04 12:12:42 UTC
tags: Frontend,Nextjs,Authentication
canonical_url: https://hasura.io/blog/next-js-jwt-authentication-with-next-auth-and-integration-with-hasura/
---

 ![Next.js JWT Authentication with NextAuth and Integration with Hasura](https://hasura.io/blog/content/images/2021/02/hasura_next_jwt_auth_integration.png)

If you are a Next.js developer and looking for an Authentication solution, look no further than [next-auth](https://next-auth.js.org), an open-source Authentication library for Next.js. It's built for serverless (can run anywhere too) and supports various services like Sign in with Google, Apple, Facebook, Github or a simple email/password combination among others. You can bring your own database for storing sessions in the db or simply use JWT as we are going to do in this tutorial.

Hasura supports Authentication in the form of JWT / webhooks. The recommendation is to typically use JWT over webhooks for most use cases. With JWT, you get latency free requests since the session information is stored on the client and not on the server. Read more on the [Best Practices for using JWT on frontend clients](https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/).

## Clone next-auth example

In this tutorial, we will look at implementing a custom JWT solution with next-auth, served by Next.js and integrate the same with Hasura and make authenticated GraphQL API calls.

Let's start with the official example app and configure it.

```
git clone https://github.com/nextauthjs/next-auth-example.git
cd next-auth-example
npm i

npm i next-auth pg
```

Copy environment variables:

```
cp .env.local.example .env.local
```

We will come back and modify the values here later. Let's look at the directory structure. Inside the `pages` directory under the `api` routes, you have the logic written for `auth` in the file `[...nextauth.js]`. This will let this component handle all the requests coming in to `/api/auth/*`. Some example include, signin, signout, callback etc.

## Deploy Hasura to get a GraphQL API

1. Click on the following button to deploy GraphQL engine on Hasura Cloud including Postgres add-on or using an existing Postgres database:

![Next.js JWT Authentication with NextAuth and Integration with Hasura](https://graphql-engine-cdn.hasura.io/img/deploy_to_hasura.png)

2. Open the Hasura console by clicking on the button "Launch console".

3. Create table users.

Head to the `Data` tab and create a new table called `users` with columns:

- id (text)
- name (text)
- created\_at (timestamp now()).

## JWT Configuration

Hasura supports authentication via webhook and JWT. For this next-auth example, we will look at creating a custom JWT server to sign and verify tokens.

### Generating Secret

We need to generate a secret that can be used to hash the tokens and configure them on Hasura. There are a couple of options available.

- HS256
- RS256 / RS512

If you are going to use `HS256` algorithm, there is only a secret to be generated that will be used on both the Next.js server and inside Hasura config. On the other hand, if you are going to use `RS256`, we need to generate a `public/private` key pair and the private key will be used to sign the token, and the public key will be used to verify the token on the Hasura's end.

#### JWT with HS256

Head to [https://generate-secret.now.sh/32](https://generate-secret.now.sh/32) to generate a random secret that can be used on both the Next.js server and Hasura config. I'm taking a value `69f8fd4d54342b7ee3b0fcdf6def434c` for the secret.

Let's configure this on the `.env.local` file that we copied earlier and substitute this value for the `SECRET` env.

On the Hasura Cloud projects page, head to the `ENV vars` page to configure this secret. Note that you need to add an admin secret using `HASURA_GRAPHQL_ADMIN_SECRET` before configuring the `HASURA_GRAPHQL_JWT_SECRET`.

The JWT config for this would look like:

```
{ "type": "HS256", "key": "69f8fd4d54342b7ee3b0fcdf6def434c"}
```

![Next.js JWT Authentication with NextAuth and Integration with Hasura](https://hasura.io/blog/content/images/2021/02/Hasura-Cloud-Console-Env-vars.png)<figcaption>Add Hasura_GRAPHQL_JWT_SECRET env var</figcaption>

Do replace the secret with your own generated code.

#### JWT with RS256

Follow the steps to generate a private/public key pair for using the RS256 algorithm.

- Generate Private Key

```
openssl genrsa -out private.pem 2048
```

- Generate Public Key

```
openssl rsa -in private.pem -pubout -out public.pem
```

- Transform public key into a single line

```
awk -v ORS='\\n' '1' public.pem | pbcopy
```

Now paste this value in your clipboard to Hasura Cloud env in the format

```
{ "type": "RS256", "key": "<insert-your-public-key-here>"}
```

- Transform private key into a single line

```
awk -v ORS='\\n' '1' private.pem | pbcopy
```

Configure this secret into your `.env.local` file under the `SECRET` env. This will be used by the next-auth config to sign the token.

## Sign In with GitHub

`next-auth` supports various data providers to integrate with Sign In services, OAuth providers and email/password combinations. We will use the `GitHub` provider in this example. Follow the [docs for enabling](https://next-auth.js.org/providers/github) that.

Head to the `[...nextauth.js]` file and remove the other providers. The configuration for providers will look like this:

```
providers: [
    Providers.GitHub({
      clientId: process.env.GITHUB_ID,
      clientSecret: process.env.GITHUB_SECRET,
    }),
],
```

## Encode JWT

Inside the `jwt` object, we need to enable the `secret` that would come from `process.env.SECRET` and expand on the logic for `encode` and `decode` methods.

We will need the `jsonwebtoken` module for signing the token with the secret.

So let's do that by `npm install jsonwebtoken`. Here's the [Hasura Docs on Custom Claims](https://hasura.io/docs/1.0/graphql/core/auth/authentication/jwt.html#the-spec). All the custom claims for Hasura stays in `https://hasura.io/jwt/claims`. The values we care are `x-hasura-role` and `x-hasura-user-id` because these session variables will be used in this example's permission system.

```
encode: async ({ secret, token, maxAge }) => {
      const jwtClaims = {
        "sub": token.id.toString() ,
        "name": token.name ,
        "email": token.email,
        "iat": Date.now() / 1000,
        "exp": Math.floor(Date.now() / 1000) + (24*60*60),
        "https://hasura.io/jwt/claims": {
          "x-hasura-allowed-roles": ["user"],
          "x-hasura-default-role": "user",
          "x-hasura-role": "user",
          "x-hasura-user-id": token.id,
        }
      };
      const encodedToken = jwt.sign(jwtClaims, secret, { algorithm: 'HS256'});
      return encodedToken;
},
```

## Decode JWT

```
decode: async ({ secret, token, maxAge }) => {
      const decodedToken = jwt.verify(token, secret, { algorithms: ['HS256']});
      return decodedToken;
 },
```

## Adding User ID to Token

##### From NextAuth Docs:

_If you want to pass data such as an Access Token or User ID to the browser when using JSON Web Tokens, you can persist the data in the token when the `jwt` callback is called, then pass the data through to the browser in the `session` callback._

We need to handle the callbacks from our Sign In service to be able to add user ID to the token. Inside the `callbacks` object, handle the logic for session:

```
async session(session, token) { 
      const encodedToken = jwt.sign(token, process.env.SECRET, { algorithm: 'HS256'});
      session.id = token.id;
      session.token = encodedToken;
      return Promise.resolve(session);
    },
```

and `jwt` callback

```
async jwt(token, user, account, profile, isNewUser) { 
      const isUserSignedIn = user ? true : false;
      // make a http call to our graphql api
      // store this in postgres
      
      if(isUserSignedIn) {
        token.id = user.id.toString();
      }
      return Promise.resolve(token);
    }
```

Note that we need to write the handler to make an http call to GraphQL API to insert the user and sync it with the `users` table in the database.

Head to `server.js` in the `pages` directory to see how the `session` prop is exported to use session information with Server Side Rendering.

```
export async function getServerSideProps(context) {
  return {
    props: {
      session: await getSession(context)
    }
  }
}
```

This set up enables you to access the session information in `_app.js` where we use the `NextAuth` `<Provider>` HOC to render the components.

After logging in, check the token generated on the network tab. There is an API call made to `/api/auth/session` that would return the token. This token can now be used to make authenticated GraphQL API calls with Hasura via the `Authorization` header.

Link to Github - [https://github.com/praveenweb/next-auth-hasura-example](https://github.com/praveenweb/next-auth-hasura-example)

Check out the YouTube video to follow along the whole integration from scratch.

<iframe width="200" height="113" src="https://www.youtube.com/embed/Vy0UldnCmrw?start=2285&amp;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

Do let me know in the comments if you want specific use cases to be covered!