Using SuperTokens for authentication in Next.js
Tags: nextjs, webdev
Published: 2023-03-28 17:15:37

**Written by [Wisdom Ekpotu](https://blog.logrocket.com/author/wisdomekpotu/)✏️**

In the fast-paced world of web development, security has become a major concern for developers and businesses alike. With the increasing number of data breaches and cyber attacks, it is essential for applications to have robust security systems in place. One critical aspect of this security system is the authentication process, which is the process of verifying a user’s identity. 

However, the process of implementing a secure authentication system can be very complex and time consuming, particularly when working with complex frameworks like [Next.js](https://nextjs.org/). This is where [SuperTokens](https://supertokens.com/) comes in. SuperTokens is a highly secure and customizable authentication solution that integrates seamlessly with Next.js. 

In this article, we will discuss how SuperTokens can be used to add authentication in Next.js applications. We’ll explore its key features and benefits. _Jump ahead:_

*   [What is SuperTokens?](#what-supertokens)
*   [What’s unique about SuperTokens?](#whats-unique-about-supertokens)
*   [Key features of SuperTokens](#key-features-supertokens)
*   [Supported technologies](#supported-technologies)
*   [Auth types (recipes) available in SuperTokens](#auth-types-recipes-available-supertokens)
*   [Getting started with SuperTokens in Next.js](#getting-started-supertokens-nextjs)

## Prerequisites

To follow along with this tutorial, you‘ll need the following:

*   Basic knowledge of JavaScript, [React](https://reactjs.org/), and [Next.js](https://nextjs.org/)
*   Node.js package manager: [npm](https://www.npmjs.com/get-npm), [Yarn](https://classic.yarnpkg.com/lang/en/docs/install), or [pnpm](https://pnpm.io/installation)
*   If you don’t have Node.js installed, install it by [downloading the official binary](https://nodejs.org/en/)
*   Basic understanding of how the [terminal](https://www.linode.com/docs/guides/using-the-terminal/) works
*   Any IDE. I recommend [Visual Studio Code](https://code.visualstudio.com/)
*   [Git](https://git-scm.com/downloads) installed

The final code is available on [GitHub](https://github.com/wisdomekpotu/supertokens-next-auth). Please give a ⭐ to the repo if you like the work.

## What is SuperTokens? <a name="what-supertokens">

Let's face it, authentication is hard and costly. A team wanting to ship a product will most likely spend a lot of time building the login and signup pages then implementing social logins, email verification, session management, user management, forgotten password functionality, and even 2FA. It’s a lot to do even before the product goes live. This is where SuperTokens shines. ![SuperTokens Cover Page](https://blog.logrocket.com/wp-content/uploads/2023/03/supertokens-cover-page.png) 

[SuperTokens](https://supertokens.com/) is an open source authentication and authorization framework designed to provide secure login and scalable access management for web and mobile applications. It allows developers to manage user sessions, handle tokens, store user data, and implement secure authentication flows: 

SuperTokens does this through various auth strategies called [r](https://supertokens.com/docs/guides)[ecipes](https://supertokens.com/docs/guides). SuperTokens is designed to streamline the authentication process, reduce security vulnerabilities, and provide a seamless user experience for both developers and end users.

## What’s unique about SuperTokens?

SuperTokens differs from existing user authentication solutions in the following ways: 

**Security**: SuperTokens is designed with security in mind, making it a secure and reliable authentication solution. It uses state-of-the-art encryption algorithms to protect user data and it is also immune to the most common security attacks, such as SQL injection and cross-site scripting (XSS). 

**Low vendor lock-in:** There is a very low vendor lock-in with SuperTokens compared to other available alternatives because users have complete control over how SuperTokens works and where their data is stored. 

**Open source:** SuperTokens is an open source solution, allowing developers to explore their code for bugs and offer suggestions for improvement. 

**Control and customizability:** SuperTokens has a fundamentally unique architecture that provides significant control to the developer (native frontend experience, customizable auth logic in the backend, SDKs using our overrides feature). 

**Pre-built UI components**: SuperTokens provides us with pre-built authentication user interfaces (e.g login form, etc) for easy integration. 

_N.B.,_ At the time of writing this tutorial, SuperTokens doesn't have first-class support for other frameworks like Vue.js and Angular. The SuperTokens's pre-built UI components are all built in React, so you will have to load them into your Vue/Angular apps or build your custom UI. 

To use SuperTokens with your own custom UI, refer to SuperTokens’ plain [JavaScript SDK](https://github.com/supertokens/supertokens-web-js).

## Key features of SuperTokens <a name="key-features-supertokens">

SuperTokens offers a rich set of features, including includes:

*   Session management
*   Role-based access control
*   Various types of auth(recipes): Email/password, passwordless, OAuth 2.0, etc.
*   User management

SuperTokens is made up of three components:

*   `Frontend SDK`: Renders the auth UI widgets and manages user session tokens automatically
*   `Backend SDK`: Adds auth APIs to your backend. For example: sign in, sign up
*   `SuperTokens Core Service`: This is an HTTP service that talks to your database. It also contains the core logic for auth. You can choose to self-host with your own database ([w](https://supertokens.com/docs/emailpassword/quick-setup/core/with-docker)[ith Docker](https://supertokens.com/docs/emailpassword/quick-setup/core/with-docker) or [without Docker](https://supertokens.com/docs/emailpassword/quick-setup/core/without-docker)) or host it with a SuperTokens-managed service by [signing up here](https://supertokens.com/)

The architecture employed here is quite unique and different from other auth providers as the backend API layer sits right in the middle of your frontend and SuperTokens. 

This means that the frontend will never talk to the SuperTokens core directly, but rather that any request made will be to the APIs exposed by the backend SDK, which will then talk to the SuperTokens core. 

This structure enables easy customizations of the auth logic and also enables a secure session solution: ![Self-Hosted Architecture Diagram ](https://blog.logrocket.com/wp-content/uploads/2023/03/self-hosted-architecture-diagram.png)

## Supported technologies <a name="supported-technologies">

For backend integration, SDKs are currently available for the following: [Golang](https://github.com/supertokens/supertokens-golang), [Python](https://github.com/supertokens/supertokens-python), and [Node](https://github.com/supertokens/supertokens-nodehttps://github.com/supertokens/supertokens-node)[.js](https://github.com/supertokens/supertokens-nodehttps://github.com/supertokens/supertokens-node). Meanwhile, for the frontend, it is available with [React.js](https://github.com/supertokens/supertokens-auth-react), [React Native](https://github.com/supertokens/supertokens-react-native), and [Vanilla JS (Vue/ Angular/ JS)](https://github.com/supertokens/supertokens-web-js). 

There are also other framework-specific integrations available including GraphQL, Hasura, etc.

## Auth types (recipes) available in SuperTokens <a name="auth-types-recipes-available-supertokens">

Currently, these are the available authentication recipes:

*   Passwordless login
*   Social login
*   Email password login
*   Email password and social login
*   Social login and passwordless
*   Phone password login
*   2FA/Multi-factor authentication
*   Micro service auth
*   Session management
*   User management dashboard
*   User role access control

Now, let's look at how SuperTokens compares to other auth providers: ![SuperTokens Vs. Other Auth Providers](https://blog.logrocket.com/wp-content/uploads/2023/03/supertokens-vs-other-auth-providers.png)

## Getting started with SuperTokens in Next.js <a name="getting-started-supertokens-nextjs">

First, choose an auth recipe. For the scope of this article, we will focus on implementing the [EmailPassword Login](https://supertokens.com/docs/emailpassword/nextjs/about) authentication recipe. 

First, get the starter project from GitHub. An important thing to note about the starter project is that it is a simple Next.js application and it uses [Next UI](https://nextui.org/) for styling. 

Now, let’s start authenticating! 

First, clone the `supertokens-next-auth` repository on its `starter` branch to get started:

```javascript
git clone --branch starter https://github.com/wisdomekpotu/supertokens-next-auth.git
```

Once you clone the repo, make `supertokens-next-auth` your current directory:

```javascript
cd supertokens-next-auth
```

Next, install all project dependencies:

```bash
# Using YARN
yarn install
# Using NPM
npm install 
# Using PNPM 
pnpm install
```

Then, run the development server:

```bash
# Using YARN
yarn run dev
# Using NPM
npm run dev
# Using PNPM 
pnpm run dev
```

The application should be running. Go to your browser and navigate to [http://localhost:3000](http://localhost:3000/) to see the app rendered successfully. You should end up with this: ![Rendered App](https://blog.logrocket.com/wp-content/uploads/2023/03/rendered-app.png) 

Now, we’ll install SuperTokens dependencies. In your terminal, run the following command:

```bash
# Using YARN
yarn add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors
# Using NPM 
npm install supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors
# Using PNPM
pnpm add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors
```

Set up a `.env.local` file in the root directory with the following:

```javascript
// .env.local
NEXT_PUBLIC_APP_DOMAIN= "http://localhost:3000"
```

Our next step is to create configuration files. In the root directory of your project, create a `config` folder. Now, in this folder, create three files: `appInfo.js` , `backendConfig.js`, and `frontendConfig.js`:

```javascript
// config/appInfo.js
export const websiteDomain = process.env.NEXT_PUBLIC_APP_DOMAIN

export const appInfo = {
  appName: 'SuperTokens Demo App',
  websiteDomain,
  apiDomain: websiteDomain,
  apiBasePath: "/api/auth",
  websiteBasePath: "/auth"
}
```

The `appInfo.js` file holds an important object called `appInfo` that carries the environment variables for both the frontend and backend. 

`appName:` The name of your application `apiDomain:` The URL of your website `websiteBasePath:` The path where our login UI will be rendered 
`apiBasePath:` The path through which SuperTokens API will be exposed 

Now, we’ll create a frontend config function. Still in the `config` folder, create a file called `frontendConfig.js` and populate it with the code below:

```javascript
// config/frontendConfig.js
import EmailPasswordReact from 'supertokens-auth-react/recipe/emailpassword'
import SessionReact from 'supertokens-auth-react/recipe/session'
import { appInfo } from './appInfo'
import Router from 'next/router'

export const frontendConfig = () => {
  return {
    appInfo,
    recipeList: [
      EmailPasswordReact.init(),
      SessionReact.init(),
    ],
 // this is so that the SDK uses the next router for navigation
    windowHandler: (oI) => {
      return {
        ...oI,
        location: {
          ...oI.location,
          setHref: (href) => {
            Router.push(href)
          },
        },
      }
    },
  }
}
```

In the code above, we export a function called `frontendConfig`, which returns the `appInfo` object created in the previous step and an array `recipeList` where we initialize the recipes we need, which are `EmailPassword` recipe and `Session` recipe. 

Then, we’ll create a `windowHandler` property where we override the default behavior of the SDK to use the `next/router` library for navigation. 

Next, we’ll create a backend config function. Create a file `backendConfig.js` in the `config` folder:

```javascript
// config/backendConfig.js
import EmailPasswordNode from 'supertokens-node/recipe/emailpassword'
import SessionNode from 'supertokens-node/recipe/session'
import { appInfo } from './appInfo'

export const backendConfig = () => {
  return {
    framework: "express",
    supertokens: {
      connectionURI: process.env.NEXT_PUBLIC_CONNECTION_URI, 
      apiKey: process.env.NEXT_PUBLIC_API_KEY,
    // For demo/test purposes all you need is to use https://try.supertokens.com as connectionURI and there is no need for an apiKey.
    },
    appInfo,
    recipeList: [
      EmailPasswordNode.init(),
      SessionNode.init(),
    ],
    isInServerlessEnv: true,
  }
}
```

The `backendConfig` function takes no arguments and returns an object containing configuration options. The options include:

*   `framework`: This specifies that the backend framework being used is Express
*   `supertokens: { ... }`: This object contains configuration options for the SuperTokens library. It includes the connection URI and API key used to connect to the SuperTokens service
*   `appInfo`: Information about the application
*   `recipeList`: A list of recipes to be used by the application. In this case, we initialize the `EmailPasswordNode` and `SessionNode` recipes
*   `isInServerlessEnv`: A Boolean value indicating whether the application is running in a serverless environment. In this case, it's set to `true`.

_N.B.,_ _You can use_ [_this site_](https://try.supertokens.com/)_ as the `connectionURI` for demo purposes. In production, you will need to replace this with the actual address of your SuperTokens core instance._ 

There are two ways to set up your core instance:

*   **Using SuperTokens Managed Service**. To use this option, head over to the SuperTokens [website](https://supertokens.com/), sign up for a free account, create an instance, and you should get your credentials.

The credentials should look like this: ![](https://paper-attachments.dropboxusercontent.com/s_BB89E5F2938622D0AAE0DF4EE17D2B39355253B7DFC62FEFA7FC786742D8724F_1677512681740_SuperTokens-Open-Source-Authentication+4.png)

*   **By self-hosting SuperTokens**. This method involves either [manually installing SuperTokens](https://supertokens.com/docs/passwordless/quick-setup/core/without-docker) or using [D](https://supertokens.com/docs/passwordless/quick-setup/core/with-docker)[ocker](https://supertokens.com/docs/passwordless/quick-setup/core/with-docker). This option is flexible as you can self host while using your own database([MySQL](https://supertokens.com/docs/passwordless/quick-setup/database-setup/mysql) or [PostgreSQL](https://supertokens.com/docs/passwordless/quick-setup/database-setup/postgresql)).

Now, when you get your credentials, head over to `.env.local` file and update as follows:

```javascript
// .env.local
NEXT_PUBLIC_APP_DOMAIN= "http://localhost:3000"
NEXT_PUBLIC_CONNECTION_URI= "<YOUR_CONNECTION_URI>",
NEXT_PUBLIC_API_KEY= "<YOUR_API_KEY>"
```

To call the frontend `init` functions, navigate to `/pages/_app.js` file and replace it with the code below:

```javascript
// pages/_app.js
import { NextUIProvider } from '@nextui-org/react';
import React from 'react';
import SuperTokensReact, { SuperTokensWrapper } from 'supertokens-auth-react';
import { frontendConfig } from '../config/frontendConfig';
if (typeof window !== 'undefined') {
  // we only want to call this init function on the frontend, so we check typeof window !== 'undefined'
  SuperTokensReact.init(frontendConfig());
}
function MyApp({ Component, pageProps }) {
  return (
    <SuperTokensWrapper>
      <NextUIProvider>
        <Component {...pageProps} />
      </NextUIProvider>
    </SuperTokensWrapper>
  );
}
export default MyApp;
```

Here, we call the `init` function for the frontend. Then, we proceed to wrap our entire application with the `<SuperTokensWrapper>` component. 

To show the login UI, create a folder called `auth` in the `pages` folder. Then, create a `[[...path]].js` page. 

The `[[...path]].js` file will contain the component for showing the SuperTokens UI:

```javascript
// pages/auth/[[...path]].js
import React, { useEffect } from 'react';
import dynamic from 'next/dynamic';
import SuperTokens from 'supertokens-auth-react';
import { redirectToAuth } from 'supertokens-auth-react';

const SuperTokensComponentNoSSR = dynamic(
  new Promise((res) => res(SuperTokens.getRoutingComponent)),
  { ssr: false }
);

export default function Auth() {
  // if the user visits a page that is not handled by us (like /auth/random), then we redirect them back to the auth page.
  useEffect(() => {
    if (SuperTokens.canHandleRoute() === false) {
      redirectToAuth();
    }
  }, []);
  return <SuperTokensComponentNoSSR />;
}
```

Now, visit `/auth` page on your website: ![](https://paper-attachments.dropboxusercontent.com/s_BB89E5F2938622D0AAE0DF4EE17D2B39355253B7DFC62FEFA7FC786742D8724F_1675504511615_Studio_Project.gif) 

To add backend Auth APIs and CORS setup, go to the `pages/api/` folder and create an `auth` folder. Now create a file `[[...path]].js` and add the following code:

```javascript
// pages/api/auth/[[...path]].js
import { superTokensNextWrapper } from 'supertokens-node/nextjs';
import supertokens from 'supertokens-node';
import { middleware } from 'supertokens-node/framework/express';
import { backendConfig } from '../../../config/backendConfig';
supertokens.init(backendConfig());
export default async function superTokens(req, res) {
  await superTokensNextWrapper(
    async (next) => {
      // This is needed for production deployments with Vercel
      res.setHeader(
        'Cache-Control',
        'no-cache, no-store, max-age=0, must-revalidate'
      );
      await middleware()(req, res, next);
    },
    req,
    res
  );
  if (!res.writableEnded) {
    res.status(404).send('Not found');
  }
}
```

In the code above, the `[[...path]].js` file will use the middleware exposed by the `supertokens-node` library to expose all the APIs like signin, signup, etc. 

The backend setup is done! Try signing up now. It should be successful and you should be redirected to the home page. 

You can also head over to your [dashboard](https://supertokens.com/dashboard-saas) to see your user count: ![](https://paper-attachments.dropboxusercontent.com/s_BB89E5F2938622D0AAE0DF4EE17D2B39355253B7DFC62FEFA7FC786742D8724F_1679059811057_Screenshot+2023-03-17+at+2.24.36+PM.png) _N.B., This is for a SuperTokens managed service._ 

### Protecting a website route

When a website is protected, only logged-in users can access it. A user who is not logged in and tries to access it will be taken to the login page. Let's imagine we wish to safeguard your website's home page (the `/` route). 

In this case, we can edit the `/pages/index.js` file to add an auth wrapper around our `Home` component like so: 

Import the `SessionAuth` module from `supertokens-auth-react`:

```javascript
import { SessionAuth } from 'supertokens-auth-react/recipe/session'
```
Then, wrap our `Home` component with `SessionAuth`:

```javascript
// pages/index.js
export default function Home() {
  return (
    // we protect ProtectedPage by wrapping it with SessionAuth
    <SessionAuth>
      // ...
    </SessionAuth>
  )
}
```

Test the page by navigating to `/`. You will be redirected to the login page. After that, sign in and visit `/` again. This time, there should be no redirection. 

Finally, to implement the logout functionality, modify the `pages/index.js` file with the code below:

```javascript
// pages/index.js
import { Card, Grid, Row, Text, Navbar, Button, Link } from '@nextui-org/react';
import { SessionAuth } from 'supertokens-auth-react/recipe/session';
import { signOut } from 'supertokens-auth-react/recipe/emailpassword';
import { useState } from 'react';
export default function Home() {
  const [isloggedIn, setIsLoggedIn] = useState(null);
  async function onLogout() {
    await signOut();
    setIsLoggedIn;
    window.location.href = '/';
  }
  const list = [
    {
      title: 'Orange',
      img: '/images/fruit-1.jpeg',
      price: '$5.50',
    },
    {
      title: 'Tangerine',
      img: '/images/fruit-2.jpeg',
      price: '$3.00',
    },
    {
      title: 'Cherry',
      img: '/images/fruit-3.jpeg',
      price: '$10.00',
    },
    {
      title: 'Lemon',
      img: '/images/fruit-4.jpeg',
      price: '$5.30',
    },
    {
      title: 'Avocado',
      img: '/images/fruit-5.jpeg',
      price: '$15.70',
    },
    {
      title: 'Lemon 2',
      img: '/images/fruit-6.jpeg',
      price: '$8.00',
    },
    {
      title: 'Banana',
      img: '/images/fruit-7.jpeg',
      price: '$7.50',
    },
    {
      title: 'Watermelon',
      img: '/images/fruit-8.jpeg',
      price: '$12.20',
    },
  ];
  return (
    <>
      <SessionAuth>
        <Navbar isBordered variant='floating'>
          <Navbar.Brand>
            <Text b color='inherit' hideIn='xs'>
              Test App
            </Text>
          </Navbar.Brand>
          <Navbar.Content hideIn='xs' variant='highlight-rounded'>
            <Navbar.Link href='#'>Features</Navbar.Link>
            <Navbar.Link isActive href='#'>
              Customers
            </Navbar.Link>
            <Navbar.Link href='#'>Pricing</Navbar.Link>
            <Navbar.Link href='#'>Company</Navbar.Link>
          </Navbar.Content>
          <Navbar.Content>
            <Navbar.Item>
              {isloggedIn ? (
                <Button auto flat as={Link} href='http://localhost:3000/auth'>
                  Login
                </Button>
              ) : (
                <Button auto flat as={Link} onPress={onLogout}>
                  Sign Out
                </Button>
              )}
            </Navbar.Item>
          </Navbar.Content>
        </Navbar>
        <Grid.Container gap={2} justify='center'>
          {list.map((item, index) => (
            <Grid xs={6} sm={2.5} key={index}>
              <Card isPressable>
                <Card.Body css={{ p: 0 }}>
                  <Card.Image
                    src={'https://nextui.org' + item.img}
                    objectFit='cover'
                    width='100%'
                    height={140}
                    alt={item.title}
                  />
                </Card.Body>
                <Card.Footer css={{ justifyItems: 'flex-start' }}>
                  <Row wrap='wrap' justify='space-between' align='center'>
                    <Text b>{item.title}</Text>
                    <Text
                      css={{
                        color: '$accents7',
                        fontWeight: '$semibold',
                        fontSize: '$sm',
                      }}
                    >
                      {item.price}
                    </Text>
                  </Row>
                </Card.Footer>
              </Card>
            </Grid>
          ))}
        </Grid.Container>
      </SessionAuth>
    </>
  );
}
```

The `signOut` method revokes the session on both the frontend and backend. 

As seen in the code above, SuperTokens does not provide us with any UI for a signout button, so we have to add that. We then create a function called `onLogout` and pass it into the button using an `onPress` method. 

Also, on auth success, the `signOut` function does not automatically redirect the user to the home page, so we do that by ourselves by using `window.location`. 

The `signOut` function uses the backend signout API that was made available by the session recipe. Sign in and click on the `signOut` button to log out. 

To implement a forgotten password functionality, we don't have to do anything as SuperTokens takes care of this already.

## Upcoming SuperTokens features to watch out for

At the time of writing this article, the following features are currently been developed:

*   Account linking
*   Support of other languages(Java, PHP)
*   Organization/Multi-tenant support

You can stay updated with them by checking the [SuperTokens product map](https://supertokens.com/product-roadmap).

## Conclusion

This tutorial taught you how to set up quick and easy authentication in your Next.js application without extra complexities. We learned about the various recipes available and the pros and cons of SuperTokens compared to other similar solutions. 

You can go ahead and try adding [session verification](https://supertokens.com/docs/emailpassword/nextjs/session-verification/in-api) to this example. Also, explore other strategies (recipes) that suite your needs and work with other frameworks and languages. 

Feel free to drop a comment to let me know what you thought of this article. You can also find me on [Twitter](https://twitter.com/wisdom_ekpotu) and [GitHub](https://github.com/wisdomekpotu). Thank you for reading!

---

## [LogRocket](https://logrocket.com/signup): Full visibility into production Next.js apps

Debugging Next applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try [LogRocket](https://logrocket.com/signup). 

[![LogRocket signup](https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png)](https://logrocket.com/signup)

[LogRocket](https://logrocket.com/signup) is like a DVR for web and mobile apps, recording literally everything that happens on your Next app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your Next.js apps — [start monitoring for free](https://logrocket.com/signup).