Building a JWT Login Flow with Auth0, Next.js, and StepZen
Tags: webdev, nextjs, graphql
Published: 2023-02-15 13:34:42

Almost every frontend application needs some form of authentication. This post will build a JWT login flow with Auth0, Next.js, and StepZen. Auth0 Next.js authentication library `nextjs-auth0`, a library maintained by Auth0 to make integrating with Next.js flawless, will handle the authentication flow. Auth0 is a popular authentication provider that supports many different authentication methods, including social login, passwordless login, and more.

> TLDR; You can find the complete source code for this blog post on [GitHub](https://github.com/stepzen-dev/examples/tree/main/with-auth0/authorization-jwt).

What does the login flow look like?
-----------------------------------

For this login flow, we will rely on OAuth 2.0 and more specifically the [Authorization Code Grant flow](https://stepzen.com/blog/authenticating-graphql-apis-with-oauth2). This flow involves both a frontend and a backend. The frontend application will handle the login flow and redirect the user to the backend. The backend will exchange the authorization code for a JSON Web Token (JWT) and return it to the frontend application. The frontend application will then use the JWT to make requests to the backend.

![Authorization Code Grant flow with Auth0 and StepZen](https://stepzen.com/images/blog/validating-jwt-tokens/flow.png)

The frontend application will be a Next.js application that uses the `nextjs-auth0` library to handle the login flow. In this application, users click a button that brings them to the Auth0 Universal Login page. From this page, they can log in using a combination of email address and password, or one of the many social providers that are available in Auth0. After logging in, the user is asked to grant access to their profile information to the authorization server. The backend StepZen GraphQL API references an [Auth0 JSON Web Key Set](https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-key-sets) to verify the JWT before returning sensitive data to the frontend application.

Setting up Auth0
----------------

​In this section, we will configure our Auth0 account to integrate it into our application later. This involves creating an Auth0 account, creating an API in the Auth0 dashboard, and an application that will be used to generate access tokens for our StepZen GraphQL API.

First, you need to have an Auth0 account. If you don't have one yet, you can create one for free by following the instructions on the [Auth0 website](https://auth0.com/).

Second, we need to create an API in Auth0. This API will represent our StepZen GraphQL API and give it access to the Auth0 authorization server. To do this, we need to go to the Auth0 dashboard and:

*   Click the **Applications** link in the left navigation pane.
*   Click the **APIs\`** link in the left navigation pane.
*   Click the **\+ Create API** button.
*   On this page you need to fill out the following fields:​
    *   Enter a name in the _Name_ field to help you identify this client. For example: "My StepZen API".
    *   For the _Identifier_ field, enter a unique value. For example: "https://my-stepzen-api.com".
*   And click the **Create** button.

![Create an API in Auth0](https://stepzen.com/images/blog/jwt-auth0-login-setup-api.png)

You should now see a page that contains the Identifier and Audience fields. The `Identifier` is the URL that will be used to identify your API; this is the value that will be used to identify your API when requesting an access token. We will need these values later on, so copy them somewhere.

> Not setting up an API in this stage will lead to Auth0 creating an _opaque_ access token. This token will not be able to be validated by StepZen, but only by Auth0. This is not what we want, so make sure to create an API.

Finally, we need to create an application in Auth0. This application is the authorization server that will be used to generate access tokens for our StepZen GraphQL API.

*   Go Back to the **Applications** page.
*   Click the **\+ Create Application** button.
*   Fill out the following fields:​
    *   Enter a name in the _Name_ field to help you identify this client. For example: "My StepZen App".
    *   For application type, select _Single Page Web Applications_ (or _Regular Web Applications_).
*   Click the **Create** button.

Go the **Settings** tab to find the configuration needed to integrate with StepZen:

*   _Domain​_
*   _Client ID​_
*   _Client Secret​_

![Create an Application in Auth0](https://stepzen.com/images/blog/jwt-auth0-login-setup-application.png)

Copy the values for the _Domain_, _Client ID_, and _Client Secret_ fields. We will need these values in our frontend application later on.

We also need to configure the application to allow it to redirect to our frontend application. Scroll down to the **Allowed Callback URLs** field and add the following URL: "http://localhost:3000/api/auth/callback"

![Create the allowed callbacks in Auth0](https://stepzen.com/images/blog/jwt-auth0-login-setup-application-callback.png)

Great! We have now configured our Auth0 account and can move on to the next step.

Creating a Next.js application
------------------------------

In this section, we will create a Nextjs frontend application to handle the login flow with `nextjs-auth0`. This application will use the `nextjs-auth0` library to handle the login flow. This library will take the redirect to the Auth0 Universal Login page and handle the callback from the Auth0 authorization server. It will also handle storing the JWT in the browser and, optionally, refreshing the JWT when it expires.

You can create a new Nextjs application by running the following command:​

```bash
`npx create-next-app`

```

The Next.js setup will prompt you with a few questions, such as the name you want to give to the application, if you want to use TypeScript, and if you want to use experimental features. We will use the default settings for this post, so you can press enter to accept the default values.

Once you've finished the setup of the Next.js application, let's install the following dependency that is needed for authentication:

```bash
npm install @auth0/nextjs-auth0

# or if you're using yarn
yarn add @auth0/nextjs-auth0
```

And add your Auth0 API and Application configuration to the `.env` file:

```bash
AUTH0_SECRET='LONG_RANDOM_VALUE' # A long, secret value used to encrypt the session cookie
AUTH0_BASE_URL='http://localhost:3000'
AUTH0_ISSUER_BASE_URL='https://YOUR_AUTH0_DOMAIN.auth0.com'
AUTH0_CLIENT_ID='YOUR_AUTH0_CLIENT_ID'
AUTH0_CLIENT_SECRET='YOUR_AUTH0_CLIENT_ID'
AUTH0_AUDIENCE='YOUR_AUTH0_API_IDENTIFIER'
```

> You can execute the following command to generate a suitable string for the `AUTH0_SECRET` value: `node -e "console.log(crypto.randomBytes(32).toString('hex'))"`

With the configuration in place, we can now add the code to the Next.js application to use the `nextjs-auth0` library to handle the login flow.

*   Create a new file called `pages/api/auth/[...auth0].ts` (or create the file as `.js` if you prefer not to use TypeScript). The `nextjs-auth0` library will use this file to handle the login flow and as the callback URL for the Auth0 authorization server.
    
*   Add the following code to the new `pages/api/auth/[...auth0].ts` file:
    

```ts
import { handleAuth, handleLogin } from '@auth0/nextjs-auth0';

export default handleAuth({
  login: handleLogin({
    authorizationParams: {
      audience: process.env.AUTH0_AUDIENCE, // or AUTH0_IDENTIFIER
      // Add the `offline_access` scope to also get a Refresh Token
      scope: 'openid profile email', // or AUTH0_SCOPE
    },
  }),
});
```

*   We also need to wrap the application with the `UserProvider` component. This component will be used to store the user information in the React context. This will allow us to access the user information in any component in the application. For example, by using any of the Hooks provided by `nextjs-auth0`. To do this, we need to add the following code to the `pages/_app.tsx` file:

```ts
// pages/_app.tsx
import '@/styles/globals.css';
import type { AppProps } from 'next/app';
import { UserProvider } from '@auth0/nextjs-auth0/client';

export default function App({ Component, pageProps }: AppProps) {
  return (
    <UserProvider>
      <Component {...pageProps} />
    </UserProvider>
  );
}
```

*   The last step is to add a login button to the application. To do this, we need to add the replace the contents in the `pages/index.tsx` file with the following code:

```tsx
// pages/index.tsx
import Head from 'next/head';
import Link from 'next/link';
import styles from '@/styles/Home.module.css';

export default function Home() {
  return (
    <>
      <Head>
        <title>My StepZen App</title>
        <meta name='description' content='Generated by create next app' />
        <meta name='viewport' content='width=device-width, initial-scale=1' />
        <link rel='icon' href='/favicon.ico' />
      </Head>

      <main className={styles.main}>
        <Link href='/api/auth/login' className={styles.loginButton}>
          <span className={styles.auth0Logo} />Login with Auth0
        </Link>
      </main>
    </>
  );
}
```

*   And finally, we need to add some styles to the application. Open the file called `styles/Home.module.css` and add the following code to the bottom of it:

```css
.loginButton {
  display: flex;
  align-items: center;
  background: #eb5424;
  padding: 10px 20px;
  border-radius: 10px;
  font-size: larger;
  color: white;
}

.auth0Logo {
  width: 32px;
  height: 32px;
  margin-right: 10px;
  background: url('/auth0_icon.svg');
}
```

*   Now run the application by executing the following command:

```bash
npm run dev

# or if you're using yarn
yarn dev
```

*   Open the application in your browser by navigating to `http://localhost:3000`. You should see a login button:

![Login button for Auth0 in a Next.js app](https://stepzen.com/images/blog/jwt-login-flow-auth0-login-button.png)

*   Once you press the login button, you should be redirected to the Auth0 Universal Login page. Sign up here for a new account that will be added to the linked Auth0 account.

![Auth0 Universal Login page](https://stepzen.com/images/blog/jwt-login-flow-auth0-login-screen.png)

*   After clicking the **Continue** button, you should be redirected back to the application. If you open the browser's developer tools and look at the cookies, you should see a new cookie added that includes your JWT. This cookie is used to authenticate you in the application.

We now have the first part of the login flow that uses Auth0 to get a JWT. Next, we want to use this JWT to authenticate the user in the StepZen GraphQL API, so we can fetch the user's profile information from the Auth0 API.

Creating a StepZen GraphQL API
------------------------------

With StepZen, you can create a GraphQL API for every data source, including REST APIs, databases, and more. In this section, we will create a GraphQL API that uses the Auth0 JWT to authenticate the user. The GraphQL API will fetch the user's profile information from the Auth0 API.

First, we need to create a new StepZen project. To do this, create a new directory called `stepzen` in the root of your project and run the following command in your terminal:

```bash
`stepzen init api/jwt-login-flow`

```

This will create a new StepZen configuration file and set the endpoint name to `api/jwt-login-flow`. You can also choose to use a different name if you prefer.

To set up the StepZen GraphQL API, we need to complete the following steps:

*   Create a new schema file called `api.graphql`. This file will contain the GraphQL schema for the API, including a query to get user information from the Auth0 API. Replace the value for `YOUR_AUTH0_DOMAIN` with the domain of your Auth0 account:

```graphql
type User {
  email: String
  email_verified: Boolean
  name: String
  nickname: String
  picture: String
  sub: String
  updated_at: DateTime
}

type Query {
  me: User
    @rest(
      endpoint: "https://YOUR_AUTH0_DOMAIN/userinfo"
      forwardheaders: ["Authorization"]
    )
}
```

*   StepZen needs to have an `index.graphql` that references the `api.graphql` file. Create a new file called `index.graphql` and add the following code to it:

```graphql
schema @sdl(files: ["api.graphql"]) {
  query: Query
}
```

*   To verify the Auth0 JWT, we need to create a new file called `config.yaml`. In this file, we'll add the configuration to valide the JWT using the JSON Web Key Set (JWKS) endpoint from Auth0 and the configuration to protect the GraphQL query `me` so authenticated users can only access it. Replace the value for `YOUR_AUTH0_DOMAIN` with the domain of your Auth0 account:

```yaml
# Add the JWKS endpoint
deployment:
  identity:
    jwksendpoint: 'https://YOUR_AUTH0_DOMAIN/.well-known/jwks.json'

# Set the policies
access:
  policies:
    - type: Query
      policyDefault:
        condition: true
      rules:
        - condition: '?$jwt' # Require JWT
          fields: [me] # Define fields that require JWT
```

*   Now run the following command to deploy and run your StepZen project:

```bash
`stepzen start`

```

*   In your terminal, you should see a message that includes the URL of your GraphQL API. Copy the URL (which starts with `https://YOUR_USERNAME.stepzen.net/api/******` and paste it into the `.env` file:

```bash
# Your StepZen endpoint
STEPZEN_ENDPOINT='YOUR_STEPZEN_ENDPOINT'
```

That's it! We now have a working GraphQL API that can be used to validate the Auth0 JWT and fetch user information from the Auth0 API.

In the next section, we'll use this GraphQL API to fetch the user's profile information in the Next.js application.

Fetching user information in the Next.js application
----------------------------------------------------

In this section, we will use the GraphQL API that we created in the previous section to fetch the user's profile information in the Next.js application. We'll take the token from Auth0 using the library `nextjs-auth0` to authenticate the user in the GraphQL API.

To do this, we need to complete the following steps:

*   Create a new file called `pages/api/graphql/index.ts`. This file will be the API route to send requests to the StepZen GraphQL API. It uses the `withApiAuthRequired` function from the `nextjs-auth0` library, so the JWT will be available in the request, which we can extract using the `getAccessToken` function. We're using an API route here as exectuting the data fetching server side is the recommended way to fetch data in Next.js. This JWT will then be forwarded to the GraphQL API together with the GraphQL query. You can add the following code to this file:

```ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { withApiAuthRequired, getAccessToken } from '@auth0/nextjs-auth0';

export default withApiAuthRequired(async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  const { accessToken } = await getAccessToken(req, res);

  const headers = {
    Authorization: `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  };

  const body = req.body;

  try {
    const response = await fetch(process.env?.STEPZEN_ENDPOINT || '', {
      method: 'POST',
      headers,
      body,
    });

    const json = await response.json();

    res.status(200).json(json);
  } catch (e: unknown) {
    const message = (e as Error).message;

    res.status(500).json({ error: message });
  }
});
```

> You can also generate a code snippet to connect to a StepZen GraphQL API from the [StepZen dashboard](https://dashboard.stepzen.com/). You can find this under the **Explorer** tab in the left pane of the dashboard by clicking on the **Connect** button in the top navigation.

*   In the `pages/index.tsx` file, we're using the new API route to fetch the user's profile information. When sending a request to this API route, we need to pass along the GraphQL query to get the user's name and picture. You can add the following code to this file:

```tsx
export default function Home() {
  const [userData, setUserData] = useState<null | {
    name: string;
    picture: string;
  }>(null);

  useEffect(() => {
    async function fetchData() {
      const res = await fetch('/api/graphql', {
        method: 'POST',
        body: JSON.stringify({
          query: `
            query {
              me {
                name
                picture
              }
            }
          `,
        }),
      });
      const json = await res.json();

      if (json?.data?.me) setUserData(json.data.me);
    }

    fetchData();
  }, [setUserData]);

  return (
    // ...
  );
}
```

*   After retrieving the user's profile information, we can display it in the UI. You can add the following code to the `pages/index.tsx` file:

```tsx
return (
  <main className={styles.main}>
    <div className={styles.center}>
      {userData ? (
        <div className={styles.profile}>
          <img
            src={userData.picture}
            alt={`${userData.name}'s profile picture`}
            width={200}
            height={200}
          />
          <p>
            <strong>Welcome {userData?.name}!</strong>{' '}
            <a href='/api/auth/logout'>Logout</a>
          </p>
        </div>
      ) : (
        <Link href='/api/auth/login' className={styles.loginButton}>
          <span className={styles.auth0Logo} />
          Login with Auth0
        </Link>
      )}
    </div>
  </main>
)
```

> Next.js recommends using the `Image` component from `next/image` to render images. However, when rendering remote sources, you need to allow access to the remote URLs of these sources. Therefore, we're using the `img` tag instead.

*   Finally, we need to add the styling for the profile information. You can add the following code to the `Home.module.css` file:

```css
.profile {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  margin-top: 20px;
}

.profile img {
  border-radius: 50%;
  margin-bottom: 20px;
}

.profile a {
  color: #eb5424;
  text-decoration: underline;
}
```

*   Now, if you open the application in the browser again and click on the **Login with Auth0** button, you should be redirected to the Auth0 login page. After logging in, you should see the user's profile information in the UI.

![Application after logging in](https://stepzen.com/images/blog/jwt-login-flow-auth0-login-profile-page.png)

*   As a finishing touch, we can show a loading indicator while the application checks if the user is authenticated and fetches the user's profile information. Therefore the `useUser` hook should be imported from `@auth0/nextjs-auth0/client` and the `isLoading` property should be used to check if the user is authenticated. You can add the following code to the `pages/index.tsx` file:

```tsx
import { useEffect, useState } from 'react';
import Head from 'next/head';
import Link from 'next/link';
import { useUser } from '@auth0/nextjs-auth0/client';
import styles from '@/styles/Home.module.css';

export default function Home() {
  const { isLoading } = useUser();

  // ...

  return (
    <main className={styles.main}>
      {isLoading ? (
        <div className={styles.center}>Loading...</div>
      ) : (
        <div className={styles.center}>
        {
          // ...
        } 
        </div>
      )}
      </main>
  );
}
```

Great! With this, we've implemented the login flow using Auth0 and StepZen. You can find the complete source code for this blog post on [GitHub](https://github.com/stepzen-dev/examples/tree/main/with-auth0/authorization-jwt).

Next Steps?
-----------

The flow we've implemented in this blog post is a typical pattern for frontend applications that want to provide a secure way to authenticate users. The application uses the `@auth0/nextjs-auth0` package to handle the authentication flow and a StepZen GraphQL API to verify the JWT on the server side. This way, the application can use the user's profile information on both the client side and in requests to the GraphQL API.

Follow us on [Twitter](https://twitter.com/stepzen_dev) or [join our Discord community](https://discord.gg/9k2VdPn2FR) to stay updated about our latest developments.

***

This post was originally published on [stepzen.com](https://stepzen.com/blog/building-jwt-login-flow-auth0-nextjs-stepzen). Reposted automatically with [Reposted.io](https://reposted.io?utm_source=postFooter).