# Clerk Blog — Guides — Page 5

# A Complete Guide to Session Management in Next.js
URL: https://clerk.com/blog/complete-guide-session-management-nextjs.md
Date: 2023-09-27
Category: Guides
Description: Session management allows users to stay logged in across multiple tabs devices and maintains security by tracking user sessions.

Session management is a concept that flies under the radar in most applications. It’s built into every authentication library you are using, and seamlessly allows users to stay logged in, use different tabs, and stay secure while they are using your app.

But because it is abstracted away by auth systems, it’s also opaque. How does session management work to keep track of your usage?

Here, we want to build session management in Next.js without using any authentication library to show you what is really happening under the hood.

## What is a session?

This might seem like a trivial question, but it doesn’t have a trivial answer. One of the reasons that session management is often abstracted away from developers is that it’s a difficult concept to grok and implement.

A [session](/blog/what-is-session-management) is a series of interactions between a user and an application that occur within a given time frame.

A session is initiated when a user logs in or starts interacting with the application and is typically terminated when the user logs out or after a period of inactivity. It is a way to preserve certain data/state across multiple requests between the client and the server in an inherently stateless environment, which is the HTTP protocol.

These are the main components of a session:

1. **Session Identifier** (Session ID): A unique string that distinguishes one session from another. It is sent by the server to the client after successful login and is usually stored in a cookie on the client side.
2. **Session Store**: A storage mechanism, often on the server side, where session data, such as user details and preferences, are stored. This could be in-memory storage, a database, a file system, or a distributed cache, depending on the application's requirements.
3. **Session Data**: Information stored in the session, often including user preferences, user identification and authentication data, and temporary application state. This data is used to personalize the user experience and to maintain the state of the application between different requests from the client.
4. **Session Timeout**: A mechanism to terminate sessions after a predefined period of inactivity to minimize the risk of unauthorized access. Once a session is timed out, the user needs to re-authenticate to continue interacting with the application.
5. **Session Cookie**: A type of HTTP cookie sent from the server to the client’s browser to store the session ID.

So a session lifecycle starts with **creation**, when a session is created from a user login or starts interacting with an application. This is when a unique session ID is generated and associated with the user. The session is **maintained** through the session ID that is transmitted with each subsequent request from the client and is used to retrieve and manage session data on the server. The session **ends** when the user logs out or after a period of inactivity (session timeout). Any data stored in the session is usually deleted or invalidated.

## Why session management is important

Session management is pivotal for the seamless functioning and robust security of web applications. When it's not implemented effectively, applications become vulnerable to a host of security issues and often provide an experience that's frustrating for users. Thus, grasping and applying solid session management strategies are absolutely critical if one wants to build web applications that are secure, scalable, and user-friendly.

### Importance for Security

Session management acts as the security guard of web applications. It works to correctly identify and authenticate users, ensuring they only access what they’re allowed to. It’s there to protect sensitive information belonging to the users by allowing only authenticated and authorized individuals to access it. It also safeguards session identifiers as they are transmitted and stored. It shields applications from security threats, such as session hijacking, session fixation, and Cross-Site Request Forgery (CSRF).

### Enhancement of User Experience

From a user experience standpoint, sessions empower applications to remember user preferences and deliver personalized content, crafting an experience that is more engaging for the user. Efficient session management allows users to move between different devices and browser tabs when interacting with applications without needing to keep logging in. This ease of access enhances overall user convenience and experience. Sessions are like invisible assistants, remembering temporary data between user requests, meaning users can roam freely within an application without the fear of losing their progress or context.

Beyond security and user experience, sessions are a tool for collecting valuable data regarding user behavior and preferences. This kind of information is a goldmine for businesses, helping them make well-informed decisions and refine their strategies based on user interaction and needs. In essence, it’s like having a pulse on user behavior, enabling the refinement of business strategies and decision-making.

## Setting up session management in Next.js

We’re going to produce a simple two page site that allows us access to a protected page if we are logged in. Fundamentally, this is an authentication setup, but we are going to set it up using JSON Web Tokens (JWT) that we’ll store on the client. This will give the user a live "session," so once they have logged in, they can continue to access the protected page, until the token and session expires.

We’re going to use Next.js 13 and the App Router. Let’s first create a new Next project:

```sh
npx create-next-app@latest
```

To follow this tutorial you should use the defaults from the prompts. We’ll then open up the code in our IDE. We’re using VS Code, so we can:

```sh
cd my-app
code .
```

We also want to install the libraries we’re going to use. None of these are authentication libraries. Instead they are libraries that let us directly access cookies and databases, and implement JWTs.

```sh
npm install js-cookie sqlite sqlite3 jsonwebtoken
```

- `js-cookie` is a lightweight JavaScript library that provides a straightforward API to handle browser cookies, allowing you to create, read, and delete cookies in a way that works with various JavaScript environments, like the browser and Node.js.
- `sqlite` is a library that serves as a lightweight, file-based database engine, allowing developers to utilize SQL-based database functionality without the need for a full-fledged database management system.
- `sqlite3` is a Node.js library that provides bindings to SQLite3, enabling interaction with SQLite databases, allowing developers to perform operations like querying, updating, and deleting records in SQLite databases from within Node.js applications.
- `jsonwebtoken` is a Node.js library that allows you to securely handle JSON Web Tokens (JWTs), which are compact, URL-safe means of representing claims to be transferred between two parties, commonly used for authentication and information exchange in web development.

Now, we’re ready to code.

### The login page

First, let’s remove the boilerplate from the app/page.js file and replace it with this code:

```jsx
'use client'
import { useState } from 'react'
import { useRouter } from 'next/navigation'

function LoginPage() {
  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')
  const router = useRouter()

  const handleLogin = async (e) => {
    e.preventDefault() // Prevent default form submission

    try {
      const response = await fetch('/api/login', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          username,
          password,
        }),
      })

      if (!response.ok) throw new Error('Login failed')

      const { token } = await response.json()
      document.cookie = `token=${token}; path=/`
      router.push('/protected')
    } catch (error) {
      console.error(error)
    }
  }

  return (
    <div>
      <form onSubmit={handleLogin}>
        <label>
          Username:
          <input
            type="text"
            value={username}
            onChange={(e) => setUsername(e.target.value)}
            required
          />
        </label>
        <br />
        <label>
          Password:
          <input
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            required
          />
        </label>
        <br />
        <button type="submit">Log In</button>
      </form>
    </div>
  )
}

export default LoginPage
```

### Login Code

This is going to be our login page. The UX is simple–just a form with a username field, a password field, and a submit button.

![Complete Guide Session Management Nextjs guide illustration](./1b1e772a51af40ea7d19df96151a464aac6a65c9-2000x1264.png)

When the button is clicked, the `handleLogin` function is called.

The `handleLogin` function is an asynchronous event handler that deals with the logic of the login attempt. There are five main components to this function:

1. `const response = await fetch("/api/login", {...})`. This sends a POST HTTP request to the `/api/login` endpoint with the username and password as the body of the request.
2. `if (!response.ok) throw new Error("Login failed")`. This checks if the response received from the server is not ok (i.e., the HTTP status code is not in the range 200-299). If it's not ok, it throws an error with the message "Login failed".
3. `const { token } = await response.json()`. If the response is ok, this parses the JSON body of the response and extracts the token property from it. This is the token that authenticates the user for subsequent requests.
4. `document.cookie = token=${token}; path=/`. This sets a cookie in the user's browser with the name token and the value received from the login API, which is accessible to any path in the domain.
5. `router.push("/protected")`. This navigates the user to the `/protected` route of the app.

So this is calling the login API, and if it receives a token back, sets that token in the browser and passes the user to the protected page. If the login fails and no token comes back, it just tells the user “Login failed.”

### The login API

Let’s take a look at the login API next:

```jsx
import { NextResponse } from 'next/server'
import sqlite3 from 'sqlite3'
import { open } from 'sqlite'
import jwt from 'jsonwebtoken'

async function authenticateUser(username, password) {
  let db = null

  // Check if the database instance has been initialized
  if (!db) {
    // If the database instance is not initialized, open the database connection
    db = await open({
      filename: 'userdatabase.db', // Specify the database file path
      driver: sqlite3.Database, // Specify the database driver (sqlite3 in this case)
    })
  }

  const sql = `SELECT * FROM users WHERE username = ? AND password = ?`
  const user = await db.get(sql, username, password)
  return user
}

export async function POST(req) {
  const body = await req.json()
  const { username, password } = body

  // Perform user authentication here against your database or authentication service
  const user = await authenticateUser(username, password)
  const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, {
    expiresIn: '1m',
  })
  return NextResponse.json({ token })
}
```

Let’s go through the POST function first. This is the part of the code that receives the POST call from the login page and authenticates our users.

- `const body = await req.json()` reads the JSON body from the incoming request object (req). It is awaited because reading the body is an asynchronous operation.
- `const { username, password } = body`. After the body is read, the username and password are destructured from it. These would be the username and password sent in the request, likely provided by the user through a form in the frontend.
- `const user = await authenticateUser(username, password)` calls the authenticateUser function to authenticate users against the user database.
- `const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: "1m" })`. If the user is successfully authenticated, a JWT is generated using the jwt.sign method. This token includes the user’s ID (user.id) as part of its payload. The token is signed using a secret key stored in `process.env.JWT_SECRET`, and it’s set to expire in 1 minute (expiresIn: "1m").
- `return NextResponse.json({ token })`. Finally, if everything is successful, the function returns a response with the generated token in JSON format.

The core parts here are the `authenticateUser` call and the JWT signing. We’ll look closer at the `authenticateUser` call in a moment, but let’s discuss JWTs first as they are integral to session management.

### JSON Web Tokens

JSON Web Tokens (JWTs) are a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of the token, which is then signed to secure the information.

JWTs are commonly used for authentication and information exchange in web development. When a user logs in, the server generates a JWT that encodes user information (like user ID) and sends this token to the client. The client then includes this token in the Authorization header in subsequent requests, allowing the server to identify and authorize the user.

JWTs consist of three parts separated by dots (.):

1. **Header**: The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 or RSA.
2. **Payload**: The payload contains the claims. Claims are statements about a user and additional metadata, such as expiry times, which are critical in session management.
3. **Signature**: The signature is used to verify the message wasn't changed along the way and, in the case of tokens signed with a private key, it can also verify the sender of the JWT.

A JWT might look like this:

```text
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
```

- The first part is the Header, Base64Url encoded.
- The second part is the Payload, also Base64Url encoded.
- The third part is the Signature.

So here, the payload is our user ID, and we’re signing the token with our `JWT_SECRET` in our `.env.local`. This secret should be a long, random string. You can [generate a random JWT secret](https://mojitocoder.medium.com/generate-a-random-jwt-secret-22a89e8be00d) like this:

```sh
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
```

### Authenticating the user

The `authenticateUser` function is an asynchronous function intended to authenticate a user based on a provided username and password against a user record in an SQLite database.

Session management is really user management. So, you need to have a database set up of all your users so you can get, in this case, their IDs to add as the JWT payload. Here, we’ve set up a small SQLite database locally with a single user. To do this properly, you’ll need a full database for all your users, plus a way to add those users.

In this function, we initialize a connection to an SQLite database file named `userdatabase.db` using the sqlite [`open`](https://javascript.plainenglish.io/using-sqlite-with-next-js-13-cfa270e1d7ba) method. Once the database connection is established, we create an SQL query string, `sql`, to select a user from the users table where the `username` and `password` match the provided arguments.

We then execute this SQL query using `await db.get(sql, username, password)`, which will return the first row that satisfies the conditions (i.e., where the username and password match the input), or return undefined if no such row exists.

We then return that user to the `POST` function, which uses the ID within the JWT payload, and returns that to the client.

### Validating the token

After we’ve got the user and added the token to the user’s browser cookies, we are routed to the /protected page.

```jsx
'use client'
import Cookies from 'js-cookie'
import jwt from 'jsonwebtoken'
import { useEffect } from 'react'
import { useRouter } from 'next/navigation'

function ProtectedPage() {
  const router = useRouter()

  useEffect(() => {
    const token = Cookies.get('token')

    if (!token) {
      router.replace('/') // If no token is found, redirect to login page
      return
    }

    // Validate the token by making an API call
    const validateToken = async () => {
      try {
        const res = await fetch('/api/protected', {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        })

        if (!res.ok) throw new Error('Token validation failed')
      } catch (error) {
        console.error(error)
        router.replace('/') // Redirect to login if token validation fails
      }
    }

    validateToken()
  }, [router])

  return <div>Protected Content</div>
}

export default ProtectedPage
```

Not too much is happening on this page, apart from checking the token exists on the local client and then sending it as part of the authorization header as a bearer token to the protected API endpoint. That endpoint is where we do two things:

1. Check that the token hasn’t expired
2. Check that the token is valid

```jsx
import jwt from 'jsonwebtoken'
import { NextResponse } from 'next/server'
import { headers } from 'next/headers'

export async function GET() {
  try {
    const headersInstance = headers()
    const authHeader = headersInstance.get('authorization')

    const token = authHeader.split(' ')[1]

    const decoded = jwt.verify(token, process.env.JWT_SECRET)
    if (!decoded) {
      return NextResponse.json(
        { message: 'Expired' },
        {
          status: 400,
        },
      )
    } else if (decoded.exp < Math.floor(Date.now() / 1000)) {
      return NextResponse.json(
        { message: 'Expired' },
        {
          status: 400,
        },
      )
    } else {
      // If the token is valid, return some protected data.
      return NextResponse.json(
        { data: 'Protected data' },
        {
          status: 200,
        },
      )
    }
  } catch (error) {
    console.error('Token verification failed', error)
    return NextResponse.json(
      { message: 'Unauthorized' },
      {
        status: 400,
      },
    )
  }
}
```

The first part is to extract the authorization header from the request, and then extract the token by splitting it from `Bearer`.

Then we use the verify method on the JWT with the secret we used to sign it originally. This will allow us to show it is an authenticated token. If the token is invalid, `jwt.verify` throws an error. From there, we want to check whether the token has expired by comparing the exp field in the decoded token with the current timestamp.

If the token is valid and not expired, the function returns a JSON response (with some data if you wanted). If the token is invalid or expired, or if any error occurs during verification, it returns a JSON response with a 400 status code and a message "Unauthorized".

If all is good, the user will be directed to the protected page:

![Complete Guide Session Management Nextjs guide illustration](./da7c8a02cfdbb7b9a65e0f53ae3c725e060bcdc8-2000x1264.png)

Because the token persists within the browser, they can also go to the protected page in another tab:

![Complete Guide Session Management Nextjs guide illustration](./419859cc96776f5a43a5d90463299cc8f812cd6b-2000x1264.png)

But the token expires after only a minute. If they try and reload after that time, they are redirected to the login page again:

![Complete Guide Session Management Nextjs guide illustration](./1b1e772a51af40ea7d19df96151a464aac6a65c9-2000x1264.png)

And you have successfully managed a session!

### The problems with this approach

This is the most basic code to get session management working. But even here we’ve had to manage our own user database, manage our own secrets, and manage all of the logic in between. It isn’t a robust system:

- We’re missing the substantial error handling that is needed for this to work properly. For instance, we want to handle the case where the Authorization header is missing or malformed, to avoid issues like calling split on undefined, which would throw an error.
- We’re missing any of the checks in the user management system for encrypting passwords.
- We’re not managing our database calls well or persisting a connection.

If you are building your own session management system, you are also building your own user management system, and becoming a database administrator.

## Session management in Next.js with Clerk

The easier way is to [use a specifically designed authentication library](/nextjs-authentication). Here, we’re going to use Clerk, but any auth library is going to take this headache away from you.

First, we’ll set up the project in exactly the same way:

```
npx create-next-app@latest
```

Again, use the defaults from the prompts. Then open the code

```
cd my-clerk-app
code .
```

We don’t need to install all the libraries from before. All we need this time is the Clerk SDK:

```sh
npm install @clerk/nextjs
```

We’ll start with adding the environment variables we need for Clerk–our `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY`–into our `.env.local file`:

```text
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_something
CLERK_SECRET_KEY=sk_test_something
```

After that, we need to add the [`<ClerkProvider />`](/docs/components/clerk-provider) wrapper to the app. This is the critical component for session management. It is what we provide the active session and user information to all of Clerk’s components anywhere in the app. We add it in` Layout.js`, wrapping the entire body of our application:

```jsx
import { ClerkProvider } from '@clerk/nextjs'

export const metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({ children }) {
  return (
    <ClerkProvider>
      <html lang="en">
        <body>{children}</body>
      </html>
    </ClerkProvider>
  )
}
```

We’ll then add some middleware. This is what decides which pages are protected and which aren’t. The default code below protects every page on the site:

```jsx
import { authMiddleware } from '@clerk/nextjs'

// This example protects all routes including api/trpc routes
// Please edit this to allow other routes to be public as needed.
// See https://clerk.com/docs/references/nextjs/auth-middleware for more information about configuring your middleware
export default authMiddleware({})

export const config = {
  matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'],
}
```

We then need three pages. First, a sign up page, which will go at `app/sign-up/[[...sign-up]]/page`:

```jsx
import { SignUp } from '@clerk/nextjs'

export default function Page() {
  return <SignUp />
}
```

Then a sign in page at `app/sign-in/[[...sign-in]]/page`:

```jsx
import { SignIn } from '@clerk/nextjs'

export default function Page() {
  return <SignIn />
}
```

Finally, we’ll add a button to interact with these pages on our home page:

```jsx
import { UserButton } from '@clerk/nextjs'

export default function Home() {
  return (
    <div>
      <UserButton afterSignOutUrl="/" />
    </div>
  )
}
```

That’s a lot less code. We need to add paths to these in our `.env.local` as well:

```text
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/
```

And that’s it. Run `npm run dev` and you’ll get a way to sign in:

![Complete Guide Session Management Nextjs guide illustration](./0eb8660cecafbbf96fd7fe4858a3fab97b6868d1-2000x1264.png)

Sign in, and you’ll be at a protected account page:

![Complete Guide Session Management Nextjs guide illustration](./0eb8660cecafbbf96fd7fe4858a3fab97b6868d1-2000x1264.png)

And that is all that’s needed for session management with Clerk. You can set up other [session options](/docs/authentication/configuration/session-options) like token timeouts and custom payloads in your [dashboard](https://dashboard.clerk.com).

## The pitfalls of session management

Session management is a critical component in web development, acting as the gatekeeper to user-specific, sensitive information and functionalities.

But implementing robust session management is not without its challenges. Security, performance, and usability issues are all concerns you’ll have to deal with when building session management in Next.js. Like many aspects of authentication, [session management](/blog/what-is-session-management) is one that is best left to dedicated libraries and solutions. Check out the [Clerk session docs](/docs/authentication/configuration/session-options) to find out more about setting this up easily with Clerk.

---

# The Advanced Guide to Passwordless Authentication in Next.js
URL: https://clerk.com/blog/advanced-guide-passwordless-authentication-nextjs.md
Date: 2023-08-25
Category: Guides
Description: Learn how to implement passwordless authentication in Next.js using magic links, social OAuth and SAML SSO.

The password has been the bedrock of account security for decades. But their vulnerabilities are well-known. From weak password choices to recycling them across platforms, users inadvertently make it simple for bad actors to gain unauthorized access.

The concept of “passwordless authentication” has become a solution to this problem. Single Sign-Ons (SSOs), OAuth, SAML, [magic links](/blog/magic-links) —each of these techniques can enhance user experience and increase security in your app. What has previously stopped developers is the difficulty of implementation. But with modern JavaScript libraries, these options now come out-of-the-box.

In this guide, we’ll implement [passwordless authentication in Next.js](/nextjs-authentication) all the way from creating the sign in page to testing each of the above techniques to usher in more secure, streamlined authentication.

## Setting Up Next.js Application

This article will use [Next.js 13](https://nextjs.org) and [Clerk’s Next.js SDK](https://www.npmjs.com/package/@clerk/nextjs) to create a passwordless flow. Start by creating a new Node project.

```sh
 npm init -y
```

Create a new Next.js app. This command will use TypeScript by default, which we recommend:

```sh
npx create-next-app@latest
```

Once you have a Next.js application ready, you also need to install [Clerk’s Next.js SDK](https://www.npmjs.com/package/@clerk/nextjs) library. The SDK contains prebuilt React components and hooks, allowing for fast time-to-market.

```sh
npm i @clerk/nextjs
```

Now, create a new `.env.local` file in the source of your project, which will contain all keys and endpoints. See keys in the [Clerk dashboard](https://dashboard.clerk.com/last-active?path=api-keys).

```sh
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
```

Continue by mounting the `<ClerkProvider>` wrapper which will serve as the session and user context provider to the app.

It is advised that the `<ClerkProvider>` wraps the `<body>` element, allowing context-accesibility anywhere within the app.

```tsx
// app/layout.tsx
import './globals.css'
import { Inter } from 'next/font/google'
import { ClerkProvider } from '@clerk/nextjs'

const inter = Inter({ subsets: ['latin'] })

export const metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <ClerkProvider>
      <html lang="en">
        <body className={inter.className}>{children}</body>
      </html>
    </ClerkProvider>
  )
}
```

If you intend to use the `<ClerkProvider>` outside the root layout, you must ensure it is also a server component, just like the root layout.

### Protect the App

After giving the app Clerk’s context, you will now create a middleware, which will dictate which page should be public and which need to be behind an authentication wall.

Create a `middleware.ts` file in the root folder of your app (or inside `src/` if you opted for that).

```jsx
import { authMiddleware } from '@clerk/nextjs'

// This example protects all routes including api/trpc routes
// Please edit this to allow other routes to be public as needed.
// See https://clerk.com/docs/nextjs/middleware for more information about configuring your middleware
export default authMiddleware({})

export const config = {
  matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'],
}
```

This will protect your entire application. By accessing the application you will be redirected to the Sign Up page. Read more about [authMiddleware](/docs/nextjs/middleware) to see how to make other routes public.

## Implementing Magic Links in Next.js Using Clerk

![Advanced Guide Passwordless Authentication Nextjs tutorial illustration](./610e8c4b679fbc725708dd90ea03dc2e496c4436-3592x1198.png)

Magic links offer a seamless and secure alternative to traditional password-based authentication, elevating user convenience while bolstering security and representing a modern shift in authentication.

In this section, you will methodically explore the steps to [implement magic links in Next.js](/blog/magic-links) through the Clerk platform.

### Creating the Sign Up Page

We’ll start off by creating a simple sign up page, containing a magic link flow. Start by following the steps outlined below:

1. Create a new folder `sign-up` in the `app` folder (so `app/sign-up`).

2. Create a subfolder `[[...sign-up]]` in the `sign-up` folder (so `app/sign-up/[[...sign-up]]`). This will use [Next.js optional catch-all route](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes).

3. Create a new file `page.tsx` inside that subfolder (finally, `app/sign-up/[[...sign-up]]/page.tsx`).

4. Import the necessary dependencies:

```jsx
'use client'
import React from 'react'
import { useRouter } from 'next/navigation'
import { useSignUp } from '@clerk/nextjs'
```

5. Continue by creating a new functional component and a few hooks that will be used later down the road to conditionally render components and perform authentication:

```jsx
export default function SignUp() {
  const [emailAddress, setEmailAddress] = React.useState('')
  const [expired, setExpired] = React.useState(false)
  const [verified, setVerified] = React.useState(false)
  const router = useRouter()
  const { signUp, isLoaded, setActive } = useSignUp()
}
```

6. You’ll now check whether the `useSignUp` is loaded:

```jsx
if (!isLoaded) {
  return null
}
```

7. Next, destructure methods that will be used to initiate and cancel a magic link flow:

```jsx
const { startMagicLinkFlow, cancelMagicLinkFlow } = signUp.createMagicLinkFlow()
```

8. You’ll now create a method that will perform actual magic link flow:

```tsx
async function submit(e: any) {
  e.preventDefault()
  setExpired(false)
  setVerified(false)
  if (signUp) {
    // Start the sign up flow, by collecting
    // the user's email address.
    await signUp.create({ emailAddress })

    // Start the magic link flow.
    // Pass your app URL that users will be navigated
    // when they click the magic link from their
    // email inbox.
    // su will hold the updated sign up object.
    const su = await startMagicLinkFlow({
      redirectUrl: 'http://localhost:3000/verification',
    })

    // Check the verification result.
    const verification = su.verifications.emailAddress
    if (verification.verifiedFromTheSameClient()) {
      setVerified(true)
      return
    } else if (verification.status === 'expired') {
      setExpired(true)
    }

    if (su.status === 'complete') {
      // Sign up is complete, we have a session.
      // Navigate to the after sign up URL.
      setActive({ session: su.createdSessionId || '' })
      router.push('/after-sign-up')
      return
    }
  }
}
```

This method takes the inputted email address of an user and starts the magic link flow. Then, a link is sent to the given email with a specified redirect URL. Later, the method will perform verification and update the state accordingly.

9. Now, let’s add some conditional logic to render the components giving the user some input and feedback.

```jsx
if (expired) {
  return <div>Magic link has expired</div>
}

if (verified) {
  return <div>Signed in on other tab</div>
}

return (
  <form onSubmit={submit}>
    <input type="email" value={emailAddress} onChange={(e) => setEmailAddress(e.target.value)} />
    <button type="submit">Sign up with magic link</button>
  </form>
)
```

That’s it for the sign up page. As we specified a redirect URL above in the submit method, we also need to handle that logic.

### Setting Up the Verification Page

To complete the magic link flow, we need to perform the verification that will be the final decision between authentication or denial.

1. Start by creating a new folder `verification` in the `app` folder (so, `app/verification`).

2. Create a new file `page.tsx` inside the folder (so, `app/verification/page.tsx`).

3. Import the dependencies:

```jsx
import { MagicLinkErrorCode, isMagicLinkError, useClerk } from '@clerk/nextjs'
import React from 'react'
```

4. Next, create a functional component for the page and the hooks:

```jsx
function Verification() {
  const [verificationStatus, setVerificationStatus] = React.useState('loading')

  const { handleMagicLinkVerification } = useClerk()
}
```

5. Now, we’ll use the `useEffect` hook from React to perform the flow verification.

```tsx
React.useEffect(() => {
  async function verify() {
    try {
      await handleMagicLinkVerification({
        redirectUrl: 'https://redirect-to-pending-sign-up',
        redirectUrlComplete: 'https://redirect-when-sign-up-complete',
      })
      // If we're not redirected at this point, it means
      // that the flow has completed on another device.
      setVerificationStatus('verified')
    } catch (err: any) {
      // Verification has failed.
      let status = 'failed'
      if (isMagicLinkError(err) && err.code === MagicLinkErrorCode.Expired) {
        status = 'expired'
      }
      setVerificationStatus(status)
    }
  }
  verify()
}, [])
```

The verification will happen on the page load, hence the `useEffect` hook.

6. Finish it off with some conditional rendering again:

```jsx
if (verificationStatus === 'loading') {
  return <div>Loading...</div>
}

if (verificationStatus === 'failed') {
  return <div>Magic link verification failed</div>
}

if (verificationStatus === 'expired') {
  return <div>Magic link expired</div>
}

return <div>Successfully signed up. Return to the original tab to continue.</div>
```

### Testing the Magic Link Flow Integration

After writing down the code, let’s test the magic flow integration by starting up the Next.js app with the following command:

```sh
npm run dev
```

After the app has started, navigate to `http://localhost:3000` in your browser. In the input area presented, enter a valid email address on which you will receive a magic link.

![Advanced Guide Passwordless Authentication Nextjs tutorial illustration](./0a1647dbf3a2f262e28679c5f702b9d3c933a516-584x62.png)

Then, press **Sign up with magic link button**. Shortly, an email from Clerk will arrive with the magic link for signing up.

![Advanced Guide Passwordless Authentication Nextjs tutorial illustration](./6053b9de32b521426c399fb571dca03925384ed0-1230x688.png)

If the verification is successful, you will be presented with a confirmation message.

![Advanced Guide Passwordless Authentication Nextjs tutorial illustration](./614b77c622741d4f4b0207b70fde8b9dd1d1c328-956x60.png)

## Implementing OAuth in Next.js Using Clerk

OAuth stands as a cornerstone in modern authentication, allowing users to securely log in using third-party accounts without sharing passwords.

When integrated effectively, it can transform the user authentication experience, making it both swift and secure.

In this section, we will delve into the intricacies of setting up OAuth, harnessing the utility of Clerk.

### Setting Up Social Connection in Clerk Dashboard

To enable a social connection provider, go to the [Clerk Dashboard](https://dashboard.clerk.com), select your **Application**, and navigate to **User & Authentication >** **Social Connections.** Social connection configuration consists of the following steps:

1. Enable the providers you want to use.
2. (production instances only) Enter your OAuth credentials (Client ID and Client Secret) for each provider
3. (production instances only) Copy the `Authorized redirect URI` from the Clerk Dashboard to the provider's app configuration.

Clerk supports multiple providers, but for the purposes of this guide we will enable social connection with **Google**.

![Advanced Guide Passwordless Authentication Nextjs tutorial illustration](./ee5b5d833d6af497e0502c3a49363c7a58024ff2-3522x1958.png)

In development, after applying these changes, you're good to go! To make the development flow as smooth as possible, Clerk uses pre-configured shared OAuth credentials and redirect URIs.

Using shared OAuth credentials should not be treated as secure and you will be considered to operate under Development
mode. For this reason, you will be asked to authorize the OAuth application every single time. Also, they are not
allowed for production instances, where you should provide your own instead.

### Creating the Social Sign Up Page

You can start with a blank sign-up page (`app/sign-up/[[…sign-up]]`), described above in the section **Implementing Magic Links in Next.js Using Clerk**.

1. Import the dependencies:

```jsx
'use client'
import { useSignIn } from '@clerk/nextjs'
import { OAuthStrategy } from '@clerk/nextjs/server'
```

2. Create a functional component with some hooks:

```jsx
export default function SignInOAuthButtons() {
  const { signIn } = useSignIn()
}
```

3. Next, create a method that will handle the single-sign on (SSO) process:

```tsx
const signInWith = (strategy: OAuthStrategy) => {
  if (signIn) {
    return signIn.authenticateWithRedirect({
      strategy,
      redirectUrl: '/sso-callback',
      redirectUrlComplete: '/',
    })
  }
}
```

4. And finish it off with rendering a simple button for signing up:

```jsx
return (
  <div>
    <button onClick={() => signInWith('oauth_google')}>Sign in with Google</button>
  </div>
)
```

### Creating a Single-Sign On (SSO) Callback in Next.js

[Single Sign-On (SSO)](https://en.wikipedia.org/wiki/Single_sign-on) streamlines user access across multiple services, providing a centralized and more efficient authentication process.

In this section, you’ll create an SSO callback using a very simple component from Clerk.

1. Create a new folder `sso-callback` in the `app` folder (so `app/sso-callback`).

2. Create a new file `page.tsx` in that folder (so `app/sso-callback/page.tsx`).

3. Import a dependency:

```jsx
import { AuthenticateWithRedirectCallback } from '@clerk/nextjs'
```

4. Finish it off by returning a Clerk redirection component - [AuthenticateWithRedirectCallback](/docs/component-reference/authenticate-with-redirect-callback), used to complete an OAuth flow:

```jsx
export default function SSOCallback() {
  // Handle the redirect flow by rendering the
  // prebuilt AuthenticateWithRedirectCallback component.
  // This is the final step in the custom SAML flow
  return <AuthenticateWithRedirectCallback />
}
```

### Testing the Social OAuth Flow Integration

Let’s test the social integrations by starting up the Next.js app with the following command:

```sh
npm run dev
```

Navigate to `http://localhost:3000` in the browser and you’ll be presented with a button Sign in with Google.

![Advanced Guide Passwordless Authentication Nextjs tutorial illustration](./46c659f01aa89cf77ed0822c03847b6b326a0a12-268x70.png)

Press the button and you will be redirected to the Google OAuth. Select an account you want to use.

![Advanced Guide Passwordless Authentication Nextjs tutorial illustration](./778d5c5d55cb14cc2243c0899e4c7a5abfa7adf1-1078x1424.png)

After successful authentication, you will be redirected to the user page.

## Implementing SAML SSO in Next.js Using Clerk

[The Security Assertion Markup Language (SAML)](https://en.wikipedia.org/wiki/Security_Assertion_Markup_Language) is a pivotal standard for Single Sign-On (SSO) implementations, offering secure and efficient user authentications across different services.

Mostly used by B2B companies, it allows companies to utilize one set of credentials across all of their tools.

This section will cover how to integrate SAML SSO in the Next.js, using Clerk.

### Setting Up SAML SSO in Clerk Dashboard

To enable a social connection provider, go to the [Clerk Dashboard](https://dashboard.clerk.com), select your Application, and navigate to **User & Authentication > Enterprise Connections**.

![Advanced Guide Passwordless Authentication Nextjs tutorial illustration](./baba635074a4ce6b4c79b27e65baff08b1755d2a-3600x2002.png)

Then, press + Create connection. Enter the name and the domain for the connection.

![Advanced Guide Passwordless Authentication Nextjs tutorial illustration](./d03820277a6182edf88d44a60793001c1b54bbf7-1256x886.png)

Go to the newly created connection and perform the setup.

![Advanced Guide Passwordless Authentication Nextjs tutorial illustration](./ad1eecbfde9469e47a5b17f746a856ab5f051737-3600x2004.png)

Here, you can assign the Identity Provider (IdP) SSO URL, IdP Entity ID and the certificate.

### Creating the SAML Sign In Page in Next.js Using Clerk

Creating the SAML sign in page is very simple. We will tweak the OAuth page slightly and should get a working SAML sign in page.

Here’s the OAuth page code, let’s see what we need to change.

```tsx
'use client'
import { useSignIn } from '@clerk/nextjs'
import { OAuthStrategy } from '@clerk/nextjs/server'

export default function SignInOAuthButtons() {
  const { signIn } = useSignIn()
  const signInWith = (strategy: OAuthStrategy) => {
    if (signIn) {
      return signIn.authenticateWithRedirect({
        strategy,
        redirectUrl: '/sso-callback',
        redirectUrlComplete: '/',
      })
    }
  }
  // Render a button for each supported OAuth provider
  // you want to add to your app
  return (
    <div>
      <button onClick={() => signInWith('oauth_google')}>Sign in with Google</button>
    </div>
  )
}
```

1. We need to change the strategy `import { OAuthStrategy } from "@clerk/nextjs/server"` to `import { SamlStrategy } from "@clerk/types";`

2. Also the `signInWith` method:

```tsx
const signInWith = (strategy: SamlStrategy) => {
  if (signIn) {
    return signIn.authenticateWithRedirect({
      identifier: 'email_goes_here',
      strategy: strategy,
      redirectUrl: '/sso-callback',
      redirectUrlComplete: '/',
    })
  }
}
```

3. And finally the parameter in the button `onClick` handler:

```jsx
return (
  <div>
    <button onClick={() => signInWith('saml')}>Sign in with SAML</button>
  </div>
)
```

## Next Steps and Resources

In this guide you’ve learned how to implement three major methods of passwordless authentication – [magic links](/blog/magic-links), social OAuth and SAML SSO, using Clerk - an advanced user-management platform.

Have an issue within the code? Refer to the extensive [documentation](/docs?utm_source=www.google.com\&utm_medium=referral\&utm_campaign=none).

Continue by implementing [reCAPTCHA in React](/blog/implementing-recaptcha-in-react). Maybe skip [Next.js middleware for static and public files](/blog/skip-nextjs-middleware-static-and-public-files)? Or find your next project idea on Clerk’s [blog](/blog).

---

# Password-Based Authentication in Next.js
URL: https://clerk.com/blog/password-based-authentication-nextjs.md
Date: 2023-07-26
Category: Guides
Description: This article explores password authentication, risks, and better solutions like SSO, MFA, and passwordless login.

Passwords. The best and worst thing that ever happened to internet security. We talk about passwordless and [SSO](/features/social-sso) and [magic links](/blog/magic-links) and [MFA](/features/multifactor-authentication), but [98% of the world’s websites](https://www.shrm.org/resourcesandtools/hr-topics/technology/pages/the-password-is-slowly-becoming-extinct.aspx) only accept password authentication.

It is expected that a site will allow you to enter your own username/email and a password to sign up and log in. Even though we know there are security flaws with this approach and much better ways to build authentication, your site has to have password-based authentication, otherwise it looks… odd.

So how do you do that? Here we’re going to show you. But this is a demonstration of the internal workings of password authentication to give you an understanding of how it works. This isn’t something you should truly build yourself if you care about your users. Use libraries and services built by experts if you are going to implement password authentication in your app–we show you how to do this with Clerk at the end.

## Building passwords from basics in Next.js

You need four components to build password authentication:

1. A frontend where the user can enter their username and password to sign up or log in
2. A backend to deal with the signup/login logic
3. A way to hash the password so it can be stored securely
4. A storage mechanism (and logic) to save the username and hashed password

Parts 1-3 are are possible with Next.js. For storage, we’ll be using [Supabase](https://supabase.com). Supabase is an open source Firebase alternative that provides a large selection of database management tools. It integrates with a large number of modern SaaS tools, including [Clerk](/docs/integrations/databases/supabase). Here, we won’t be using the Supabase libraries. Instead, as under the hood Supabase is a Postgres database, we’ll use the low-level methods to connect and then use SQL to load and recall our data.

Let’s start with creating a new Next.js application:

```
npx create-next-app@latest password-auth
cd password-auth
```

We’ll only be using two extra libraries in this build:

- bcrypt: Bcrypt is a password hashing function which incorporates a salt to protect against rainbow table attacks.
- pg: Pg (short for “node-postgres”) is a collection of Node.js modules for interfacing with PostgreSQL databases, offering features such as connection pooling and prepared statements.

You can install them with npm install:

```
npm install bcrypt pg
```

### Storage

We’ll actually work backwards from our list above and start with our database functionality. As we said, we’re using Supabase. Supabase is an open-source Firebase alternative that provides developers with a suite of tools and services for building serverless applications. It offers real-time databases, instant APIs, and authentication and authorization functionalities.

Here, we’re only going to use the database component, and even then we won’t use the Supabase libraries. Instead, we’ll just use the general Postgres account information to connect directly to the database.

[Sign up for Supabase](https://supabase.com) and create a new project. The project can be called anything, but take note of the password you create as you will need that for the connection. The project will take a few minutes to spool up, but once it has, go to “Database → Table → new table” to create a new table. You’ll only need two fields in this table:

- Username - Text
- Password - Text

You can keep the `id` and `created_at` fields. Make sure, for the purposes of this demo at least, you turn Row Level Security off as otherwise it’ll be much more difficult to access the database.

Row-Level Security (RLS) is a feature that allows fine-grained control over which rows in a table can be accessed and modified by users. With RLS, the database admin can define policies that restrict access to certain rows based on the attributes of the user or the data. If you are building for production, RLS is a must.

With the table created, head to Project Settings -> Database. You’ll see “Connection info.” This is what we’ll need to connect to this database:

With that information (and the password you created earlier), we can now start building the code and logic for our password authentication.

Open up your password-app directory in your favorite IDE and add a “utils” directory at the root. Within utils, create a db.js file that will handle your database connection:

```jsx
import { Pool } from 'pg'

const pool = new Pool({
  user: 'User',
  host: 'Host',
  database: 'Database name',
  password: 'Password',
  port: 5432,
})

export default pool
```

Fill in the `User`, `Host`, `Database name`, and `Password` with the “Connection info” from Supabase.

(Like with RLS, don’t do it this way if you are deploying to production–never hardcode variables like this in your code. Instead save them as environmental variables and import them via process.env).

### Hashing and salting

With our database connection sorted, we can start to create the backend logic we need to route our user requests and deal with the username and password.

There should already be a pages/api directory. Within that create a signup.js file. Add this code to the file:

```jsx
import pool from '../../utils/db'
import bcrypt from 'bcrypt'

export default async function signup(req, res) {
  if (req.method === 'POST') {
    const { username, password } = req.body

    try {
      // Hash the password
      const hashedPassword = await bcrypt.hash(password, 10)

      // Store the username and hashed password in the database
      const result = await pool.query(
        'INSERT INTO users(username, password) VALUES($1, $2) RETURNING *',
        [username, hashedPassword],
      )

      // If user is created successfully, return a success message
      res.status(201).json({ status: 'Created', user: result.rows[0] })
    } catch (error) {
      res.status(500).json({ status: 'Error', message: error.message })
    }
  } else {
    res.status(405).json({ status: 'Method Not Allowed' })
  }
}
```

Here’s a breakdown of what the code does:

- `import pool from ‘../../db’` imports the `pool` object from `db.js` which is a pool of database connections we’re using to connect to Postgres
- `import bcrypt from ‘bcrypt’` imports the `bcrypt` library, which is a password-hashing function. You’ll use it to securely hash passwords before storing them in the database.
- `export default async function signup` defines an asynchronous function called `signup` which is the main function of this module.
- `if (req.method === ‘POST’)` checks if the HTTP request method is POST. If it’s not, it returns a 405 status code.
- `const { username, password } = req.body` destructures the request body to extract the username and password properties from the request body.
- `const hashedPassword = await bcrypt.hash(password, 10)` uses `bcrypt` to hash the user’s password asynchronously with a salt round of 10. The hashed password is then stored in hashedPassword.
- `const result = await pool.query(…)` sends a SQL query to the Supabase to insert a new row into the `users` table. It inserts the username and the hashed password.
- `’INSERT INTO users(username, password) VALUES($1, $2) RETURNING *’` is the SQL query being sent to the database. It’s parameterized to prevent SQL injection attacks. The `$1` and `$2` are placeholders for the `username` and `hashedPassword` that will be inserted.
- The final lines are logic for catching errors or returning success messages.

There’s a lot there, but basically when this API route is called it takes the username and password the user entered, hashes and salts the password, and then saves them in the database.

**What are hashing and salting?**

- Hashing: Hashing is the process of converting an input of any length into a fixed size string of text, using a mathematical algorithm. Hashing is often used to securely store sensitive data such as passwords. Even a small change in the input text will produce a drastic change in the output hash, making it computationally infeasible to derive the original input from the hashed output.
- Salting: Salting is a technique used in conjunction with hashing to increase the security of stored passwords. A salt is a random piece of data generated for each user that is added to the password before it is hashed. This means that even if two users have the same password, their hashed passwords will be different because the salts are different. Salting helps protect against rainbow table attacks, where an attacker pre-computes the hash values for possible passwords and looks for matches with hashed passwords.

All that happens in the line `const hashedPassword = await bcrypt.hash(password, 10)`. Doing this is fundamental to password security. Without it, passwords would be saved in plain text, and anyone having access to the database would be able to retrieve everyone’s passwords. With hashing and salting, what is saved in the database isn’t the raw password.

Now that we can sign up, let’s create a file called pages/api/login.js so we can also log in. In this file, you would fetch the user from the database, compare the hashed passwords, and if they match, return a success:

```jsx
import pool from '../../utils/db'
import bcrypt from 'bcrypt'

export default async function login(req, res) {
  if (req.method === 'POST') {
    const { username, password } = req.body

    try {
      // Get the user with the provided username
      const user = await pool.query('SELECT * FROM users WHERE username = $1', [username])

      if (user.rows.length > 0) {
        const passwordMatches = await bcrypt.compare(password, user.rows[0].password)

        if (passwordMatches) {
          // Passwords match, return a success message
          res.status(200).json({ status: 'Success', message: 'Login successful' })
        } else {
          // Passwords don't match, return an error message
          res.status(403).json({ status: 'Error', message: 'Invalid password' })
        }
      } else {
        res.status(404).json({ status: 'Error', message: 'User not found' })
      }
    } catch (error) {
      res.status(500).json({ status: 'Error', message: error.message })
    }
  } else {
    res.status(405).json({ status: 'Method Not Allowed' })
  }
}
```

This is very similar to the previous route, but instead of hashing and then storing, we’re retrieving and then comparing the stored hash to a hash of the password the user tried with the login page.

We retrieve the saved password from Supabase with `const user = await pool.query(‘SELECT * FROM users WHERE username = $1’, [username])`. This grabs the user with the username just entered by the user.

We then use `const passwordMatches = await bcrypt.compare(password, user.rows[0].password)` to compare the entered password with the retrieved password. `bcrypt.compare` is a function that takes a plain-text input and a hashed string as arguments, and returns true if the plain-text input, when hashed with the same salt as the hashed string, matches the hashed string, thus verifying the authenticity of the input.

### Creating the frontend with Next.js

All we need now is some logic on the frontend for the user to interact with. First, we’ll create a Profile component in components/profile.jsx:

```jsx
import React from 'react'

const Profile = ({ user }) => {
  return (
    <div>
      <h1>Your Profile</h1>
      <p>Welcome, {user.username}!</p>
    </div>
  )
}

export default Profile
```

In this component, we simply display a welcome message with the user’s username. Then we’ll remove the current Next.js boilerplate from index.js and add this code to include a login/signup form and the profile display.

```jsx
import React, { useState } from 'react'

const AuthForm = () => {
  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')
  const [isLoggedIn, setIsLoggedIn] = useState(false)
  const [user, setUser] = useState(null)

  const handleSubmit = async (e, path) => {
    e.preventDefault()
    const response = await fetch(`/api/${path}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ username, password }),
    })
    if (response.ok) {
      const user = await response.json()
      setUser(user)
      setIsLoggedIn(true)
    } else {
      console.log(`${path} failed`)
    }
  }

  return (
    <div>
      {!isLoggedIn ? (
        <form>
          <label>
            Username:
            <input type="text" value={username} onChange={(e) => setUsername(e.target.value)} />
          </label>
          <label>
            Password:
            <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
          </label>
          <button type="submit" onClick={(e) => handleSubmit(e, 'signup')}>
            Signup
          </button>
          <button type="submit" onClick={(e) => handleSubmit(e, 'login')}>
            Login
          </button>
        </form>
      ) : (
        <Profile user={user} />
      )}
    </div>
  )
}

export default AuthForm
```

In this component, we have a form with fields for username and password, and two buttons for signup and login. When either button is clicked, the `handleSubmit` function is called with the corresponding path. If the request is successful, we update the `isLoggedIn` and `user` states, which will cause the `Profile` component to be rendered.

So the user sees this (very simple) form:

![Clerk Login](./1052cd293fef425f61aa9b3b11c5120e38262053-1102x72.png)

If they sign up/log in correctly, they get to their profile page:

![Clerk Profile](./c072c74366600461f737bd84de0aa4c1a7a7173c-368x186.png)

On the backend, we can see the new user in our database in Supabase, with their hashed and salted password:

![Hashed Password](./7663231353d3d9d11a1d426bb3252b18904aaa0d-1786x216.png)

### Extra security

This is a basic example and does not handle all the edge cases you might need to cover in a production app, such as:

- Checking for unique usernames or emails during signup. For instance, the hashing and database retrieval depends on unique usernames.
- Handling password resets.
- Adding email verification.

You can check whether a username exists by running an additional query on the database before you try and select the user:

```jsx
export default async function signup(req, res) {
  if (req.method === 'POST') {
    const { username, password } = req.body

    try {
      // Check if a user with the same username already exists
      const userExists = await pool.query('SELECT username FROM users WHERE username = $1', [
        username,
      ])

      if (userExists.rows.length > 0) {
        res.status(409).json({ status: 'Error', message: 'Username already exists' })
        return
      }

      // Hash the password
      const hashedPassword = await bcrypt.hash(password, 10)

      // Store the username and hashed password in the database
      const result = await pool.query(
        'INSERT INTO users(username, password) VALUES($1, $2) RETURNING *',
        [username, hashedPassword],
      )

      // If user is created successfully, return a success message
      res.status(201).json({ status: 'Created', user: result.rows[0] })
    } catch (error) {
      res.status(500).json({ status: 'Error', message: error.message })
    }
  } else {
    res.status(405).json({ status: 'Method Not Allowed' })
  }
}
```

Here, you’ll get an error message if the user already exists.

Handling password resets and email verification are much more difficult. To handle password resets, you typically need to do the following:

- Generate a unique token for the password reset request.
- Associate this token with the user in your database, and set an expiry time for it.
- Send an email to the user with a link containing this token.
- When the user clicks the link, verify the token and its expiry time.
- If the token is valid, allow the user to enter a new password.

Email verification is similar, but instead of adding a new password at the end, you’ll have a verified boolean on the user that you set to true.

We also haven’t added any ability to force stronger passwords on users. You can do that through using a library such as the validator library. The validator library provides a collection of string validation and sanitization methods, simplifying data validation tasks in the server side, client side, or even for data stored in the database:

```jsx
import bcrypt from 'bcrypt'
import validator from 'validator'
import pool from '../../utils/db'

export default async function signup(req, res) {
  if (req.method === 'POST') {
    const { username, password } = req.body

    // Validate the password
    if (
      !validator.isStrongPassword(password, {
        minLength: 8,
        minLowercase: 1,
        minUppercase: 1,
        minNumbers: 1,
        minSymbols: 1,
        returnScore: false,
      })
    ) {
      res.status(400).json({
        status: 'Error',
        message: 'Password does not meet complexity requirements',
      })
      return
    }

    try {
      const hashedPassword = await bcrypt.hash(password, 10)
      const result = await pool.query(
        'INSERT INTO users(username, password) VALUES($1, $2) RETURNING *',
        [username, hashedPassword],
      )

      res.status(201).json({ status: 'Created', user: result.rows[0] })
    } catch (error) {
      res.status(500).json({ status: 'Error', message: error.message })
    }
  } else {
    res.status(405).json({ status: 'Method Not Allowed' })
  }
}
```

Here we can set that the password must have eight characters and one uppercase letter, one lowercase, one number, and one symbol.

There is a lot to think about to just do the basics of password authentication. Don’t want to do all that?

## Using Clerk with Next.js for password authentication

Clerk allows you to quickly and easily add password [authentication to Next.js](/nextjs-authentication) and has both client and server side components.

Before we get to the code, we first want to set up our application to use email and password authentication in the Clerk dashboard. Head to your dashboard and select “Email, Phone, Username” under the “User & Authentication” menu. Make sure email is selected:

![Clerk User & Authentication Menu](./ffec29def468461c607f10f34705648584d1aaf0-2048x884.png)

You can see you can make this required and used for sign-in, which is what we want here. We can also, with a quick toggle rather than dozens of lines of JavaScript, say that we want email verification.

Then, in the same menu, find the “Authentication factors” options and select “Password.” Again here you can easily select to force the user to use a more secure password:

![Authentication Factors](./95cfa2ef5079df45e735309765f7515521d5e76e-2050x1068.png)

Now we can start with the code. Let’s create a new Next.js app:

```
npx create-next-app@latest clerk-auth
cd clerk-auth
```

Now we can install Clerk:

```
npm install @clerk/nextjs
```

Next, we want to create our environment variables for our Clerk API keys and [routes](/docs/nextjs/api-routes). Create a `.env.local file` in the root directory and add your keys and these routes (that we’re going to create in a moment):

```
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_****
CLERK_SECRET_KEY=sk_test_****
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/signin
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/signup
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/
```

With the keys and routes in place, we can add wrapper. This provides an active session and user context to Clerk’s hooks and other components. We want to wrap the entire to enable the context to be accessible anywhere within the app, so we put it in our `_app.jsx` file:

```tsx
import { ClerkProvider } from '@clerk/nextjs'
import type { AppProps } from 'next/app'

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ClerkProvider {...pageProps}>
      <Component {...pageProps} />
    </ClerkProvider>
  )
}

export default MyApp
```

We’re also going to add some middleware, which is the function that decides which pages are protected. Here, we’re going to protect everything. Add a middleware.js file to the root directory with this code:

```jsx
import { authMiddleware } from '@clerk/nextjs'

// This example protects all routes including api/trpc routes
// Please edit this to allow other routes to be public as needed.
// See https://clerk.com/docs/nextjs/middleware for more information about configuring your middleware
export default authMiddleware({})

export const config = {
  matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'],
}
```

We’ll now create our sign up and sign in pages. To create the sign up page, create a file at page/signup/\[\[…index]].jsx:

```jsx
import { SignUp } from '@clerk/nextjs'

export default function Page() {
  return <SignUp />
}
```

The \[\[…index]] syntax defines a catch-all route, so anything the user entered under signup (e.g. signup/a or signup/b) will still go to this page.

We’ll do the same for signing in, with the page at page/signin/\[\[…index]].jsx:

```jsx
import { SignIn } from '@clerk/nextjs'

export default function Page() {
  return <SignIn />
}
```

Finally, all we need is a button on the client to sign up and log in:

```jsx
// pages/index.jsx
import { UserButton } from '@clerk/nextjs'

export default function Example() {
  return (
    <>
      <header>
        <UserButton afterSignOutUrl="/" />
      </header>
      <div>Your page's content can go here.</div>
    </>
  )
}
```

Now when we `npm run dev`, we’ll get the Clerk sign in modal:

![Clerk Sign In](./c98e16686ed716b048388f304bf555a6385c2bdd-884x698.png)

As we don’t have an account, we’ll switch to the sign up option:

![Create Account](./4e24a55a569a4ec42093a1acb304f92b6a38cf2b-900x850.png)

We can then enter our email address and password. We have email verification turned on, so we have to go and click the link in our email. After that we’ll be redirected to our content:

![Next.js Content](./069e85f6ed8b8df28a28dd8fe0d7669605781392-438x140.png)

## Easier passwords in Next.js

That’s it. You now have password authentication set up with the necessary security features. Clerk offers custom [password flows](/docs/authentication/custom-flows/password) so you can design the sign in flow for your app as you want

People expect passwords on their sites. They aren’t going anywhere soon. So if you are creating a new site and want password authentication, use a well-designed library or service rather than creating your own–you and your users will be grateful.

---

# Exploring the Intricacies of OTP Authentication in Next.js
URL: https://clerk.com/blog/otp-authentication-nextjs.md
Date: 2023-07-24
Category: Guides
Description: Learn how one-time passwords work, best practices for using OTPs in authentication, and how to implement OTPs in Next.js.

Passwords aren’t great. They’re often weak, reused, and need to be stored indefinitely making them susceptible to attacks and leaks. [have i been pwned?](https://haveibeenpwned.com) tells me passwords associated with just one of my email addresses have been leaked 18 times, and I have over 800 individual passwords stored in my password manager.

This is why [magic links](/blog/magic-links), [SSO](/blog/social-sso-in-next-js), and one-time passwords (OTPs) are becoming standard authentication methods. They provide better or additional security for your users.

Here we’re going to look at OTPs. One-time passwords are a great option for improving the security of your application. Let’s go through exactly what one-time passwords are, how they can improve the security of your application, the best practices for using them in authentication, and how you can [implement OTPs in Next.js](/features/email-sms-passcodes-otp).

## What is a one-time password?

OTP or One-Time Password authentication is a method in which a unique code is sent to a user's device and the user enters this code into an application to verify their identity. It’s valid for only one login session and usually time-limited.

There are two ways OTPs are implemented:

1. As the main factor for logging in a user. If you don’t want to use any username/password combinations in your authentication flow, you can send a one-time password for log in. You can also use it as an alternative to username/password. This is not particularly common, but can be seen on sites such as local social networking site Nextdoor.
2. As an additional step in [multi-factor authentication (MFA)](/docs/custom-flows/mfa#multi-factor). After a user has logged in with their username/password or another authentication provider (such as Google, Twitter, or GitHub), they are then sent an OTP to a registered email address or phone number as a secondary layer of security for applications. This second option is much more common.

You’d think that one-time passwords would be long and complicated like the suggested passwords from a password manager. But because they are transient in nature and rarely subject to dictionary or brute force attacks, they can be much simpler. OTPs can have different formats, but they usually consist of a series of alphanumeric characters or purely numeric characters. The length of OTPs can vary, but a common format is a 6 or 8-digit numeric code.

The choice between numeric and alphanumeric OTPs depends on the context and requirements. Numeric OTPs can be easier to enter, especially on mobile devices, which makes them a popular choice for SMS-based OTPs. However, alphanumeric OTPs provide a larger possible combination set for the same number of characters, which can be more secure against brute-force attacks.

There are six main steps in the OTP flow:

![Otp Authentication Nextjs tutorial illustration](./2ba42bc94e55e995017d20204bb6ee2a763a8d8a-2000x698.png)

1. **Trigger**. The user initiates the OTP process. This could be a login attempt, a transaction verification, or any other scenario where identity needs to be confirmed.
2. **OTP generation**. The server generates an OTP. This is typically a random string or number that is time-limited.
3. **OTP delivery**. The generated OTP is sent to the user through a predetermined method. This could be an SMS to their phone, an email to their registered email address, or generated in a hardware token or software app, such as Google Authenticator.
4. **User input**. The user receives the OTP and enters it into the application.
5. **OTP verification**. The server then verifies the OTP. The server also verifies that the OTP is used within the allowed time period, and hasn't been used before.
6. **Authentication**: If the OTP is verified, the server authenticates the user and allows them to proceed. If the OTP is incorrect or expired, the server rejects the request.

Though this is only six steps, there are a lot of moving parts in OTP use. You need extra frontend UI design and logic to handle the OTP inputs; you need to integrate a delivery mechanism such as SMS, email, or an authenticator app; you need extra authentication logic to handle OTP errors; and you need the OTP generation and verification logic as well.

There are several ways to generate and verify an OTP:

- **Time-Synchronized**: In this method, the OTP is generated by applying a cryptographic hash function to a shared secret and the current time, typically measured in intervals of 30 seconds. The Google Authenticator app uses this method.
- **Counter-Based**: Here, the OTP is generated by hashing a shared secret with a counter which increments with each new OTP.
- **Algorithm-Based**: In this method, a mathematical algorithm is applied to the previous password to generate the new one.

If a time-based or counter-based OTP was used, the server repeats the same OTP generation process during verification and checks if the received OTP matches the one it generated.

These algorithms aren’t easy to implement. As you are dealing with an authentication factor, there are specific designs that you must use and RFCs that you must follow, such as this one for [Time-Based OTPs](https://datatracker.ietf.org/doc/html/rfc6238)**.** This is the biggest challenge around building your own one-time password (or any authentication) system–implementation.

## The security benefits (and challenges) of OTPs

You can quickly see the complexity involved in setting up OTP authentication. But doing so is worth it as they provide two key security benefits.

### Risk mitigation

The mitigation of risk with OTPs comes from two different avenues.

The first is mitigating the risk associated with static passwords. Traditional static passwords, if stolen, provide ongoing access until they are changed. OTPs are dynamic and expire after a single use or after a short period of time, limiting the potential damage if they are intercepted or stolen. Another problem is users reusing the same password across multiple services. If one service is compromised, all accounts using the same password are at risk. OTPs eliminate this risk because they are unique for each login session.

The second is the reduction of attack vectors. Because OTPs are typically time-limited, it makes brute-force attacks infeasible. An attacker doesn't have the time to try all possible combinations before the password expires. They also help with phishing. Even if a user is tricked into entering their OTP into a phishing site, the attacker can't reuse that OTP to gain future access to the account.

Additionally, since an OTP is valid for only one login session or transaction, it cannot be reused, preventing replay attacks. In a replay attack, an attacker tries to reuse a password that was intercepted in a previous session. However, if there's a flaw in the system's design where the OTP doesn't expire immediately after use or isn't time-bound, there's a possibility for replay attacks.

### Identity security and verification

OTPs also play a significant role in enhancing identity security and verification processes. They provide an additional layer of protection beyond traditional static passwords, aiding in the confirmation of a user's identity in several ways:

- OTPs are often used as part of a two-factor authentication process. In addition to a traditional username and password (something the user knows), the user must enter an OTP (something the user has, typically their mobile device). This confirms that the user has access to a specific device (like a phone) that is associated with the account, verifying the identity of the user.
- OTPs are commonly used in financial transactions or account changes to verify the identity of the user making the transaction. For example, when conducting a bank transfer or changing account details, an OTP might be sent to the registered mobile number or email address. The user enters the OTP to confirm the transaction, verifying that they are the account holder.
- OTPs are often used in password recovery processes to verify the user's identity. The service sends an OTP to the user's registered email address or mobile number, which the user then enters to verify their identity and proceed with resetting their password.
- When a user logs in from a new device, an OTP might be sent to their registered contact information. The user must enter the OTP to verify they have access to the registered device, confirming their identity and that the new device is trusted.

By integrating OTPs into authentication and verification processes, services can add an extra level of security and significantly reduce the risk of unauthorized access or identity theft.

## Best practices for using one-time passwords

OTPs aren’t infallible, though. But the associated risks are generally around poor implementation rather than inherent to the method. To ensure OTP effectiveness and avoid some of the above potential vulnerabilities, you can follow some best practices.

### Basic security practices

These practices are the principles of any good system:

- **Secure delivery channel**. Use a secure delivery channel for sending the OTP. If you're sending the OTP via email or SMS, ensure the communication channel is secure.
- **Encrypt communication**. Ensure all communications between the client and the server are done over HTTPS to prevent any interception of the OTP.
- **Use secure storage**. When storing OTPs on the server side, consider hashing them. This ensures that even if someone gains access to your storage, they cannot obtain the actual OTPs.

### Good OTP design

These relate to how well you design your OTP algorithm and logic:

- **Use a strong OTP**. Use an OTP that is long and complex enough to resist brute-force attacks. An OTP with at least 6 digits is usually recommended.
- **Time-Bound OTP**. Make sure the OTP is valid only for a short period of time. This reduces the window an attacker has to use a stolen OTP. Usually, OTPs are valid for about 2-10 minutes.
- **Limit OTP attempts**. Implement rate limiting on your OTP endpoints to protect against brute force attacks. After a certain number of incorrect attempts, either block the user or implement a cool-down period.
- **Expiry after use.** The OTP should expire immediately after it has been used once, to prevent replay attacks.

### Good UX

These help users use your OTP and make sure they don’t turn it off:

- **Backup codes**. For applications using OTP as a second factor, provide backup codes that the user can write down and use if they lose access to their OTP delivery method (like losing their phone).
- **Fallback Options**. In case the primary delivery channel fails (e.g., SMS not being delivered), have a secondary option like email or voice call.

Also consider educating users about using OTPs. One of the main threats to OTP use are physical–if an attacker steals a user's phone then they’ll have access to the SMS or email used with OTPs. Or a fraudster can fake a user’s identity to trick a telecoms company into assigning a new SIM with the user’s phone number to them (known as [SIM swapping](https://en.wikipedia.org/wiki/SIM_swap_scam)).

While OTPs can greatly enhance security, they are not foolproof. Implementation within a broader security strategy is key.

## Setting up OTP Authentication in Next.js

Let’s walk through setting up a one time password system within Next.js. If you already have a Next.js app up and running you can add this code directly. Otherwise create a new app using:

```sh
npx create-next-app@latest
```

We’ll also need to use a few modules to help us with our OTPs, namely:

- [**Twilio**](http://twilio.com). Twilio allows us to send SMS messages programmatically. Here we’re going to use it to send the OTP to the user's phone number via SMS.
- [**bcryptjs**](https://www.npmjs.com/package/bcryptjs). bcryptjs is a JavaScript library for hashing and comparing passwords. We’re going to use it to hash the OTP before storing it in the database for added security.
- [**MongoDB**](https://www.mongodb.com). MongoDB is a NoSQL database that we’ll use to store hashed OTPs along with the associated phone numbers and expiry times.
- [**Upstash**](http://upstash.com). Upstash is a serverless data platform. We’re going to use it’s rate limiter and Redis functionality.

Install these with:

```sh
npm install twilio bcryptjs mongodb @upstash/ratelimit @upstash/redis
```

For Twilio and MongoDB, you’ll also need to sign up for accounts and then need your `TWILIO_ACCOUNT_SID`, your `TWILIO_AUTH_TOKEN`, and your `MONGODB_URI`. For Twilio, you’ll also need to buy a `TWILIO_PHONE_NUMBER` that will be used to send your SMS messages.

You’ll also need an account with Upstash, and then your `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN` variables.

With that done, we’ll first create the API route that will generate our OTP:

```javascript
// pages/api/generateOTP.js
import crypto from 'crypto'
import twilio from 'twilio'
import bcrypt from 'bcryptjs'
import { MongoClient } from 'mongodb'

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).end() // Method Not Allowed
  }

  // Generate a six digit number using the crypto module
  const otp = crypto.randomInt(100000, 999999)

  // Hash the OTP
  const hashedOtp = await bcrypt.hash(otp.toString(), 10)

  // Initialize the Twilio client
  const client = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN)

  try {
    // Send the OTP via SMS
    await client.messages.create({
      body: `Your OTP is: ${otp}`,
      from: process.env.TWILIO_PHONE_NUMBER, // your Twilio number
      to: req.body.phone, // your user's phone number
    })

    // Store the hashed OTP in the database along with the phone number and expiry time
    const mongoClient = new MongoClient(process.env.MONGODB_URI)
    await mongoClient.connect()
    const otps = mongoClient.db().collection('otps')
    await otps.insertOne({
      phone: req.body.phone,
      otp: hashedOtp,
      expiry: Date.now() + 10 * 60 * 1000, // OTP expires after 10 minutes
    })
    await mongoClient.close()

    // Respond with a success status
    res.status(200).json({ success: true })
  } catch (err) {
    console.error(err)
    res.status(500).json({ error: 'Could not send OTP' })
  }
}
```

With this code we initially import all our dependencies, then create a handler function for our POST endpoint. The body of the POST request will contain the phone number of the user that we’ll get from the frontend. Within the endpoint, we’re doing a few things:

- Creating a six-digit random OTP
- Hashing that OTP with `bcryptjs` for storage
- Creating a Twilio client and then sending the OTP to the user’s phone number
- Creating a MongoDB client and storing the OTP along with the user’s phone number and an expiry time for the password.

Is this best practice? Absolutely not. We are doing a few things right, such as setting an expiry time on the OTP and hashing them. But our OTP generating ‘algorithm’ is laughably simple.

Let’s quickly create a frontend for this now:

```jsx
import { useState } from 'react'

const OTPGenerator = () => {
  const [phone, setPhone] = useState('')
  const [otp, setOTP] = useState('')
  const [isLoading, setIsLoading] = useState(false)
  const [message, setMessage] = useState('')
  const [otpSent, setOtpSent] = useState(false)

  const handleSendOTP = async (event) => {
    event.preventDefault()
    setIsLoading(true)
    setMessage('') // reset message

    try {
      const response = await fetch('/api/generateOTP', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ phone }),
      })

      if (response.ok) {
        setMessage('OTP has been sent to your phone.')
        setOtpSent(true)
      } else {
        const data = await response.json()
        setMessage(data.error)
      }
    } catch (error) {
      setMessage('An error occurred. Please try again.')
      console.error(error)
    } finally {
      setIsLoading(false)
    }
  }

  const handleVerifyOTP = async (event) => {
    event.preventDefault()
    setIsLoading(true)
    setMessage('') // reset message

    try {
      const response = await fetch('/api/verifyOTP', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ phone, otp }),
      })

      if (response.ok) {
        setMessage('OTP verification successful!')
        setOtpSent(false)
        setPhone('')
        setOTP('')
      } else {
        const data = await response.json()
        setMessage(data.error)
      }
    } catch (error) {
      setMessage(error)
      console.error(error)
    } finally {
      setIsLoading(false)
    }
  }

  return (
    <div>
      {!otpSent ? (
        <form onSubmit={handleSendOTP}>
          <label>
            Phone Number:
            <input type="tel" value={phone} onChange={(e) => setPhone(e.target.value)} required />
          </label>
          <button type="submit" disabled={isLoading}>
            {isLoading ? 'Sending...' : 'Send OTP'}
          </button>
        </form>
      ) : (
        <form onSubmit={handleVerifyOTP}>
          <label>
            Enter OTP:
            <input type="text" value={otp} onChange={(e) => setOTP(e.target.value)} required />
          </label>
          <button type="submit" disabled={isLoading}>
            {isLoading ? 'Verifying...' : 'Verify OTP'}
          </button>
        </form>
      )}
      {message && <p>{message}</p>}
    </div>
  )
}

export default OTPGenerator
```

All this code will just show a single form on the page. On first load this form will ask for the user’s phone number.

![Otp Authentication Nextjs tutorial illustration](./1633315883a8a1ff7d1274d4cb1f3174f28be50d-2000x206.png)

When the user enters their phone number and hits submit, the above generateOTP endpoint will be called. This will send the OTP to the user’s phone number:

![Otp Authentication Nextjs tutorial illustration](./4f315b984011eab37c084d6add0805fb54c63bf5-2000x346.jpg)

Hitting submit will also change the form to accept the OTP as the input. The user can then check their phone and enter the six-digit code: and hit submit again to send the OTP and phone number to a verifyOTP endpoint for verification:

```javascript
// pages/api/verifyOTP.js
import bcrypt from 'bcryptjs'
import { MongoClient } from 'mongodb'
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'

const rateLimiter = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(2, '3 s'),
})

export default async function handler(req, res) {
  const user_ip = req.headers['x-forwarded-for']
  const { success } = await rateLimiter.limit(user_ip)

  if (!success) {
    return res.status(429).json({ error: 'Too Many Requests' })
  }

  if (req.method !== 'POST') {
    return res.status(405).end() // Method Not Allowed
  }

  const mongoClient = new MongoClient(process.env.MONGODB_URI)
  await mongoClient.connect()
  const otps = mongoClient.db().collection('otps')

  try {
    // Fetch the OTP record from the database
    const otpRecord = await otps.findOne({ phone: req.body.phone })

    if (!otpRecord) {
      return res.status(400).json({ error: 'Invalid phone number or OTP' })
    }

    // Check if the OTP has expired
    if (Date.now() > otpRecord.expiry) {
      return res.status(400).json({ error: 'OTP has expired' })
    }

    // Check if the OTPs match
    const otpMatch = await bcrypt.compare(req.body.otp.toString(), otpRecord.otp)
    if (!otpMatch) {
      return res.status(400).json({ error: 'Invalid phone number or OTP' })
    }

    // OTP is valid and has not expired, so we can delete it now
    await otps.deleteOne({ phone: req.body.phone })

    // Respond with a success status
    res.status(200).json({ success: true })
  } catch (err) {
    console.error(err)
    res.status(500).json({ error: 'Could not verify OTP' })
  } finally {
    await mongoClient.close()
  }
}
```

When called, this API loads the OTP MongoDB database and finds the one associated with the phone number. It checks whether it has expired, and if not, matches the hashed OTPs. If it's valid, the OTP gets deleted from the database and a 200 code is returned to the frontend.

![Otp Authentication Nextjs tutorial illustration](./fa2cf32dae69b1db97696e978df995bce600e361-2000x374.png)

We could then work that response into any other authentication flow we had set up. We also have a basic rate limiter set into that will make sure a user can’t input more than 2 codes in 3 seconds, to try and prevent brute force attacks:

![Otp Authentication Nextjs tutorial illustration](./326e38b1b19e83387e3cfaac1381657ba7c43bda-2000x438.png)

And that’s it. You have one-time passwords working in Next.js.

## OTPs are intricate but worth implementing

This code gives you a one-time password option for [Next.js authentication](/nextjs-authentication). But we’ve only scratched the surface. We haven’t implemented this within any other authentication flow–this just generates, sends, and verifies the OTP, it doesn’t use it to authenticate the user.

We’ve also generated the OTP in the most basic manner, not following the RFCs and guidelines. We do have some nice best practices–rate-limiting, time-bounding, and expiry–but again these are all basic implementations. We also had to buy a new phone number!

This is the intricacy of OTPs. They are easy to set up, but difficult to get right. Like most authentication methods, it is better to use a provider than trying to create your own. Check out Clerk’s [OTP solution here](/docs/custom-flows/email-sms-otp#email-sms-otp) to have these intricacies taken care of for you.

---

# Build a Cookie Clicker App with Clerk and Hasura
URL: https://clerk.com/blog/build-a-cookie-clicker-app-with-clerk-and-hasura.md
Date: 2023-07-23
Category: Guides
Description: In this tutorial we will use Clerk with Hasura to build a full-stack Next.js app with a database and GraphQL API, all without having to write any backend code.

[Hasura](https://hasura.io) provides a GraphQL engine that can help you build real-time APIs and ship modern apps faster. Although Hasura itself does not handle authentication, you can bring your own auth server and integrate it with Hasura via JWTs. This is where [Clerk](/) fits in.

In this tutorial we will use Clerk with Hasura to build a full-stack Next.js app with a database and GraphQL API, all without having to write any backend code.

> If you would like to skip ahead and see the completed codebase, browse to the repo [here](https://github.com/clerkinc/more-cookies-please).

## Assumptions

This tutorial makes the following assumptions:

- Basic command line usage
- Node.js installed and `npm` (or `yarn` if you prefer) for package management
- Experience with React components and hooks
- Familiarity with the Next.js application structure (created with `create-next-app`)
- Comfortable running Docker Compose commands (alternative path is to use Hasura Cloud)
- [Clerk](https://dashboard.clerk.com/sign-in) and [Hasura](https://cloud.hasura.io/login) accounts already set up (if you haven’t done so, do it now\... we’ll wait)

## Set up Clerk project

We’re going to start off with creating a new project from the Clerk dashboard. I’m going to name this application “More Cookies Please” (you’ll see why shortly) and leave the default options selected for authentication strategy and turn on social login with Google.

![Build A Cookie Clicker App With Clerk And Hasura guide illustration](./deb49deb5a617c0b5dc625a4c03525a1c4110354-1176x1514.png)

The next thing we need to do is navigate to JWT Templates from the left menu and create a template based on Hasura.

![Hasura template](./c32bdcf8bc58e5c2e8787e5f5cfbc32d7fd2b352-1636x1000.png)

The next thing we need to do is navigate to JWT Templates from the left menu and create a template based on Hasura.

![Hasura token claims](./460f05efd18bcbfa6120d6c2296969b088c000e0-2072x1360.png)

Click the “Apply changes” button and navigate back to the Home dashboard. Here we’re going to copy the Frontend API key.

![Frontend API key](./848ed7537b737ab642164c7df56400766316b770-2050x506.png)

That’s all we need to do in the Clerk dashboard.

## Clone the starter repo

Now it’s time to clone the [clerk-hasura-starter](https://github.com/clerkinc/clerk-hasura-starter) repo from GitHub. Name this project directory `more-cookies-please` to match the Clerk instance name.

```bash
git clone https://github.com/clerkinc/clerk-hasura-starter.git more-cookies-please
```

Once you have the repository downloaded to your computer, run the following commands to change into the directory, install the package dependencies, and copy the `.env.local.sample` so we can set a couple environment variables:

```bash
cd more-cookies-please/
npm install
cp .env.local.sample .env.local
```

Add in the Frontend API key from Clerk that was copied earlier. We’re also going to set the GraphQL endpoint even though it hasn’t been created yet.

```bash
NEXT_PUBLIC_CLERK_FRONTEND_API=<YOUR_FRONTEND_API>
NEXT_PUBLIC_HASURA_GRAPHQL_API=http://localhost:8080/v1/graphql
```

**Note**: `CLERK_API_KEY` is available in the sample but isn’t needed for this tutorial.

Once those environment variables are set, start up the application with `npm run dev`

Open your web browser to [http://localhost:3000](http://localhost:3000) and you should see the starter application homepage, which prompts you to sign up. So now let’s sign up for an account.

Click the Sign up button and you will be redirected to a Sign Up form generated for your application with Clerk components. I’m going to choose **Sign up with Google** since it's the fastest (and doesn’t require a new password).

Once you’ve signed up and logged in, you should see the following screen:

![App welcome](./2586548dde72a7d28cd9ea95d1a9d5b9ffedd8ae-2276x1666.png)

Now it’s time to customize this application. We’re going to install a little package I created based on the excellent [react-rewards](https://github.com/thedevelobear/react-rewards) library and inspired by [Cookie Clicker](https://en.wikipedia.org/wiki/Cookie_Clicker) (thank [@bsinthewild](https://twitter.com/bsinthewild) for reminding me of this).

```bash
npm install react-cookie-clicker
```

**Note**: ⚠️ You will see some warnings about conflicting peer dependencies due to a mismatch of React versions, but it’s safe to proceed.

We’re going to create a new file called `MoreCookies.js` inside of the `components/` folder.

Because this library does not support server-side rendering (SSR), we need to make use of the [dynamic imports from Next.js](https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr) or we’ll get some nasty errors.

```jsx
import dynamic from 'next/dynamic'
const CookieClicker = dynamic(() => import('react-cookie-clicker'), {
  ssr: false,
})

const MoreCookies = () => {
  return (
    <div style={{ marginTop: 150 }}>
      <CookieClicker />
      <h2>Click the cookie</h2>
    </div>
  )
}

export default MoreCookies
```

Now let’s add the component to `pages/index.js`:

```jsx
import styles from '../styles/Home.module.css'
import Link from 'next/link'
import { SignedIn, SignedOut } from '@clerk/nextjs'
import MoreCookies from '../components/MoreCookies'

const SignupLink = () => (
  <Link href="/sign-up">
    <a className={styles.cardContent}>
      <img src="/icons/user-plus.svg" alt="Clone the starter repo illustration" />
      <div>
        <h3>Sign up for an account</h3>
        <p>Sign up and sign in to explore all the features provided by Clerk out-of-the-box</p>
      </div>
      <div className={styles.arrow}>
        <img src="/icons/arrow-right.svg" alt="Clone the starter repo illustration" />
      </div>
    </a>
  </Link>
)

const Main = () => (
  <main className={styles.main}>
    <SignedOut>
      <h1 className={styles.title}>Welcome to your new app</h1>
      <p className={styles.description}>Sign up for an account to get started</p>
      <div className={styles.cards}>
        <div className={styles.card}>
          <SignupLink />
        </div>
      </div>
    </SignedOut>
    <SignedIn>
      <MoreCookies />
    </SignedIn>
  </main>
)
```

The `ClerkFeatures` component can be removed, but the `Footer` and `Home` components should remain untouched.

You can see here we are making use of the `SignedIn` and `SignedOut` components from Clerk. We can also finally see the big cookie button!

Go ahead and click it for a nice reward. You’ve earned it. 🍪

![Cookie button](./a99cf1d2ef740351be1972ded05a878652b92a3a-1686x1206.png)

## Set up Hasura GraphQL engine

Clicking the cookie is a lot of fun, but what is even more fun? Keeping count of all those clicks!

This is where the Hasura GraphQL integration comes in.

There are two different ways we can connect to Hasura: we can use Hasura Cloud or Hasura Core running from a Docker container. We’re going to do the latter for this tutorial, but you can see instructions for connecting with Hasura Cloud in our [integration documentation](/docs/integrations/databases/hasura).

The starter repo already contains the `docker-compose.yml` file we need.

The only part we need to update here is the JWT secret. Uncomment the line for `HASURA_GRAPHQL_JWT_SECRET` and add in the value for your Clerk Frontend API. The JWT URL path points to the JSON Web Key Set (JWKS) endpoint we have set up for your application.

```yaml
HASURA_GRAPHQL_JWT_SECRET: '{"jwk_url":"https://<YOUR_FRONTEND_API>/.well-known/jwks.json"}'
```

**Note**: Make sure the **https\://** protocol is included in the URL in front of the Frontend API.

Once the JWT secret is set, run the following command:

```bash
docker compose up -d
```

This will spin up Docker services for GraphQL engine as well as a Postgres database.

You can confirm that the services are running correctly with the following:

```bash
docker compose ps
```

If all is good, you should see output similar to:

```bash
COMMAND                  SERVICE           STATUS        PORTS
"graphql-engine serve"   graphql-engine    running       0.0.0.0:8080->8080/tcp
"docker-entrypoint.s…"   postgres          running       5432/tcp
```

Head to [http://localhost:8080/console](http://localhost:8080/console) to open the Hasura console.

![Hasura GraphiQL console](./24485ecee44a1614483815c81820affa357376d0-2544x1670.png)

Hasura has already done the work of setting up a GraphQL endpoint for us and also provided the GraphiQL integrated development environment (IDE) to explore the API.

It’s time to set up the database to keep the score count.

Navigate to the **Data** page and fill out the form to Connect Existing Database. (Remember we have the Postgres one running from Docker Compose?)

![Connect database](./c8140b09ad7a9a761bb9633a079b5c8c85f260cd-1668x1430.png)

Name the database `default` (or something more clever) and input the database URL copied from the `docker-compose.yml` file. Click connect and the data source will be added.

The next step is to create the database table named `scoreboard` and add two fields:

1. `user_id` is a Text field that will contain the user ID from Clerk
2. `count` is an Integer field that will keep track of the click count

![Add new table](./a8236a9c8daf4eff6717e6055e3fd52feec692df-2244x1324.png)

Set the `user_id` as the **Primary Key** for the table. Then click the Add Table button.

The next thing we need to do is set permissions for the “user” role. Click on the **Permissions** tab and enter `user` as a new role. Then we need to set the basic **CRUD** (Create, Read, Update, Delete) operations on the table.

### Insert (Create)

For **Insert** permissions, set the following values:

- **Row insert permissions**: Without any checks
- **Column insert permissions**: `count` checked
- **Column presets**: `user_id` from session variable `X-Hasura-User-Id`

![Insert permissions](./6f63cdd947fd37c6bd707ac93579f28b074f031d-1966x1300.png)

With the Clerk integration, the user ID will be set as the session variable and Hasura will then set that as the `user_id` column when the request is made.

### Select (Read)

For **Select** permissions, set the following values:

- **Row select permissions**: With custom check `{"user_id":{"_eq":"X-Hasura-User-Id"}}`
- **Column select permissions**: `count` and `user_id` checked

![Select permissions](./0cfbbb9668e9a9d95c05b6c457301f30136977d2-1966x1412.png)

The custom check ensures only the current authenticated user can read their own count. If the user ID from the session variable matches the one from the table, the user is granted read permission to every column in their database row.

### Update

For Update permissions, set the following values:

- **Pre-update check**: With same check as select `{"user_id":{"_eq":"X-Hasura-User-Id"}}`
- **Column update permissions**: `count` checked

![Update permissions](./23862bf8f3bbffaef05ad5d6f9d239f2a2efd5fc-1958x1464.png)

Having the same custom check prevents another authenticated user from updating someone else’s count.

### Delete

We can skip over **Delete** permissions since we aren’t implementing a mechanism to delete user records from the scoreboard.

Your final permissions access chart should look like the following:

![Permissions chart](./b4cfa610c9a9316934c6ea992f1e6c9973009aad-1744x920.png)

## Configure the client

Now it’s time to make authenticated requests from the codebase to Hasura.

If you take a look at `hooks/index.js`, you can see the `useQuery` hook that has been set up. It makes use of [graphql-request](https://github.com/prisma-labs/graphql-request), a minimal GraphQL client, with the [useSWR](https://swr.vercel.app) hook to perform query requests to the GraphQL endpoint.

```jsx
import { request } from 'graphql-request'
import { useAuth } from '@clerk/nextjs'
import useSWR from 'swr'

export const useQuery = (query, variables, blockRequest) => {
  if (!query) {
    throw Error('No query provided to `useQuery`')
  }
  const { getToken } = useAuth()
  const endpoint = process.env.NEXT_PUBLIC_HASURA_GRAPHQL_API
  const fetcher = async () =>
    request(endpoint, query, variables, {
      authorization: `Bearer ${await getToken({ template: 'hasura' })}`,
    })

  return useSWR(query, blockRequest ? () => {} : fetcher)
}
```

What we’re doing is reading the custom JWT (from the template we named `hasura`) from the session object provided by Clerk. Note that the call to `getToken` is asynchronous and returns a Promise that needs to be resolved before accessing the value.

We pass the custom fetcher function, which accepts a GraphQL query and optional variables, to `useSWR`. The `blockRequest` parameter is something we’ll make use of later to prevent certain calls from happening.

Let’s try this out to make sure we can get some data. Open up `components/MoreCookies.js` and import the `useQuery` hook and log the `data` to the console:

```jsx
import dynamic from 'next/dynamic'
import { useQuery } from '../hooks'
const CookieClicker = dynamic(() => import('react-cookie-clicker'), {
  ssr: false,
})

const MoreCookies = () => {
  const { data } = useQuery(`query { scoreboard { count } }`)
  console.log('data >>', data)

  return (
    <div style={{ marginTop: 150 }}>
      <CookieClicker />
      <h2>Click the cookie</h2>
    </div>
  )
}

export default MoreCookies
```

If all went well, you should see the following:

```jsx
data >> undefined
data >> { scoreboard: Array(0) }
```

The data is `undefined` at first but then gets populated. `scoreboard` is an empty Array because we haven’t recorded any click counts yet. So let’s do that now.

In order to make the GraphQL mutation we’re going to create another custom hook in `hooks/index.js`:

```jsx
export const useCountMutation = (count, data) => {
  const prevCount = data?.scoreboard[0]?.count ?? 0
  const blockRequest = count < 1 || prevCount === count

  // Block mutation if count is less than 1 or equal to previous value
  return useQuery(
    `mutation {
      insert_scoreboard_one(
        object: { count: ${count} },
        on_conflict: { constraint: scoreboard_pkey, update_columns: count }) {
        count
        user_id
      }
  }`,
    null,
    blockRequest,
  )
}
```

This hook accepts the `count` as the first parameter and the `data` object containing previous data as the second parameter. It makes use of the `useQuery` hook to apply the `insert_scoreboard_one` insert mutation as an [upsert](https://hasura.io/docs/2.0/mutations/postgres/upsert). Instead of adding multiple rows to the database table, the `on_conflict` argument sets a constraint on the primary key (`user_id`) and if it already exists, only the `count` column will be updated. Both `count` and `user_id` values are returned from a successful mutation.

If we replace the `useQuery` with `useCountMutation` in the `MoreCookies` component, we can give us some credit for those clicks we’ve already made. (I set mine at `10` but you can be more or less generous.)

```jsx
import dynamic from 'next/dynamic'
import { useCountMutation } from '../hooks'
const CookieClicker = dynamic(() => import('react-cookie-clicker'), {
  ssr: false,
})

const MoreCookies = () => {
  const { data } = useCountMutation(10)
  console.log('data >>', data)

  return (
    <div style={{ marginTop: 150 }}>
      <CookieClicker />
      <h2>Click the cookie</h2>
    </div>
  )
}

export default MoreCookies
```

If you look at the browser console, you should now see something like:

```
data >> { insert_scoreboard_one: { count: 10, user_id: 'user_29IqLFGiidcpkwqplE1F8C8EnD1' } }
```

You can confirm that this made it into the Postgres database by going to the **Data** tab in the Hasura Console and clicking into **scoreboard** and **Browse Rows**:

![Browse rows](./31968443a55bf5e2b2d0bced0969311a221cc0d9-1940x924.png)

Success! The count (fake or not) has made it into the database and is associated with the authenticated user.

So now that everything is working as intended, we can go ahead and connect it all together. We’ll add one more custom hook that performs both the initial `useQuery` and the `useCountMutation`. This is going to need both `useState` and `useEffect` from React so make sure you import those.

```jsx
export const useScoreboard = () => {
  const [count, setCount] = useState(0)
  const { data } = useQuery(`query {
    scoreboard { count, user_id }
  }`)
  const increment = () => {
    setCount(count + 1)
  }

  // Perform mutation on count
  useCountMutation(count, data)

  useEffect(() => {
    if (!count && data?.scoreboard[0]) {
      // Set initial count from database
      setCount(data.scoreboard[0].count)
    }
  }, [count, data])

  return [count, increment]
}
```

It returns the current `count` as well as an `increment` function, both of which we can pass as props to the `<CookieClicker />` component.

```jsx
import dynamic from 'next/dynamic'
import { useScoreboard } from '../hooks'
const CookieClicker = dynamic(() => import('react-cookie-clicker'), {
  ssr: false,
})

const MoreCookies = () => {
  const [count, increment] = useScoreboard()

  return (
    <div style={{ marginTop: 150 }}>
      <CookieClicker count={count} onClick={increment} />
      <h2>Click the cookie</h2>
      <p>Current count: {count}</p>
    </div>
  )
}

export default MoreCookies
```

By setting the `count` and `onClick` props on `CookieClicker`, it will now reward you with cookies based on the number of times the button is clicked. Keep clicking for more cookies!

![Build A Cookie Clicker App With Clerk And Hasura guide illustration](./276b94611d06d56484ba13d0b5cdb9b803964b0a-1526x1265.jpg)

## Closing thoughts

Hope you had fun building this. You now have a complete Cookie Clicker app built using Clerk, Hasura, and Next.js — with no backend code required! To take it even further, you could implement an actual scoreboard that keeps track of all the cookie clicks from multiple users. Then [deploy this app to production](/docs/deployments/overview), share it with your friends, and see how much idle time they have on their hands. 😆

If you enjoyed this tutorial or have any questions, feel free to reach out to me ([@devchampian](https://x.com/devchampian)) on X, follow [@clerk](https://x.com/clerk), or join our [Discord community](https://clerk.com/discord) to connect with other developers. Happy coding!

---

# RedwoodJS Blog Tutorial with Clerk
URL: https://clerk.com/blog/redwoodjs-blog-tutorial-with-clerk.md
Date: 2023-07-23
Category: Guides
Description: Branching off from the excellent (and mighty) Redwood tutorial, the guide will lead you through setting up Clerk as the authentication provider.

> \[!WARNING]
> As of April 4, 2025, RedwoodJS is no longer actively developed. [Learn more](https://community.redwoodjs.com/t/the-future-of-redwood-launches-today/7938).

Branching off from the excellent (and mighty) Redwood tutorial, the guide will lead you through setting up Clerk as the authentication provider. You can think of Clerk as the ranger of the forest, only allowing verified users pass through the secluded parts of your app. (Be prepared for tree puns ahead — you’ve been warned! 🌲)

## Assumptions

This tutorial makes the following assumptions:

- Basic command line usage
- Node.js installed with both `npm` and `yarn` (required by Redwood)
- Experience with React components and hooks
- Have gone through the first part of the [Redwood tutorial](https://learn.redwoodjs.com/docs/tutorial/welcome-to-redwood)
- [Clerk](https://dashboard.clerk.com/sign-in) account already set up (if you haven’t done so, do it now\... we’ll wait)

> If you would like to skip ahead and see the completed codebase, browse to the repo [here](https://github.com/clerkinc/redwood-tutorial-with-clerk).

## Getting started

This journey begins with cloning the [example repo](https://github.com/redwoodjs/redwood-tutorial) that Redwood has set up.

```bash
git clone https://github.com/redwoodjs/redwood-tutorial.git redwood-tutorial-with-clerk
```

Follow their instructions to run the following commands:

```bash
cd redwood-tutorial-with-clerk/
yarn install
yarn rw prisma migrate dev
yarn rw dev
```

**Note**: If the `rw` (short for `redwood`) command isn’t working, make sure you have the proper versions of [Node.js and Yarn](https://learn.redwoodjs.com/docs/tutorial/prerequisites#nodejs-and-yarn-versions) installed.

If all went well, you should be looking at the most beautiful blog you’ve ever seen...

![Redwood blog](./2733571d4e74adab3f76818c54be7968d468dd9c-2348x1372.png)

If you try to navigate to [http://localhost:8910/admin/posts](http://localhost:8910/admin/posts) you will be redirected back to the homepage. This is due to the `<Private unauthenticated="home">` wrapper around the admin routes that was already set up.

## Set up Clerk authentication

As part of the [Authentication chapter](https://learn-redwood.netlify.app/docs/tutorial/authentication) of the Redwood tutorial, they went through the setup of their built-in database-backed authentication system called dbAuth. (Can’t blame them for planting those seeds.)

To transplant Clerk as the new authentication provider, first, navigate to your [Clerk dashboard](https://dashboard.clerk.com) and create a new application. Give your application any name you’d like, leave the default authentication strategy selected, and then choose a social login provider if you would like. (Google OAuth is pretty fast and doesn’t make you create a new password.)

![Redwoodjs Blog Tutorial With Clerk guide illustration](./079ce27b85ebf6511a2a2f55d090c87dcf4cafd0-1174x1352.png)

Once the application has been created and the confetti clears, scroll down to the **Connect your application** section to grab your API keys.

Back in the codebase, create a new `.env` file in the project directory and set the following environment variables to the respective values from your Clerk dashboard:

```bash
CLERK_API_KEY=<YOUR_BACKEND_API_KEY>
CLERK_FRONTEND_API_URL=<YOUR_FRONTEND_API_KEY>
```

Once you have the environment variables set, the next step is to root out the existing auth logic. The quickest way to do this is to run:

```bash
yarn rw setup auth clerk --force
```

Note: If you’re into the more labor-intensive, manual way of doing things, [here are the instructions](https://redwoodjs.com/docs/authentication#clerk) for you. (Chainsaws not required.)

You should see terminal output similar to the following:

```bash
✔ Overwrite existing /api/src/lib/auth.[jt]s? … yes
  ✔ Generating auth lib...
    ✔ Successfully wrote file `./api/src/lib/auth.js`
  ✔ Adding auth config to web...
  ✔ Adding auth config to GraphQL API...
  ✔ Adding required web packages...
  ✔ Adding required api packages...
  ✔ Installing packages...
  ✔ One more thing...

You will need to add two environment variables with your Clerk URL and API key.
Check out web/src/App.{js,tsx} for the variables you need to add.
See also: https://redwoodjs.com/docs/authentication#clerk
```

If you already followed the instructions to add your environment variables, great job! If you didn’t, please add them now.

In your code editor of choice, open up `web/src/App.js`

Wrap the Redwood `<AuthProvider />` component with `<ClerkAuthProvider />` and replace the prop `type="dbAuth"` with `type="clerk"`:

```jsx
const App = () => (
  <FatalErrorBoundary page={FatalErrorPage}>
    <RedwoodProvider titleTemplate="%PageTitle | %AppTitle">
      <ClerkAuthProvider>
        <AuthProvider type="clerk">
          <RedwoodApolloProvider>
            <Routes />
          </RedwoodApolloProvider>
        </AuthProvider>
      </ClerkAuthProvider>
    </RedwoodProvider>
  </FatalErrorBoundary>
)
```

## Add Clerk components

Now that Clerk is set up, restart the dev server with `yarn rw dev`. If you had the dev server running, it needs to be restarted to read the newly added environment variables.

Open the `web/src/layouts/BlogLayout/BlogLayout.js` component in your code editor and add the following imports:

```jsx
import { SignInButton, UserButton } from '@clerk/clerk-react'
```

While the `login` and `logOut` methods from the Redwood `useAuth()` hook will work, Clerk provides nice UI components to accomplish the same thing. Remove the `logIn` and `logOut` methods and replace the last navigation list item with the following code:

```jsx
<li className={isAuthenticated ? 'ml-2' : null}>
  {isAuthenticated ? (
    <UserButton afterSignOutAll={window.location.href} />
  ) : (
    <SignInButton mode="modal">
      <button className="rounded px-4 py-2 transition duration-100 hover:bg-blue-600">
        Log in
      </button>
    </SignInButton>
  )}
</li>
```

**Note**: The `afterSignOutAll` prop needs to be set to the current URL when using Clerk Hosted Pages to redirect back to your app.

Making use of the `isAuthenticated` property checks if there is an active user session. If there isn’t one, the Clerk `<SignInButton />` component renders a custom button element matching the blog styles. Clicking “Log in”, opens a modal window allowing you to sign in with Google or sign up with an email and password.

![Clerk sign in modal](./1a05816face419ca2799bb6268f42d82c5ea0824-2348x1366.png)

After signing in, you should see the `<UserProfile />` component with an avatar.

If you look in the code right underneath the navigation, there is a conditionally rendered text block for `currentUser.email`. This doesn’t render anything because the Clerk user object is structured a little differently. To display the current user’s email address, make the following tweaks:

```jsx
{
  isAuthenticated && (
    <div className="text-right text-xs text-blue-300">
      {currentUser?.emailAddresses[0]?.emailAddress}
    </div>
  )
}
```

This reads the primary email address property and removes the absolute positioning styles.

The navigation header should now look similar to:

![Navigation header](./c013386659d283218c0ea71a36cc353597168e6b-1778x166.png)

(Displaying your own account of course.)

Clerk makes it super easy to add in these authentication components. There are more options for customization available as well.

Now that you have an authenticated user, you should be able to safely navigate to [http://localhost:8910/admin/posts](http://localhost:8910/admin/posts) and manage the blog posts.

That’s really all there is to it.

## Going deeper

If you’d like to go deeper into the forest (really stretching this metaphor here), you could try your hand at the following:

- Update the Login and Sign Up pages with [mounted Clerk components](/docs/components/authentication/sign-in)
- Add `roles: ['admin']` to the user public metadata to [implement role-based access control](/docs/guides/basic-rbac)
- Go outside and visit the [Redwood National and State Parks](https://www.nps.gov/redw/index.htm) to see these majestic trees in person
- Connect with other developers or say hi in our [Discord community](https://clerk.com/discord) 👋

---

# Migrating from Pages Router to App Router: An Incremental Guide
URL: https://clerk.com/blog/migrating-pages-router-to-app-router-an-incremental-guide.md
Date: 2023-07-03
Category: Guides
Description: Already know the /pages directory? Here's a simple way to migrate to the /app directory in Next.js 13.

The Next.js [App Router](https://nextjs.org/docs/app) (in the **/app** directory) is a new way to build React applications. If you're already familiar with the [Pages Router](https://nextjs.org/docs/pages) (in the **/pages** directory), Next.js has made it really easy to adopt the App Router incrementally, quite literally on a page-by-page basis. This guide explains how.

## How is this guide different?

The App Router already has a [migration guide](https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration), so how is this different?

We want to demonstrate a 1-to-1 mapping of Pages Router to App Router, but this is not a complete migration. In the snippets below you will see obvious potential refactors, and **that is on purpose.**

As an example, one App Router snippet below still has function called `getServerSideProps`. It doesn't make sense to keep that name, but we want to demonstrate how `getServerSideProps` can be expressed in the context of the App Router.

One more disclaimer: this will not explain how to migrate *everything*. We focused on the best practices for the Pages Router in Next.js 12.3, but left out older APIs like `getInitialProps`.

## One quick clarification

You probably know that the App Router supports both **Client Components** and the newly introduced **Server Components**.

Before the App Router, Client Components were just called Components. We want to clarify that after the App Router, **absolutely nothing has changed about them.**

Most importantly, within the App Router, **Client Components** are still rendered on the server, then hydrated on client. Search engine crawlers can still index their HTML.

Within this guide, the React code from your Pages Router will be copied to new files and labeled with `"use client"` at the top. This is expected, since we're doing a 1-to-1 mapping.

## Migrating from the Pages Router to the App Router

### 0. Create the /app directory

Before you can get started with the App Router, you will first need to create a **/app** directory as a sibling to your **/pages** directory.

### 1. Migrate /pages/\_document to the App Router

If you have a [Custom Document](https://nextjs.org/docs/pages/building-your-application/routing/custom-document) at **/pages/\_document.tsx**, it should look something like this, though likely with some customization:

```tsx {{ title: '/pages/_document.tsx' }}
import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
  return (
    <Html>
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}
```

We need to convert this into a [Root Layout](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required), which can be treated as a 1-to-1 corollary to a Custom Document:

1. Clone **/pages/\_document.tsx** into **/app/layout.tsx**. We will keep both files since we're doing incremental adoption. (If you use .jsx that is no problem, you can use layout.jsx instead)
2. Remove the **next/document** import line entirely
3. Replace `<Html>` and `</Html>` with the lowercase, HTML equivalent `<html>` and `</html>`. For accessibility, it's best to add a language to your opening tag, like `<html lang="en">`
4. Replace `<Head>` and `</Head>` with the lowercase, HTML equivalent `<head>` and `</head>`. If you only have a self-closing `<Head />`, you can remove it entirely
5. Replace `<Main />` with `{children}`, and update the default function export to accept a `{children}` argument. For Typescript users, `children` is of type `React.ReactNode`
6. Remove `<NextScript />` entirely

When complete, **/app/layout.tsx** should look more like this, plus your customizations:

```tsx {{ title: '/app/layout.tsx' }}
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}
```

**Important: /app/layout.tsx is required** in the **/app** directory. If you do not have a Custom Document, you can copy-paste the above sample directly into **/app/layout.tsx**.

### 2. Migrate /pages/\_app.tsx to the App Router

**Note:** If you do not have a file at **/pages/\_app.tsx** you can skip to Step 3.

If you have a [Custom App](https://nextjs.org/docs/pages/building-your-application/routing/custom-app) at **/pages/\_app.tsx**, it should look something like this, though likely with some customization:

```tsx {{ title: '/pages/_app.tsx' }}
import type { AppProps } from 'next/app'

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

The **/app** directory does not have a 1-to-1 corollary for a Custom App, but it can easily be expressed in the new structure:

1. Clone **/pages/\_app.tsx** into **/app/ClientLayout.tsx**. We will keep both files since we're doing incremental adoption. (If you use .jsx that is no problem, you can use ClientLayout.jsx instead)
2. Add a new line to the top of the file that reads `"use client"` (with the quotes)
3. Replace the default export's function signature. Instead of taking `Component` and `pageProps` arguments, it should only take a `children` argument. For Typescript users, `children` is of type `React.ReactNode`.
4. Replace `<Component {...pageProps} />` with `<>{children}</>`, or just `{children}` if you have another wrapping element
5. If there are any remaining references to `pageProps`, please comment them out for now, and revisit them on a page-by-page basis. Next.js has added a new [metadata API](https://nextjs.org/docs/app/building-your-application/optimizing/metadata) that should normally be used in place of accessing `pageProps` here
6. We recommend changing the default export name from `MyApp` to `ClientLayout`. It is not strictly necessary, but it is more conventional

When complete, **/app/ClientLayout.tsx** should look more like this, plus your customizations:

```tsx {{ title: '/app/ClientLayout.tsx' }}
'use client'

export default function ClientLayout({ children }: { children: React.ReactNode }) {
  return <>{children}</>
}
```

Now, this is where things get a little different:

- In the Pages Router, **/pages/\_app.tsx** is a "magic" layout file that is automatically added to the React tree
- In the App Router, the only layout file automatically added to the React tree is the Root Layout from Step 1. So, we will need to manually import and mount our `ClientLayout` inside **/app/layout.tsx**

Open **/app/layout.tsx**, import ClientLayout, and use it to wrap `{children}`. When complete, your Root Layout should look like this, plus any customizations from Step 1:

```tsx {{ title: '/app/layout.tsx' }}
import ClientLayout from './ClientLayout'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <ClientLayout>{children}</ClientLayout>
      </body>
    </html>
  )
}
```

### 3. Migrate each page to the App Router

Now that your layout has been copied into the App Router, it's time to start migrating your pages one-by-one. There will be a few steps for each page:

1. Create a directory for the page
2. Create one file to handle data fetching
3. Create one file to render the page
4. Remove the Pages Router page

For the avoidance of doubt: yes, we will be splitting your Pages Router page into two files: one for data fetching and one for rendering.

#### 3.1. Create a directory for the page

Both the Pages Router and the App Router are "filesystem routers," but they are organized slightly differently. In the App Router, each page gets its own directory. Here is how to determine the directory name:

- If your file is named **index.tsx**, create the same parent directory structure
  - For **/pages/foo/index.tsx**, create **/app/foo**
  - For **/pages/index.tsx**, you already have **/app**
- If your file is **not** named **index.tsx**, create a directory with that filename
  - For **/pages/bar.tsx**, create **/app/bar**
  - For **/pages/baz/\[slug].tsx**, create **/app/baz/\[slug]**
  - For **/pages/baz/\[\[...slug].tsx**, create **/app/baz/\[\[...slug]]**

#### 3.2. Create a file to handle data fetching

Inside your page directory, create a file called **page.tsx** to handle data fetching. Copy-paste the following snippet as the foundation of this file (**Note:** we will create **ClientPage.tsx** in 3.3.):

```tsx {{ title: 'page.tsx' }}
import ClientPage from './ClientPage'

export default async function Page() {
  return <ClientPage />
}
```

If your Pages Router file does not have any data fetching, you can continue on to the next step. Otherwise, find your data fetcher below to learn how it can be migrated:

**Migrating getStaticProps to the App Router**

Consider the following is your implementation of `getStaticProps`:

```typescript
export const getStaticProps: GetStaticProps<PageProps> = async () => {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const repo = await res.json()
  return { props: { repo } }
}
```

To migrate this with as little modification as possible, we will:

1. Copy-paste `getStaticProps` into **page.tsx**
2. Call `getStaticProps` from within our `Page` component
3. Add `export const dynamic = "force-static"` so the page data is fetched once and cached, not refetched on every load
4. Pass the result to our (not yet created) `ClientPage` component

Here is the end result:

```tsx {{ title: 'page.tsx' }}
import ClientPage from './ClientPage'

export const getStaticProps: GetStaticProps<PageProps> = async () => {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const repo = await res.json()
  return { props: { repo } }
}

export const dynamic = 'force-static'

export default async function Page() {
  const { props } = await getStaticProps()
  return <ClientPage {...props} />
}
```

**Migrating getServerSideProps to the App Router**

Consider the following implementation of `getServerSideProps`:

```typescript
import { getAuth } from '@clerk/nextjs/server'

export const getServerSideProps: GetServerSideProps<PageProps> = async ({ req }) => {
  const { userId } = getAuth(req)

  const res = await fetch('https://api.example.com/foo', {
    headers: {
      Authorization: `Bearer: ${process.env.API_KEY}`,
    },
  })
  const data = await res.json()
  return { props: { data } }
}
```

To migrate this with as little modification as possible, we will:

1. Copy-paste `getServerSideProps` into **page.tsx**
2. Add `export const dynamic = "force-dynamic"` so the page data is refetched on every load
3. Replace any usage of `req` with the App Router equivalent
4. Our example uses [Clerk for authentication](/nextjs-authentication), so the end result will replace this line with its App Router-compatible replacement
5. Replace `req.headers` with the new [headers() helper](https://nextjs.org/docs/app/api-reference/functions/headers)
6. Replace `req.cookies` with the new [cookies() helper](https://nextjs.org/docs/app/api-reference/functions/headers)
7. Replace `req.url.searchParams` with the new [searchParams helper](https://nextjs.org/docs/app/api-reference/file-conventions/page#searchparams-optional)
8. Replace any Dynamic Route segment usage with the new [params helper](https://nextjs.org/docs/app/api-reference/file-conventions/page#params-optional)
9. Call `getServerSideProps` from within our `Page` component
10. Pass the result to our (not yet created) `ClientPage` component

Here is the end result:

```tsx {{ title: 'page.tsx' }}
import { auth } from '@clerk/nextjs'
import ClientPage from './ClientPage'

export const getServerSideProps: GetServerSideProps<PageProps> = async () => {
  const { userId } = auth()

  const res = await fetch('https://api.example.com/foo', {
    headers: {
      Authorization: `Bearer: ${process.env.API_KEY}`,
    },
  })
  const data = await res.json()
  return { props: { data } }
}

export const dynamic = 'force-dynamic'

export default async function Page() {
  const { props } = await getServerSideProps()
  return <ClientPage {...props} />
}
```

**Migrating getStaticPaths to the App Router**

Consider the following implementation of `getStaticPaths`:

```typescript
export async function getStaticPaths() {
  return {
    paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
  }
}
```

In the App Router, this implementation barely changes. It's simply given a new name (`generateStaticParams`) and the output is transformed to something simpler. That means you can use your old implementation directly, and simply transform the output.

Here is the end result – we included an example of how it can be used in tandem with `getStaticProps`:

```tsx {{ title: 'page.tsx' }}
import ClientPage from './ClientPage'

export async function getStaticPaths() {
  return {
    paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
  }
}

export async function generateStaticParams() {
  const staticPaths = await getStaticPaths()
  return staticPaths.paths.map((x) => x.params)
}

export const getStaticProps: GetStaticProps<PageProps> = async ({ params }) => {
  const res = await fetch(`https://api.example.com/foo/${params.id}`)
  const data = await res.json()
  return { props: { data } }
}

export default async function Page({ params }) {
  const { props } = await getStaticProps({ params })
  return <ClientPage {...props} />
}
```

#### 3.3. Create a file to render the page

Now that data fetching is ready, we need to configure the rendering. To accomplish this:

- Copy your original Pages Router page into **ClientPage.tsx**
- Remove any data fetching code, since it now lives in **page.tsx**

That's it! We have already configured **page.tsx** to mount this file and pass props, so it should be working.

#### 3.4. Remove the Pages Router page

Now that your page is ready in the App Router, you can delete the old Pages Router variant.

## What's next?

Now that your Pages Router application is working in the App Router, it's time to start taking advantage of the App Router and React Server Components.

In particular, right now your **ClientPage.tsx** files are one big Client Component. Going forward, it's best to refactor this so `"use client"` is used as sparingly as possible, ideally only on small components. A big Server Component importing many small Client Components will lead to less Javascript sent to the client, and a faster experience for your end user.

---

# Social SSO in Next.js
URL: https://clerk.com/blog/social-sso-in-next-js.md
Date: 2023-06-24
Category: Guides
Description: In this article, we explore how to incorporate OAuth SSO into a Next.js project with JSON Web Tokens (JWTs) and the new app router from Next.js.

Authentication has always been a critical aspect of web development, with user data security being paramount.

As the digital world continues to evolve, so does the need for more efficient and secure authentication methods. However, users do not necessarily want to remember secure logins for every app they use.

This is where OAuth Single Sign-On (SSO) comes into play. OAuth simplifies the user authentication process by allowing users to log in with accounts they already have with other services like [Google](/blog/nextjs-google-authentication), Facebook, or Microsoft.

In this article, we will explore how to incorporate OAuth SSO into a Next.js project with [JSON Web Tokens (JWTs)](https://jwt.io/introduction) and Next.js’s new app router, and later see how Clerk, an [authentication service](/nextjs-authentication), can help simplify this and make it more secure. We will focus on GitHub SSO for simplicity, but most other OAuth providers can be implemented similarly.

Before we get started, if you ever need to look at the full source, code, the [example code is on GitHub](https://github.com/AsyncBanana/nextjs-sso).

## Set up the project

Before we start, make sure you are on Node v18+. You can check this by running `node -v` in a terminal.

### Scaffolding

We will use [create-next-app](https://nextjs.org/docs/getting-started/installation) to scaffold our project. First, you will want to open a terminal in the directory you want to put the project in and run:

```sh
npx create-next-app@latest
```

If you want to use a different package manager, use their own counterpart to `npx`, like `pnpx`. c`reate-next-app` will ask you some questions about your project. Name the project whatever you want; it doesn’t matter. For TypeScript, ESLint, Tailwind, and using `/src`, select no. For the app router, select yes. Finally, leave the import aliases unmodified. After, the output should look like this:

![Social Sso In Next Js guide illustration](./3831e3d2719600d436fc5a7f55c3528434e9b6e0-2000x1250.png)

Now, open that directory in a code editor of your choice. You will need to install jsonwebtoken, which we will use for verifying JWTs.

```sh
npm i jsonwebtoken
```

### Create a GitHub OAuth App

Next, we will need to create the OAuth app in GitHub. Go to [github.com/settings/applications/new](https://github.com/settings/applications/new) and fill out the information. Set the homepage URL to `http://localhost:3000` and the callback URL to `http://localhost:3000/callback` (if you are running the Next.js server on a port other than 3000, you can replace 3000 with that port). You can leave device flow unchecked. Click register and you will be sent to the new application page.

![Social Sso In Next Js guide illustration](./387ca25acbfc80693dda994683b9ed4a0ba430ae-2000x1250.png)

Now, let’s go back to the code for a minute. Create a new file called `.env.local`. This is where you will store your environment variables, which are variables that specify service keys or other configuration that is specific to each deployment and are specified by writing `VARIABLE_NAME=variable_value`, with each variable being on one line.

In the `.env.local` file, create a variable named `NEXT_PUBLIC_GITHUB_OAUTH_ID`. This will contain your GitHub OAuth application’s id. Note that the `NEXT_PUBLIC` prefix tells Next.js to allow the env variable to be accessed by replacing all calls to `process.env.NEXT_PUBLIC_GITHUB_OAUTH_ID` with the value of the variable at build time. If you did not include this prefix, only the server would be able to access the value, which is good for secrets. With that aside, we need to get the GitHub OAuth application id, which you can find on the application dashboard you were sent to earlier. Copy it and paste it into the .env file.

We also need to get a secret, which we will put with the variable `GITHUB_OAUTH_SECRET`. On the dashboard, you can click “Generate a client secret” to get a new secret. Copy it and paste it in the .env file under the new variable.

Finally, we need `JWT_SECRET`, which should be a random password we use for encrypting JWTs. You can use a [password generator](https://passwordsgenerator.net) for this.

That is it for set up! Remember not to give anyone any of the secrets unless you trust them, as they can be used to impersonate users and gain unauthorized access to the application.

## Implement sign in

Our next step is to allow people to sign in by adding a sign in button on the homepage that links to the GitHub OAuth verification page. Open `app/page.js` and insert the following below the Next.js logo (You should be able to find it by looking for an `<Image>` with `src=src="/next.svg"`).

```javascript
<a
  href={`https://github.com/login/oauth/authorize?scope=user:email&client_id=${process.env.NEXT_PUBLIC_GITHUB_OAUTH_ID}`}
  className={buttonStyle.button}
>
  Sign in with GitHub
</a>
```

The link will send people to a page where they can authorize the OAuth app’s access to their account information to allow the app to verify their identity. You might notice `className` contains a style that does not currently exist. We will fix this next. In `/app`, create a file named `button.module.css` and paste the following in.

```css
.button {
  z-index: 2;
  margin: 10px;
  transition-duration: 0.2s;
  display: inline-block;
  font-weight: 600;
  border: 1px solid transparent;
  border-radius: 6px;
  white-space: nowrap;
  padding: 5px 16px;
  font-size: 14px;
  line-height: 20px;
  vertical-align: middle;
  cursor: pointer;
  user-select: none;
  color: #24292e;
  background-color: #fafbfc;
}

.button:hover {
  background-color: #f3f4f6;
}

.button:focus {
  outline: none;
  border: 1px solid #c0d3eb;
  box-shadow: 0 0 0 1px black;
}

.button:active {
  background-color: #edeff2;
}
```

This just provides some simple styling for the button. In order to use it, we need to import it in `page.js`. Add this line to the top of `page.js`.

```jsx
import buttonStyle from './button.module.css'
```

To get the layout correct, we also have to add this to `.center` in `page.module.css`.

```css
flex-direction: column;
```

Now, run `npm run dev` and go to `http://localhost:3000`. You should see this:

![Social Sso In Next Js guide illustration](./247a788c35e5ea1c9dd8c876cbac8cded81fb1ff-3840x2160.png)

If you click “Sign in with GitHub,” you should be redirected to a GitHub page asking you to authorize your OAuth app. However, if you click authorize, you will get a 404 error. That is because we have not implemented a callback page yet, which we will do next.

## Creating a callback

Before we start this step, a bit of explaining is required. You might have seen OAuth flows implemented differently, and this is perfectly fine. There are multiple ways to handle OAuth codes and retrieve access tokens. In this case, we are using [Authorization Code Grant](https://oauth.net/2/grant-types/authorization-code), which is where the OAuth provider (GitHub in this case) sends a request to the specified callback URL (which we are implementing now) with a code. Then, the server sends a request to GitHub with the code, and GitHub responds with the access token. This is generally the most secure method, but for mobile apps or SPAs, it does not always work. With that explained, we will get started on implementing the callback.

You first want to create a folder named `callback` in app and a file named r`oute.js` inside callback. This tells Next.js’s filesystem router that `route.js` should handle API requests sent to `/callback`. Now, paste this into `route.js`:

```javascript
import jwt from 'jsonwebtoken'
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'

export async function GET(req) {
  const code = new URL(req.url).searchParams.get('code')

  if (!code) {
    return new Response('No code provided', { status: 400 })
  }

  try {
    const tokenResponse = await fetch('https://github.com/login/oauth/access_token', {
      method: 'POST',
      headers: {
        accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        client_id: process.env.NEXT_PUBLIC_GITHUB_OAUTH_ID,
        client_secret: process.env.GITHUB_OAUTH_SECRET,
        code,
      }),
    })

    const tokenData = await tokenResponse.json()

    const { access_token } = tokenData

    if (!access_token) {
      return new Response('GitHub login failed', { status: 400 })
    }

    const jwtToken = jwt.sign({ access_token }, process.env.JWT_SECRET, {
      expiresIn: '1h',
    })
    cookies().set('auth', jwtToken, {
      httpOnly: true,
      secure: process.env.NODE_ENV !== 'development',
      sameSite: 'lax',
      maxAge: 3600, // 1 hour
      path: '/',
    })
  } catch (error) {
    console.error(error)
    return new Response('Internal server error', { status: 500 })
  }
  redirect('/dashboard')
}
```

We will go through this step by step. First, we import a few different things:

- `jsonwebtoken` is for creating JWTs, which we use to store the userdata and allow us to verify that bad actors did not change it (we will do this later)
- `cookies` from `next/headers` is for setting cookies on the client. This function is an abstraction over the `Set-Cookie` HTTP header, hence the import location.
- `redirect` from `next/navigation` is for redirecting users. Similar to the `cookies` function, this function abstracts over HTTP responses by automatically responding with an HTTP 3xx status code (read: a redirect) with the `Location` header set to the value passed.

After that, we export a new function named `GET`, which takes `req` as a parameter. This function handles all HTTP requests to `/callback` with the HTTP method `GET`, which is the method used for typical requests that do not contain a body. `req` contains all of the information about the request.

The next part retrieves the code from the `code` query parameter in the URL. You can refer to the explanation at the start of this section to learn how this is used. If there is no code, the function returns a 400 error.

Now that we have the code, we send it back to GitHub to get the access token. After getting the response, we parse the JSON body and extract the access token. If there is no access token, another error is returned.

We sign the token to allow us to store it in a cookie with confidence that it cannot change without the JWT secret. Using the signed token, we set the `auth` cookie for the user. The parameters we passed are very important. `httpOnly` makes sure JavaScript cannot access the cookie’s value, `secure` makes sure that when deployed in production, the cookie cannot be sent over unencrypted HTTP, and `sameSite` prevents the cookie from being sent to third party websites. `sameSite=lax` is the default in modern browsers, but it is still a good idea to make it explicit.

Finally, we redirect the user to `/dashboard`. If you run this code, you should end up at another 404 at `/dashboard`. We will create the dashboard next.

## Creating a protected dashboard

Once again, we need to create a file named `dashboard` and a file inside it named `page.js`. Because this is a page rather than an API route, the naming is different. Copy the following into `page.js`:

```javascript
import { cookies } from 'next/headers'
import jwt from 'jsonwebtoken'
import { redirect } from 'next/navigation'
import buttonStyle from '../button.module.css'

export default async function Page() {
  const auth = cookies().get('auth')
  if (!auth) {
    redirect(
      `https://github.com/login/oauth/authorize?scope=user:email&client_id=${process.env.NEXT_PUBLIC_GITHUB_OAUTH_ID}`,
    )
    return
  }
  const user = jwt.verify(auth.value, process.env.JWT_SECRET)
  const response = await fetch('https://api.github.com/user', {
    headers: {
      Authorization: `token ${user.access_token}`,
    },
    cache: 'no-store',
  })
  const userdata = await response.json()
  return (
    <div>
      <h1
        style={{
          'text-align': 'center',
          'margin-top': '100px',
        }}
      >
        Welcome {userdata.name} to the dashboard!
      </h1>
      <a href="/logout" className={buttonStyle.button}>
        Logout
      </a>
    </div>
  )
}
```

Once again, we will go through this step by step. The imports are largely the same as the callback. The only difference is the addition of `../button.module.css`, which is the CSS file we created earlier for button styling.

This time, instead of a function named `GET`, because this is a page, we export a function named `Page`. Of course, because it is a default export in this case, the naming doesn’t really matter.

Next, we get the auth cookie. If no auth cookie is found, the user is not signed in, so we redirect the user to the sign in.

If there is an auth cookie, we verify the JWT contained in it. This is how we make sure the value was not tampered with. JWTs have a header, payload, and signature. The payload’s value can be accessed without the JWT secret. However, the JWT cannot be modified, as the signature is generated using the JWT secret and payload value. Therefore you need both of those to generate a valid signature. What we are doing here is both decrypting the payload and making sure the signature is valid.

Now that we have verified the JWT and extracted the payload, we use the access token in the JWT to request the user’s data from the GitHub API. The `cache` parameter disables Next.js’s AOT caching/static generation. Normally we would do this inside a `useEffect()` call, but because we are using [React Server Components](https://nextjs.org/docs/getting-started/react-essentials#server-components) with Next.js, this is the idiomatic way of using `fetch()` (remember that this renders once on the server and does not render on the client period). We then parse the response body to get the userdata.

After that, we just have some markup that renders a welcome message with the user’s name and a logout button. We use inline styles for the header because creating another CSS file just for two rules didn’t make sense. You might notice that the logout button links to `/logout`, which does not exist yet. We will fix that.

Tip: If you have lots of protected routes and want to avoid code repetition, you could implement the authentication as
middleware or just a function imported in the relevant routes

## Adding a logout route

This is pretty simple. The first thing to do is to create another route, just like what we did for `/callback`. Create a new folder in `app` called `logout` and a file called `route.js` in the new folder. Insert the following in the new file:

```javascript
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'

export async function GET(req) {
  cookies().delete('auth')
  redirect('/')
}
```

As you can see, this script is pretty simple. We just intercept GET requests to `/logout`, delete the cookie named `auth`, and redirect the user to the homepage. Note that if the user tries to log in again, it might seem as if they are still signed in, as GitHub will silently send the access token and redirect the user when they click login. However, if you implement a more complete sign in solution, this will allow users to sign in to another account with a different method.

That is all! You now have a basic system for OAuth authentication. However, there are a few issues.

## Problems with this Implementation

While this works, there are some problems:

- There is no protection against CSRF (Cross Site Request Forgery)
- There are no refresh tokens, and access tokens can last indefinitely (this is a limitation of GitHub OAuth apps)
- GitHub is currently the only sign in method (non OAuth sign requires many more security measures due to the need to store information in a database)
- There is support if issues arise with authentication

We could solve most of these problems, but it would take a significant amount of time (this tutorial is already almost 3,000 words) and increase maintenance. However, there is a better solution: you can use a service like [Clerk](/). Clerk is a user management platform that allows you to easily and securely implement most of the popular OAuth providers along with standard email/password sign in, [magic link/passwordless](/blog/magic-links), and even Metamask.

## Using Clerk for Authentication

Once again, run:

```sh
npx create-next-app@latest
```

and select the same choices as previously (any name, everything “no” except for the app router). Then, run:

```sh
npm install @clerk/nextjs
```

This installs the Clerk SDK for Next.js. Now, we need to set up a Clerk app. Go to [Clerk’s app creation page](https://dashboard.clerk.com/apps/new) (create an account if you did not already) and go through the configuration. For authentication providers, you can stick to just GitHub again or add as many providers as you want. It doesn’t change the process, and you can change it later. After that, you should be redirected to a page where you see a snippet containing `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY`. Copy this and paste it into a new file named `.env.local`. This includes the environment variables that store your public and private Clerk keys.

To allow us to use Clerk React components in our project, we first need to insert the `<ClerkProvider>` component into `layout.js`. Replace all content in `layout.js` with the following:

```javascript
import './globals.css'
import { Inter } from 'next/font/google'
import { ClerkProvider } from '@clerk/nextjs'
const inter = Inter({ subsets: ['latin'] })

export const metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <ClerkProvider>{children}</ClerkProvider>
      </body>
    </html>
  )
}
```

`<ClerkProvider>` provides the context necessary to allow Clerk components to function properly, and due to it being `layout.js`, it is inserted into every page.

Next, we need to create the sign in button, just like in the first version. Open `page.js` in `app` and insert this below the Next.js logo (the image with `src="/next.svg"`):

```javascript
{
  auth().userId ? (
    <a href="/dashboard" className={buttonStyle.button}>
      Dashboard
    </a>
  ) : (
    <SignInButton mode="modal" redirectUrl="/dashboard">
      <button className={buttonStyle.button}>Sign In</button>
    </SignInButton>
  )
}
```

This checks if the user is signed in. If they are, it shows a link to the dashboard, and if not, it shows a button to sign in. To make this work, you will also need to import two things at the top of the file:

```javascript
import { SignInButton, auth } from '@clerk/nextjs'
import buttonStyle from './button.module.css'
```

The first line contains the functions and components needed from the Clerk SDK, and the second is for the styling. You will want the same styling as in the previous version, so create a new file named button.module.css and insert this into it:

```css
.button {
  z-index: 2;
  margin: 10px;
  transition-duration: 0.2s;
  display: inline-block;
  font-weight: 600;
  border: 1px solid transparent;
  border-radius: 6px;
  white-space: nowrap;
  padding: 5px 16px;
  font-size: 14px;
  line-height: 20px;
  vertical-align: middle;
  cursor: pointer;
  user-select: none;
  color: #24292e;
  background-color: #fafbfc;
}

.button:hover {
  background-color: #f3f4f6;
}

.button:focus {
  outline: none;
  border: 1px solid #c0d3eb;
  box-shadow: 0 0 0 1px black;
}

.button:active {
  background-color: #edeff2;
}
```

Then, add this to `.center` in `page.module.css`:

```css
flex-direction: column;
```

Now sign in should work, but we still need to implement the dashboard. First, we need to create a JavaScript file at the project root named middleware.js (make sure to put this at the project root, not/app). Paste the following in the new file:

```javascript
import { authMiddleware } from '@clerk/nextjs'
export default authMiddleware()

export const config = {
  matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'],
}
```

This is a basic setup for the [authentication middleware](/nextjs-authentication). You can configure it more to exclude specific routes, but this should work in most cases.

The next step is to create a folder called `dashboard` and a file named `page.js` inside it, just like with the implementation we already made. Inside the file, paste this:

```javascript
import { currentUser, RedirectToSignIn, SignOutButton } from '@clerk/nextjs'
import buttonStyle from '../button.module.css'

export default async function Page() {
  const userdata = await currentUser()
  if (!userdata) {
    return <RedirectToSignIn />
  }
  return (
    <div>
      <h1
        style={{
          'text-align': 'center',
          'margin-top': '100px',
        }}
      >
        Welcome {userdata.emailAddresses[0].emailAddress} to the dashboard!
      </h1>
      <SignOutButton>
        <button className={buttonStyle.button}>Logout</button>
      </SignOutButton>
    </div>
  )
}
```

We will go through this step by step.

First, we import some packages.

- We import multiple different functions and components from the Clerk SDK. The first, `currentUser()`, helps us get the current user’s information. The second, `RedirectToSignIn`, not to be confused with the function `redirectToSignIn`, which is also exported, is a component that redirects the user to a sign in page. Finally, we have `SignOutButton`, which creates a button to allow the user to log out.
- `buttonStyle` is just CSS from our `button.module.css` file, which we use for the log out button.

Next, we export a function called `Page`, which has been explained previously.

After that, we use `currentUser()` to get the user’s information. If it does not exist (meaning the user is signed out), we redirect to a sign in page using a client side redirect.

Finally, using the userdata, we return markup containing a header with the user’s email and a button to log out.

Now, sign in, the dashboard, and sign out should all work.

## Easy SSO

That’s it! You now should have two implementations of OAuth authentication, one that is hand built and more limited and one that is built with Clerk and more feature rich. If you want to learn more about Clerk, check out the [Clerk Docs](/docs). I hoped you learned something, and thanks for reading!

Interested in exploring more? Look into [Next.js Magic Links](/blog/magic-links) for a seamless, passwordless authentication experience in your Next.js apps.

---

# How to Authenticate API Requests with Clerk & Express
URL: https://clerk.com/blog/how-to-authenticate-api-requests-with-clerk-express.md
Date: 2023-06-16
Category: Guides
Description: In this tutorial, we'll explore how to use Clerk with Express to authenticate API requests using middleware.

APIs are essential for building powerful applications that can communicate and share data with other systems.

However, with great power comes great responsibility: it's critical to ensure that only authorized users can access your API, and that requests are properly authenticated and verified. Failure to do so can lead to serious security breaches, data leaks, and other vulnerabilities that can compromise the integrity of your application and put your users at risk.

In this tutorial, we'll explore how to use Clerk with Express to authenticate API requests using `ClerkExpressWithAuth()` and `ClerkExpressRequireAuth()` middleware, and build a secure and robust backend for your application. Let's get started!

## Always authenticate

When developing an API, especially in Express.js or any other framework, it's important to authenticate requests for a number of reasons:

1. **Security**: The most important reason is to maintain the security of your application. By authenticating API requests, you ensure that only authorized clients or users can interact with your API. This reduces the potential for malicious actions such as data theft, unauthorized modification, or even denial of service attacks.
2. **Access Control**: It allows you to control who can access certain resources and operations in your API. For instance, certain resources might only be available to admin users, while others are available to all authenticated users.
3. **Rate Limiting**: When you authenticate a user, you can associate them with a specific usage quota. This can be used to implement rate limiting, preventing any single user from overloading the server with requests.
4. **Data Accuracy**: In many cases, your API's operations will be tied to a specific user's data. For example, a "get user profile" endpoint would need to know which user's profile to retrieve. Authentication provides a way to associate requests with users.
5. **Audit and Logs**: It allows you to keep track of who did what and when. This is very useful when you need to audit the usage of your system.

Implementing express authentication or Node.js authentication is vital for maintaining the integrity, security, and reliable operation of your APIs.

That being said, there might be some API routes that you intentionally leave unauthenticated for various reasons. For instance, a login or registration route needs to be unauthenticated so that users can authenticate or create an account. Similarly, you might provide some public data through your API that doesn't require authentication.

But you should default to authentication. Consider it a component of building as you plan out epics or sprints on APIs. But adding auth doesn’t have to be particularly challenging. You can build this out yourself with middleware functions, but like a lot of elements in authentication, it’s better to use specialized components.

Let’s go through two of these we have at Clerk, `ClerkExpressWithAuth()` and `ClerkExpressRequireAuth()` to see how we can set these up Express authentication and call these endpoints from a client.

You can check out all the code for this tutorial in this [repo](https://github.com/argotdev/express-authentication).

## Authenticating Express API endpoints with Clerk

Before we get to the Clerk specifics, it’s good to define two components of API methods in Express (and elsewhere) that are fundamental concepts to how authentication will work: *callbacks* and *middleware*.

A ***callback*** function is a function that is passed to another function as a parameter and then invoked by that function at a later time. Callbacks are heavily used in Node.js because it's designed to be asynchronous and non-blocking. When performing I/O operations like making HTTP requests, Node.js can start the operation and then continue executing other code without waiting for the operation to complete. When the operation is complete, the callback function is called with the result.

***Middleware*** functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. Middleware functions can perform tasks like modifying the request or response objects, ending the request-response cycle, or invoking the next middleware function in the stack.

In Express, middleware functions are often used as callbacks to handle HTTP requests. When you define a route in Express.js, you provide a callback function that's called whenever a client makes a request to that route. This callback function is also a middleware, because it has access to the `req`, `res`, and `next` objects.

```jsx
app.get('/example', function (req, res, next) {
  // This function is a middleware and a callback
})
```

So, in this sense, middleware functions are a specific type of callback. They're callbacks that are designed to be used in the context of an HTTP request to an Express.js server.

This is what we’re going to do with Clerk. We’re going to use one of two authentication middleware functions as a callback for the request to our API endpoint. Those two middleware functions are:

1. `ClerkExpressWithAuth()` is a lax authentication middleware that returns an empty auth object when an unauthenticated request is made.
2. `ClerkExpressRequireAuth()` is a strict authentication middleware that raises an error when an unauthenticated request is made.

There are subtle but important differences between these two. Let’s go through them.

### Using ClerkExpressWithAuth()

`ClerkExpressWithAuth()` is lax in that when it fails, it still returns an object, not an error.

Let’s get some code up and running to showcase this function. We’ll create a directory called ‘backend’ and make that the current directory:

```bash
mkdir backend && cd backend
```

With that done, we’ll start installing our dependencies for this code. If you don’t already have it, you’ll also need node as this is the runtime we’re building upon. You can grab the latest build from [here](https://nodejs.org/en).

Then you can run `npm init` to create a package.json in that directory. With that we can use npm to install:

- [Express](https://expressjs.com), which is the web framework for Node.js we’re going to use. Express is a great option for running node servers because it’s fast, minimal, and unopinionated.
- [dotenv](https://www.npmjs.com/package/dotenv), which is the node package you need to read environmental variables in node.
- [@clerk/clerk-sdk-node](https://www.npmjs.com/package/@clerk/clerk-sdk-node) is the Node.js SDK for the Clerk user management platform.
- [cors](https://www.npmjs.com/package/cors) allows us to easily call the endpoint from a client

```bash
npm install express dotenv cors @clerk/clerk-sdk-node
```

When they are installed, create a file in your `with-auth` directory called `app.js`:

```bash
touch app.js
```

Then create a `.env` file in the same directory:

```bash
touch .env
```

This is where you’re going to store your `CLERK_API_KEY`. You can find this in your dashboard. Because you are building these routes on the backend, you can use your secret key:

![Clerk Secret Key](./c5601e5fd15a61e893bfb2d1a7aea4df6eea06f5-2056x442.png)

Then open this directory with your IDE. If you are using VS Code, you can just type `code .` and you’ll get a window ready in that directory.

Add your secret key to your .env file after `CLERK_API_KEY=key-goes-here`. Add the following code to `app.js`:

```jsx
import 'dotenv/config' // To read CLERK_API_KEY
import { ClerkExpressWithAuth } from '@clerk/clerk-sdk-node'
import express from 'express'
import cors from 'cors'
const port = process.env.PORT || 3000

const app = express()
app.use(cors())
// Use the lax middleware that returns an empty auth object when unauthenticated
app.get('/protected-endpoint', ClerkExpressWithAuth(), (req, res) => {
  res.json(req.auth)
})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})
```

Let’s work through this line by line.

- Firstly we have all our imports:
  - `import "dotenv/config"` imports the "dotenv" package and automatically runs its `config` function. This package reads environmental variables from the `.env` file and adds them to `process.env`. Here we need it to access a `CLERK_API_KEY` environment variable.
  - We import `ClerkExpressWithAuth` from the "@clerk/clerk-sdk-node" package. This function is middleware for Express.js that handles authentication with Clerk.
  - We import `express` from the Express.js package
  - `import cors from "cors"` imports the "cors" package, a package used for enabling Cross Origin Resource Sharing (CORS). We’ll need this to aid calling the endpoint from our client.
- We then set a constant `port` to the value of the `PORT` environment variable if it's set, otherwise it defaults to `3000`.
- `const app = express()` creates a new Express application. The application is what is going to run our server.
- `app.use(cors())` adds the CORS middleware to the Express application, enabling CORS.
- `app.get(…)` defines a route for the path "/protected-endpoint" on the Express app. This route has two middleware functions:
  - `ClerkExpressWithAuth`: This is the function that checks the authorization of the incoming request. If the request is authenticated, it sets `req.auth` to an object representing the authenticated user.
  - `(req, res) => { res.json(req.auth); console.log(res.json); }`: This is an anonymous function that takes the incoming request and outgoing response as arguments. It sends a JSON response with the `auth` object from the request, and then it logs the JSON response function to the console.
- The final `app.listen(…)` part of the code starts the server and makes it listen for incoming connections on the specified port. It logs a message to the console indicating that the server is running and listening on that port.

Let’s run this:

```bash
node app.js
```

You should now see that message from in your `app.listen(…)` terminal:

```bash
Example app listening at http://localhost:3000
```

Great! You have a working endpoint. Let’s call that endpoint (`http://localhost:3000/protected-endpoint`) from Postman to see what it returns:

```json
{
  "sessionClaims": null,
  "sessionId": null,
  "session": null,
  "userId": null,
  "user": null,
  "actor": null,
  "orgId": null,
  "orgRole": null,
  "orgSlug": null,
  "organization": null,
  "claims": null
}
```

As we said above, `ClerkExpressWithAuth()` returns “an empty auth object when unauthenticated.” Now, you have a conundrum—you need an authenticated user to check this really works. To do that, we’ll create a quick React frontend client that calls `/protected-endpoint` after authenticating a user.

Keep that app running and open up another terminal. If it opens up in the same directory, make sure you cd .. up a level (you don’t want to create your frontend React app in a subdirectory of your backend—headaches will ensue).

We’ll first install create-react-app to help us (funnily enough) create a react app:

```bash
npm install create-react-app
```

Then run `npx create-react-app my-app` where my-app is the name of your app. Here we’ll go with auth-frontend:

```bash
npx create-react-app frontend
```

Then we’ll `cd frontend` to get into that directory and open with our IDE (again using `code .` if using VS Code).

Again, we’re going to add Clerk to this project, this time using`@clerk/clerk-react`, which is the Clerk React SDK.

We’ll also want to install `isomorphic-fetch` and `es6-promise` to polyfill the Fetch API for browsers that don't support it:

```bash
npm install @clerk/clerk-react isomorphic-fetch es6-promise
```

Like with the backend, you are going to need your Clerk API key. This time though you are going to use your public key as we’re authorizing a frontend client:

![Clerk Publishable Key](./60a107564b24f529282c1cda0eaebdfb50345894-2072x360.png)

Create a .env file and then add that key to it like this: `REACT_APP_CLERK_PUBLISHABLE_KEY=key-goes-here`.

Now go to the src/App.js file, remove the boilerplate entirely and add this code:

```jsx
import React from 'react'
import './App.css'
import { ClerkProvider, SignedIn, SignedOut, RedirectToSignIn } from '@clerk/clerk-react'
import Auth from './auth'

if (!process.env.REACT_APP_CLERK_PUBLISHABLE_KEY) {
  throw 'Missing Publishable Key'
}

const clerkPubKey = process.env.REACT_APP_CLERK_PUBLISHABLE_KEY

function App() {
  return (
    <ClerkProvider publishableKey={clerkPubKey}>
      <SignedIn>
        <Auth />
      </SignedIn>
      <SignedOut>
        <RedirectToSignIn />
      </SignedOut>
    </ClerkProvider>
  )
}

export default App
```

We won’t go through this line by line because we’ve taken it entirely, with one exception, from our docs on [getting started with React](/docs/quickstarts/get-started-with-create-react-app). Head there to learn more about Clerk and React.

That one exception is that we’ve swapped out the `<Welcome />` component in the documentation within the `<SignedIn></SignedIn>` component for an `<Auth />` component. Within the src directory add `auth.js` and add this code:

```jsx
//src/auth.js

import fetch from 'isomorphic-fetch'
import React, { useState, useEffect } from 'react'

import { useAuth } from '@clerk/clerk-react'

function Auth() {
  const [data, setData] = useState(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)
  const { getToken } = useAuth()

  useEffect(() => {
    const fetchData = async () => {
      try {
        const token = await getToken()
        const response = await fetch('http://localhost:3000/protected-endpoint', {
          method: 'GET',
          headers: {
            'Content-Type': 'application/json',
            Authorization: `Bearer ${token}`,
            mode: 'cors',
          },
        })

        if (!response.ok) {
          throw new Error('Network response was not ok')
        }

        const result = await response.json()
        setData(result)
        setLoading(false)
      } catch (err) {
        setError(err)
        setLoading(false)
      }
    }

    fetchData()
  }, [getToken])

  if (loading) {
    return <div>Loading...</div>
  }

  if (error) {
    return <div>Error: {error.message}</div>
  }

  return (
    <div>
      <h1>Data from API:</h1>
      <p>{JSON.stringify(data, null, 2)}</p>
    </div>
  )
}

export default Auth
```

We will go through this line by line as it shows how you can pass that authentication token to the API endpoint.

- `import fetch from "isomorphic-fetch"` imports the `fetch` function from the `isomorphic-fetch` package.
- The next line imports the `React` default export and the `useState` and `useEffect` named exports from the `react` package. `useState` is a React Hook that lets you add React state to function components, and `useEffect` lets you perform side effects in function components.
- The final import is for the `useAuth` hook from the `@clerk/clerk-react` package. This hook provides access to Clerk's auth-related functionality.
- The `Auth` function component is then declared. Four pieces of state are created using the `useState` hook: `data`, `loading`, and `error` for storing API response data, the loading state, and any error messages, respectively. The `getToken` function is extracted from the `useAuth` hook to allow authentication token retrieval.
- We then create a `useEffect` hook to define a side effect that fetches data from an API when the component is first mounted and whenever the `getToken` function changes.
- Within the `useEffect` hook, the `fetchData` function tries to retrieve a token, then sends a GET request to our `/protected-endpoint`. If the request fails, it sets the error state and stops loading. If it succeeds, it sets the data state to the response data, and stops loading.
  - The critical part of this is the line `Authorization: Bearer ${token}`. Here, we’re passing the authorization token from our now-signed-in-user to our `/protected-endpoint` to use in its own authentication.
- In the rendering part of the `Auth` component, it checks if the `loading` state is true, and if so, returns a "Loading..." message. If there's an error, it displays the error message. Otherwise, it displays the data fetched from `/protected-endpoint`.
- Finally we export the `Auth` component as the default export of this module. This allows the `Auth` component to be imported and used in other parts of the application.

And thus we import that `Auth` and call it within the `SignedIn` function so we can use the authorization token and pass it to `/protected-endpoint`. Within `/protected-endpoint`, the ClerkExpressWithAuth middleware will check whether it is a valid token, and, if so, return a full auth object:

```json
{
  "sessionClaims": {
    "azp": "http://localhost:3000",
    "exp": 1686337111,
    "iat": 1686337051,
    "iss": "https://keen-moray-98.clerk.accounts.dev",
    "nbf": 1686337041,
    "sid": "sess_2QvzpU7hY6lF5GQSjQQHckp8wps",
    "sub": "user_2Qbkhxfu7VCmvM4Xguez0fmMg1c"
  },
  "sessionId": "sess_2QvzpU7hY6lF5GQSjQQHckp8wps",
  "userId": "user_2Qbkhxfu7VCmvM4Xguez0fmMg1c",
  "claims": {
    "azp": "http://localhost:3000",
    "exp": 1686337111,
    "iat": 1686337051,
    "iss": "https://keen-moray-98.clerk.accounts.dev",
    "nbf": 1686337041,
    "sid": "sess_2QvzpU7hY6lF5GQSjQQHckp8wps",
    "sub": "user_2Qbkhxfu7VCmvM4Xguez0fmMg1c"
  }
}
```

Now, on the backend we have our `sessionId` and `userId` and `claims` to use as needed and we know our user is authenticated and allowed to use this API endpoint!

### Using ClerkExpressRequireAuth()

`ClerkExpressRequireAuth` works slightly different when a user is unauthenticated. Whereas `ClerkExpressWithAuth` just returned an empty auth object, `ClerkExpressRequireAuth` returns an error.

Swap out your code in your express app.js for this below:

```jsx
import 'dotenv/config' // To read CLERK_API_KEY
import { ClerkExpressRequireAuth } from '@clerk/clerk-sdk-node'
import express from 'express'

const port = process.env.PORT || 3000
const app = express()

// Use the strict middleware that raises an error when unauthenticated
app.get('/protected-endpoint', ClerkExpressRequireAuth(), (req, res) => {
  res.json(req.auth)
})

app.use((err, req, res, next) => {
  console.error(err.stack)
  res.status(401).send('Unauthenticated!')
})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})
```

Most of this code is the same as the `ClerkExpressWithAuth` example above. The differences are:

- We’re importing the `ClerkExpressRequireAuth` from the Clerk Node.js SDK
- We’re calling that `ClerkExpressRequireAuth` middleware within our app.get() function.
- We now have an error-handling middleware function. If an error occurs in any middleware function that is run before this one (here the `ClerkExpressRequireAuth`), this function will be called. It logs the stack trace of the error and sends a response with the HTTP status code `401`, indicating that the client must authenticate to get the requested response, along with the message `Unauthenticated!`.

And lo and behold, if you call this in Postman you’ll get a 401 and this message:

```
Unauthenticated!
```

This is safer as we aren’t even sharing the structure of our auth object.

If we now call this within our React app though, we do get our auth object because we are authenticated:

```json
{
  "sessionClaims": {
    "azp": "http://localhost:3000",
    "exp": 1686337111,
    "iat": 1686337051,
    "iss": "https://keen-moray-98.clerk.accounts.dev",
    "nbf": 1686337041,
    "sid": "sess_2QvzpU7hY6lF5GQSjQQHckp8wps",
    "sub": "user_2Qbkhxfu7VCmvM4Xguez0fmMg1c"
  },
  "sessionId": "sess_2QvzpU7hY6lF5GQSjQQHckp8wps",
  "userId": "user_2Qbkhxfu7VCmvM4Xguez0fmMg1c",
  "claims": {
    "azp": "http://localhost:3000",
    "exp": 1686337111,
    "iat": 1686337051,
    "iss": "https://keen-moray-98.clerk.accounts.dev",
    "nbf": 1686337041,
    "sid": "sess_2QvzpU7hY6lF5GQSjQQHckp8wps",
    "sub": "user_2Qbkhxfu7VCmvM4Xguez0fmMg1c"
  }
}
```

And with that, you can now authenticate any API endpoint in your Express apps.

## Fast, authenticated endpoints

With Express and Clerk you can get authenticated, production-ready APIs up in a matter of just a few minutes. There is more code in our client that for our endpoint. Using `ClerkExpressWithAuth()` or `ClerkExpressRequireAuth()` you can protect any endpoint and add express authentication or node authentication without the hassle of building it yourself.

This is what you need with authentication—you want it done quickly. That way it’ll actually get done rather than sitting in your backlog queue for months until a dev can get to it. Or an attacker can get to your unprotected endpoints.

Next steps? Check out the code for this tutorial [here](https://github.com/argotdev/express-authentication). Check out Clerk [here](/) and more about using Clerk for express and node authentication [here](/docs/request-authentication/nodejs-express), and how to take these security elements even further with the [options](/docs/request-authentication/nodejs-express#middleware-options). Learn how to set up Clerk within your client to make user management super simple [here](/docs/quickstarts/overview).

---

# Secure Authentication in Next.js with Email Magic Links
URL: https://clerk.com/blog/secure-authentication-nextjs-email-magic-links.md
Date: 2023-06-06
Category: Guides
Description: In this guide, you will learn how to implement email magic links in Next.js.

Traditional username and password systems are ubiquitous but mostly suck. Every user needs a complicated random 8-20 character password that they can’t possibly remember for every site. Password managers make this easier, but they are ultimately just papering over the cracks.

Added to this cognitive load for users is the cognitive load for developers, who have to implement these systems securely or constantly worry about their sites becoming targets for malicious activity.

Imagine if you could simplify the user experience, decrease your system’s attack surface, and reduce your workload when it comes to user authentication. This is the promise of [magic links](/blog/magic-links), a powerful approach to passwordless authentication that is rapidly gaining popularity in the world of web development.

Here we want to show you not just the benefits of magic links but how exactly they work, going through an implementation process in Next.js. We’ll also show you why, like most authentication patterns, you don’t want to do this all yourself and how Clerk can help you, just like magic!

## Magical magic links

So, why use magic links? Magic links can greatly improve user experience in several ways:

1. **Ease of use**: Magic links simplify the login process, as users just need to click a link sent to their email to authenticate themselves. They don’t have to remember any usernames or passwords.
2. **Security**: Since there are no passwords to guess, magic links can increase security. This can be especially beneficial for users who often reuse passwords or use weak passwords.
3. **Speed**: Magic links streamline the registration and login process. Rather than having to fill out forms, users just need to enter their email address, then check their inbox and click a link.
4. **Reduced friction**: Magic links eliminate the common frustration of forgotten passwords and the need for password reset processes. 5.**Mobile-friendly**: Typing passwords on mobile devices can be challenging, especially for complex or long passwords. With magic links, users simply click a link in their email, which is much easier on a mobile device.
5. **Trust**: When used properly, magic links can build trust, as they demonstrate a commitment to both user convenience and security.

There are downsides. For one, the user obviously needs to have access to their email. Plus, there is the slight friction element of the user having to leap from the app to their email and back again. In theory, if the user’s email is compromised, an attacker can gain easy access to the app (you can get past this by using [two-factor authentication](/docs/authentication/custom-flows/multifactor) in your authentication flow).

Creating and validating time-sensitive tokens, like those used in magic links, typically involves the following steps:

1. **User Identification**: When the user requests a magic link, your application should first ensure that the email provided is valid and linked to a user account in your system. If the account exists, the server generates a unique, temporary token.
2. **Token Generation**: Generate a unique token using a secure method. This might involve using a secure random number generator or a library or function designed for generating secure tokens, such as JWT (JSON Web Tokens). The token should be associated with the user’s account in your database, along with a timestamp indicating when it was created.
3. **Time-Sensitive Mechanism**: Attach an expiry time to the token. This could be a specific expiry date/time or a duration after which the token will expire. This is usually stored along with the token in the database.
4. **Email Delivery**: Send an email to the user containing the magic link. The link should point to your website or app and include the token as a parameter.
5. **Token Validation**: When the user clicks the magic link, your application should validate the token. This involves checking that the token exists in your database, is linked to a user, and has not expired. If all these checks pass, the user is authenticated.
6. **Token Deletion/Invalidation**: Once a magic link has been used or has expired, it’s important to invalidate it so that it cannot be used again. This can be done by deleting the token from your database or marking it as invalid.

OK, so that’s magic links at a high level. How do you implement them in an application? Let’s go through two ways to do this. Firstly, we’ll show how you can do this with minimal additional libraries in Next.js to show what is required to generate, send, and validate time-sensitive tokens such as magic links. Then we’ll go through how you can implement them quicker and more securely with Clerk.

## Build your own magic links in Next.js

We need to expand the high-level flow above into more granular detail for what we need from our application:

1. **The user enters their email**: The user will enter their email address, which you’ll send to your backend.
2. **Generate a unique token**: On your server, generate a unique token tied to the user’s email. This can be a JWT, a UUID, or some other kind of unique identifier.
3. **Send an email with the magic link**: Include the unique token in the magic link and email it to the user.
4. **User clicks the link**: The user will click the link, which sends the token back to your server.
5. **Verify the token**: On your server, verify that the token is valid and matches the user’s email.
6. **Create a session**: If the token is valid, create a new session for the user and send it back to the client.
7. **Store the session on the client**: On the client, store the session (usually in a cookie or local storage) so that the user remains logged in.
8. **Authorize the user**: Whenever the user makes a request, check that they have a valid session.

So beyond Next.js, for this to work, we need:

- A way to generate and verify our tokens. In this instance, we’re going to use JWT for our tokens and use `jsonwebtoken` to generate and verify them.
- A way to send emails. We’ll use `nodemailer`. You’ll also need SMTP information for your email provider.
- A way to create cookies to store session data. We’ll use the `cookie` library here.

That’s all you need. Let’s first spin up a Next.js app called ‘magic-links’ as the bare bones of what we’ll create:

```bash
npx create-next-app@latest magic-links
```

You’ll be asked a bunch of questions. Here we’re not using TypeScript and neither are we using the App directory (which is the new, better way of using Next.js that we’ll use later. But it doesn’t play as nicely with some of the API routes we’re creating here).

After that we’ll install the necessary packages:

```bash
npm install jsonwebtoken nodemailer cookie
```

You can then run npm run dev to start the development server. At the moment all you’ll get at [http://localhost:3000](http://localhost:3000) is the regular Next.js start page:

![image1.png](./e31247c8534a6bc92acfb54d8be11422ff7c074e-1999x1264.png)

Obviously we need a login component as the first step. We’ll create a /components directory and add a login.js file:

```jsx
// components/login.js

import { useState } from 'react'

function Login() {
  const [email, setEmail] = useState('')

  const handleSubmit = async (e) => {
    e.preventDefault()
    const res = await fetch('/api/login', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ email }),
    })
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} required />
      <button type="submit">Send Magic Link</button>
    </form>
  )
}

export default Login
```

So there are two main parts to this component. At the bottom we have the actual form a user will fill in with their email address. As they type their email in, the state of the `email` variable will change to contain their email address.

When the press ‘Send Magic Link,’ The `handleSubmit` function will be called. This function will call a backend api route, `/api/login`. We’re going to send a POST request to this endpoint with the email address in the body.

Let’s add this to our index page. Delete all the boilerplate code within that file and replace it with:

```jsx
// pages/index.js

import { Inter } from 'next/font/google'
import Login from '../components/login'

const inter = Inter({ subsets: ['latin'] })

export default function Home() {
  return (
    <main
      className={`flex min-h-screen flex-col items-center justify-between p-24 ${inter.className}`}
    >
      <div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex">
        <Login />
      </div>
    </main>
  )
}
```

We’re importing the `Login` component and adding it to this page. Now a user will see this at [http://localhost:3000](http://localhost:3000):

![image8.png](./f92c06581c57df46dfbf7dbd31ce2dafcb0dc877-1999x1264.png)

If they were to add their email into that field and press ‘Send Magic Link,’ guess what would happen?

Absolutely nothing! Let’s make something happen. What we need is that `/api/login` the Login component calls. We’ll create a `login.js` file in the api directory. Though this is within the `pages` directory, it won’t be treated as a page by Next.js, it will act like an API endpoint:

```jsx
// pages/api/login.js

import jwt from 'jsonwebtoken'
import nodemailer from 'nodemailer'

export default async function handler(req, res) {
  const { email } = req.body

  // Create a magic link token
  const token = jwt.sign({ email }, process.env.JWT_SECRET, {
    expiresIn: '15m',
  })

  const transporter = nodemailer.createTransport({
    host: 'mail.example.com',
    port: 587,
    secure: false,
    auth: {
      user: 'username',
      pass: 'password',
    },
  })

  // Generate magic link
  const magicLink = `${req.headers.origin}/api/verify?token=${token}`

  await transporter.sendMail({
    from: '"Your Name" <your-email@example.com>', // sender address
    to: email, // list of receivers
    subject: 'Your Magic Link', // Subject line
    text: `Click on this link to log in: ${magicLink}`, // plain text body
  })

  res.status(200).json({ success: true })
}
```

This is where the first part of the magic of magic links happens. Let’s step through this to see what’s happening:

- First we’re importing the libraries we need, `jsonwebtoken` and `nodemailer`.
- Within our `handler` function, we’ll get the `email` from the body of the request.
- With that email as the payload, we’ll use the sign method from `jsonwebtoken` to create our token. There are two extra parameters we need to pass to sign:
  - A `JWT_SECRET`. You can create a secret (for these purposes, not for production) by running `openssl rand -base64 32` in the terminal to generate a key. You then store that key in a .env file in the root of the project for the project to read.
  - An expiresIn time. Here, we’ve set this to 15 minutes.
- Now we have our token, we need to send it to the user’s email address. Here we’re using the `createTransport` method from `nodemailer` to create an object called a `transporter` that contains all our (i.e. the sender) SMTP email information.
- We’ll then create the actual magic link, which will be the origin URL (our URL) with the token appended as a query.
- Then we’ll call `sendMail` on the `transporter` object to send the email to the recipient

Now if the user presses ‘Send Magic Link,’ they should get an email like this:

![image5.png](./e6395766363d25d1f351680920e1e2f63485d730-1999x221.png)

Now if they click on that guess what would happen?

Absolutely nothing!

We need an endpoint to verify the token and set a cookie on the client with the user's email. First, let’s create another file in the api directory, this one called `verify.js`:

```jsx
// pages/api/verify.js

import jwt from 'jsonwebtoken'
import { serialize } from 'cookie'

export default async function handler(req, res) {
  const { token } = req.query

  try {
    // Verify the token - this throws if the token is invalid
    const { email } = jwt.verify(token, process.env.JWT_SECRET)

    // The token is valid, so we create a session
    const sessionToken = jwt.sign({ email }, process.env.JWT_SECRET, {
      expiresIn: '1h',
    })

    res.setHeader(
      'Set-Cookie',
      serialize('auth', sessionToken, {
        httpOnly: true,
        secure: process.env.NODE_ENV !== 'development', // Use secure cookies in production
        sameSite: 'strict',
        maxAge: 3600, // Expires after 1 hour
        path: '/',
      }),
    )

    // Redirect the user to the homepage
    res.writeHead(302, { Location: '/secrets' })
    res.end()
  } catch (err) {
    // The token was invalid, return an error
    res.status(401).json({ error: 'Invalid token' })
  }
}
```

The top part of this is similar to the API route, but let’s step through the entire thing for clarity:

- First we’re importing the libraries we need, `jsonwebtoken` again and cookie for session management.
- Within our `handler` function, we’ll get the token from the query of the request.
- With that token as the payload, we’ll use the verify method from `jsonwebtoken` to verify our token. This again uses our `JWT_SECRET` that we signed it with to verify.
- If that’s a valid token, we’ll then create a session for the user, again using the `sign` method from `jsonwebtoken`. We set an expiresIn time of an hour. After that, our user will be logged out.
- We add the token to our cookie using `serialize` from the `cookie` library, then add the cookie to the headers of our result.
- We’ll then redirect the user to a logged-in-only page

That page, `/secrets` doesn’t yet exist. Let’s create it in the `/pages` directory:

```jsx
// pages/secrets.js

import { useEffect, useState } from 'react'
import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'] })

export default function Secrets() {
  const [data, setData] = useState(null)

  useEffect(() => {
    // Fetch data from our API route
    fetch('/api/secure-endpoint')
      .then((res) => {
        // If the response was not ok, throw an error
        if (!res.ok) {
          throw new Error('Failed to fetch')
        }
        return res.json()
      })
      .then((data) => {
        setData(data)
      })
      .catch((err) => {
        console.error('An error occurred: ', err.message)
      })
  }, [])

  // Render data or loading message
  return (
    <main
      className={`flex min-h-screen flex-col items-center justify-between p-24 ${inter.className}`}
    >
      <div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex">
        {data ? (
          <>
            <h1>{data.secret}</h1>
            <h2>{data.email}</h2>
          </>
        ) : (
          <p>This isn&apos;t a secret </p>
        )}
      </div>
    </main>
  )
}
```

This will conditionally render either a data object with the fields `secret` and `email` if the user is authenticated, or the text ‘This isn’t a secret’ if they aren’t. The data object comes from a call to our final api endpoint that we need to create, `secure-endpoint.js`:

```jsx
// pages/api/secure-endpoint.js

import jwt from 'jsonwebtoken'

export default function handler(req, res) {
  const { auth } = req.cookies

  if (!auth) {
    return res.status(401).json({ message: 'Unauthorized' })
  }

  try {
    const { email } = jwt.verify(auth, process.env.JWT_SECRET)

    // Now you have the authenticated user's email
    // Do your secure stuff here...

    res.json({ secret: 'This is a secret!', email })
  } catch (error) {
    res.status(401).json({ message: 'Unauthorized' })
  }
}
```

This authorizes the user by verifying with `verify` from `jsonwebtoken` the session token and, if the user is authenticated, passing back an object with a `secret` (‘This is a secret!’) and an `email`. Now if a user fills in their email and clicks on the link, they’ll be sent to the secret page with the `secret` and their `email` showing:

![image4.png](./ca4c4a91d3010cf0e8f4e308548af46cb6233c91-1999x1264.png)

That's it! With these routes, you now have a basic magic link authentication system.

## Using Clerk for your magic links

The above code works. It’s also a terrible idea.

We aren’t doing any error handling. We aren’t checking for any edge cases. We’re not overly protective of our JWT token. If an attacker learns your JWT secret, they can create valid tokens and impersonate any user. There’s no rate limiting. The cookie storage isn’t ideal.

Plus we have to have our own email server that is configured to send out a lot of transactional emails (which regular email providers don’t really like as they get punished for spam). And, yeah, we know, our login and authenticated pages aren’t exactly winning any design awards.

Basically, there are a number of issues with rolling your own magic links.

That’s why services like Clerk’s [Next.js authentication](/nextjs-authentication) exist – to deal with all of the above and make it much easier for developers to implement strong authentication frameworks such as magic links.

We’ll spin up a new Next.js app:

```bash
npx create-next-app@latest magic-links
```

Again, you’ll get the questions. Clerk is written for the latest developments in Next.js, so you can use the App Router.

After that all we need to install is Clerk:

```bash
npm install @clerk/nextjs
```

If we npm run dev now and go to [http://localhost:3000](http://localhost:3000) we again get a regular Next.js start page:

![image3.png](./4bb435f2579af449d2b3fd21d8e9fef9552cc92f-1999x1264.png)

Before we get to the code, we’ll also want to do some other set up. First, we’ll need our NEXT\_PUBLIC\_CLERK\_PUBLISHABLE\_KEY and our CLERK\_SECRET\_KEY. You can get both of these from your [Dashboard](https://dashboard.clerk.com/last-active?path=api-keys).

Add these to an .env file in the root of your project:

```sh
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY = pk_test_xxxx;
CLERK_SECRET_KEY = sk_test_xxxx;
```

We’ll also want to configure our Clerk set up to use magic links. We need to change two settings from the defaults in our dashboard. The first is to choose Email verification link as the authentication factor. To do that, go to **User & Authentication > Email, Phone, Username** in your dashboard:

![CleanShot 2023-06-05 at 15.57.39@2x.png](./540c62b637a385ef8cd77f9cdca5044807fbfe6b-3346x2116.png)

Then go to **Contact information** in that subsection and toggle on **Email address** and check **Email Verification Link**:

![CleanShot 2023-06-05 at 15.56.18 2@2x.png](./cc5d1162222b94bf1c5be87853f1e248bbdfb9d9-3346x2116.png)

Now we can start with the code. The first step is to wrap our entire Next.js application in the `<ClerkProvider>`:

```tsx
// app/layout.tsx
import './globals.css'
import { Inter } from 'next/font/google'
import { ClerkProvider } from '@clerk/nextjs'

const inter = Inter({ subsets: ['latin'] })

export const metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <ClerkProvider>
      <html lang="en">
        <body className={inter.className}>{children}</body>
      </html>
    </ClerkProvider>
  )
}
```

This is going to provide all we need to pass session and user information to Clerk for the authentication logic. This step is the same for any authentication pattern you are going to use with Clerk in Next.js.

The next step is to use Clerk to protect pages within our application. To do this, we’ll create a file in the `/src` directory. This will use regular expressions to pattern match against the pages you want to protect. Here, we’re going to protect all our pages:

```javascript
//middleware.ts

import { authMiddleware } from '@clerk/nextjs'
export default authMiddleware()
export const config = {
  matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'],
}
```

Now if you load up [http://localhost:3000](http://localhost:3000), you’ll be redirected to a login/signup page:

![image9.png](./8d71d81b4d43e75cc90dd58eb82a086bbcfac4d8-1999x1264.png)

A user enters their email address here and gets sent a link to click:

![image7.png](./b9be271aeb2174a5c010fa2b21b2cfc74dac7d07-1999x965.png)

Clicking on that link sends them back to [http://localhost:3000](http://localhost:3000), but now they can access the site again:

![image3.png](./4bb435f2579af449d2b3fd21d8e9fef9552cc92f-1999x1264.png)

Much easier (and much better looking signup pages and emails as well!)

## Better security and a user experience with magic links

Magic links can really help you streamline your sign up and sign in processes. They lessen the burden on your users while providing strong security for them and your application.

But implementing them manually puts the burden on your developers. Managing creation and validation of the tokens, sending emails (and maintaining the system to do so), then coding up the right modals, pages, error states, and edge cases is a huge hassle.

It’s worth developers going through and trying this manually just to see how magic links are implemented. But if you are looking for a production-ready option that you can incorporate into your app today, you can use [Clerk](/).

---

# Generating and Using UUIDs in React
URL: https://clerk.com/blog/generating-and-using-uuids-in-react.md
Date: 2023-04-20
Category: Guides
Description: Learn the significance of UUIDs in full-stack apps, their optimal usage, and how to implement them in React apps.

When working with full-stack apps, you will often come across identifiers. Also known as IDs, identifiers are used to identify data records related to apps. Based on the sensitivity and scope of the data in question, the identifier can be set as locally or globally unique. A popular globally unique identifier is UUID, which stands for *universally unique identifier*.

In this article, you will learn what UUIDs are, when to use them, and how to get started with implementing them in your React app.

## What Are UUIDs and When Are They Used?

UUIDs are a popular and safe method of generating globally unique identifiers for data records. It's said that there's a [one-in-a-billion chance of two randomly generated UUIDs matching exactly](https://en.wikipedia.org/wiki/Universally_unique_identifier#:~:text=Thus%2C%20the%20probability%20to%20find,is%20one%20in%20a%20billion) in a set of 103 trillion UUIDs, which is small enough to say that UUIDs are practically unique.

UUIDs are also better than sequential identifiers when it comes to parallel data insertion in databases as you don't need to adhere to a sequence to create keys and insert records.

A UUID is formatted like this: `2a6db6e1-8967-4511-9839-a7cb3c895710`.

There are a total of thirty-two hexadecimal characters separated into sets of 8-4-4-4-12 characters, which are themselves separated by hyphens. However, these thirty-two characters cannot be randomly generated and put together to create a UUID. In order for an ID to be universally unique—and therefore be called a UUID—it needs to be [compliant with the RFC 4122 protocol](https://www.cryptosys.net/pki/uuid-rfc4122.html).

UUIDs have multiple use cases, the most prominent of which include the following:

- To identify records uniquely across tables
- When two tables are merged, as UUIDs remain unique to avoid confusion
- When parallel insertion is needed, as sequential IDs can be created in parallel

A number of third-party libraries and functions are available to make it simpler for developers to implement UUIDs in apps. In the following section, you'll see multiple ways to implement UUIDs in a React app.

## Generating UUIDs in Your React Application

Now that you understand what UUIDs are (and when you might use them), let's move on to how you can implement them in your React apps. First, you will create a boilerplate form, then learn how to set up a UUID on that form in four different ways.

Each of these methods will use the same protocol to generate UUIDs that are globally unique. Which one you use, however, will depend on your use case and preferences.

The first two will require external dependencies that may make developer experience better but add a performance overhead and/or weight to the app size. The third method will use an inbuilt function from the `crypto` package (which may or may not be available depending on the JavaScript environment), and the last method will use a raw algorithm to create UUIDs manually in app, adding no weight or performance overhead to your app but requiring manual setup and maintenance.

You can find the complete source code of the demo app in this [GitHub repo](https://github.com/krharsh17/react-uuid-demo).

### Prerequisites

To proceed with this tutorial, you need to have [npm installed](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) on your system.

Next, you'll need to set up a new React project. Run the following command:

```sh
npx create-react-app react-uuid-demo
```

Once the new React project is created, run the following commands to start the development server:

```sh
cd react-uuid-demo
npm start
```

This is what the output should look like.

![Generating And Using Uuids In React guide illustration](./cb0f1846dd3b84dbe27c108ff7ed6c7420992d7a-2000x1310.png)

You will install the dependencies as required later on.

### Create a Simple Page with User Information

To ease your familiarity with the concepts, you'll create a basic boilerplate form that asks for a username and email and allows users to generate a UUID for themselves. Here's what the form will look like.

![Generating And Using Uuids In React guide illustration](./5878f82d4a51af6fbbd163e2b42d20f13fd7b8fc-2000x1089.png)

The **Generate UUID** button will be enabled once the user fills in the form data.

To set it up, you'll need to paste the following code snippet into your **App.js** file:

```jsx
import './App.css'
import { useState } from 'react'

export default function App() {
  // define state containers
  const [name, setName] = useState('')
  const [email, setEmail] = useState('')
  const [id, setId] = useState('')

  // Define listener for button click event. You will use this function to generate UUIDs later
  const onGenerateButtonClick = () => {
    console.log('Button clicked')
  }

  return (
    <div className={'mainContainer'}>
      <div className={'titleContainer'}>
        <div>Create your profile</div>
      </div>

      {/* Name input field */}
      <div className={'inputContainer'}>
        <input
          value={name}
          placeholder="Enter your full name"
          onChange={(ev) => setName(ev.target.value)}
          className={'inputBox'}
        />
        <br />
      </div>

      {/* Email input field */}
      <div className={'inputContainer'}>
        <input
          value={email}
          placeholder="Enter your email"
          onChange={(ev) => setEmail(ev.target.value)}
          className={'inputBox'}
        />
        <br />
      </div>

      {/* Button to generate UUIDs */}
      <div className={'buttonContainer'}>
        <input
          type={'button'}
          disabled={!(name !== '' && email !== '')}
          value={'Generate UUID'}
          onClick={onGenerateButtonClick}
          className={'inputBox'}
        />
        <br />
      </div>

      {/* UUID box */}
      <div className={'inputContainer'}>
        <input
          value={id}
          placeholder="UUID"
          disabled={true}
          onChange={(ev) => setId(ev.target.value)}
          className={'inputBox'}
        />
        <br />
      </div>
    </div>
  )
}
```

To add some basic styling so that the form looks like the one shown in the image above, you'll need to paste the following code snippet into your `App.css` file:

```css
.mainContainer {
  flex-direction: column;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
}

.titleContainer {
  display: flex;
  flex-direction: column;
  font-size: 64px;
  margin-bottom: 32px;
  font-weight: bolder;
  align-items: center;
  justify-content: center;
}

.inputContainer {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.buttonContainer {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin-bottom: 40px;
}

.inputBox {
  height: 48px;
  width: 400px;
  font-size: large;
  border-radius: 8px;
  border: 1px solid grey;
  padding-left: 8px;
}
```

You'll also need to update the styles in `index.css` with the following code to complete the styling of the app:

```css
html,
body {
  padding: 0;
  margin: 0;
  font-family:
    -apple-system,
    BlinkMacSystemFont,
    Segoe UI,
    Roboto,
    Oxygen,
    Ubuntu,
    Cantarell,
    Fira Sans,
    Droid Sans,
    Helvetica Neue,
    sans-serif;
}

* {
  box-sizing: border-box;
}

main {
  padding: 5rem 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

code {
  background: #fafafa;
  border-radius: 5px;
  padding: 0.75rem;
  font-family:
    Menlo,
    Monaco,
    Lucida Console,
    Courier New,
    monospace;
}

input[type='button'] {
  border: none;
  background: cornflowerblue;
  color: white;
  padding: 4px 12px;
  border-radius: 12px;
  cursor: pointer;
}

input[type='button']:disabled,
input[type='button'][disabled] {
  border: 1px solid #999999;
  background-color: #cccccc;
  color: #666666;
}
```

If you run the app now, it should look like the one in the image shared above.

### Create UUIDs Using Different Methods

Now that your base app is ready, you'll see how to create UUIDs using `uuidv4`, `react-uuid`, `crypto.randomUUID()`, and finally, through code.

### Using uuidv4

The first and quite popular method of generating UUIDs in JavaScript-based apps is with the [uuid](https://www.npmjs.com/package/uuid) npm package. You can install it in your React app by running the following command:

```sh
npm i uuid
```

You'll need to import it into your app by adding the following line of code below the existing imports in your `App.js` file:

```jsx
import { v4 as uuid } from 'uuid'
```

You can now use the following function to generate UUIDs using this package:

```jsx
const uuidFromUuidV4 = () => {
  const newUuid = uuid()
  setId(newUuid)
}
```

*Note:* You'll need to paste this function in your `App` component right below the `onGenerateButtonClick()` function.

Finally, you'll need to replace the `onGenerateButtonClick` function in your `App` component with the code below to call this method when the **Generate UUID** button is clicked:

```jsx
const onGenerateButtonClick = () => {
  uuidFromUuidV4()
}
```

Once you've done this, you can see it in action by going to `http://localhost:3000` and filling out the form.

### Using react-uuid

Another popular method for React apps to implement UUID is by using the npm package [react-uuid](https://www.npmjs.com/package/react-uuid). Both the `react-uuid` and `uuidv4` packages can be implemented seamlessly in React; their main difference is that `react-uuid` was designed specifically for React apps while `uuidv4` was primarily meant for Node.js apps.

You can install the package in your project by running the following command:

```sh
npm i react-uuid
```

Next, you'll need to import the package in your source code by adding the following import line at the top of your `App.js `file (below the existing imports):

```jsx
import uuid from 'react-uuid'
```

You can now use the following function to generate UUIDs using this package:

```jsx
const uuidFromReactUUID = () => {
  const newUuid = uuid()
  setId(newUuid)
}
```

*Note:* You'll need to paste this function in your `App` component.

To call this function when **Generate UUID** is clicked, you'll need to update the code for the `onGenerateButtonClick` function with the following:

```jsx
const onGenerateButtonClick = () => {
  uuidFromReactUUID()
}
```

Once you're done with the steps above, you can see this function in action.

### Using crypto.randomUUID()

The inbuilt `crypto` package in JavaScript runtimes can be used to generate UUIDs. Here's a function that uses `crypto.randomUUID()` to generate a UUID:

```jsx
const uuidFromCrypto = () => {
  const newUuid = crypto.randomUUID()
  setId(newUuid)
}
```

You don't need to include any imports for this to work. However, this method only works over secure contexts ([local or HTTPS](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API)). Here's how you can update your `onGenerateButtonClick` function to use this method in your app:

```jsx
const onGenerateButtonClick = () => {
  uuidFromCrypto()
}
```

The result is similar to the other methods seen so far.

### Through Code

Perhaps you prefer not to install any third-party libraries to implement UUID and the `crypto.randomUUID()` doesn't suit your use case. If so, you can use a method that relies on another function from the `crypto` package to generate RFC 4122–compliant UUIDs in your source code:

```javascript
const uuidFromCode = () => {
  const newUuid = ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
    (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16),
  )
  setId(newUuid)
}
```

Based on a [Stack Overflow answer](https://stackoverflow.com/a/2117523), this method fits most UUID-related use cases perfectly. Since it uses `crypto.getRandomValues()` instead of `Math.random()`, you can rest assured that the UUIDs generated using this method will be practically globally unique.

Here's how your `onGenerateButtonClick` function should look like using this method:

```javascript
const onGenerateButtonClick = () => {
  uuidFromCode()
}
```

The result will again look similar to the methods discussed above. Once you've filled in the form, you can keep clicking **Generate UUID** in order to generate new UUIDs.

As mentioned, you can find the complete source code of the demo app used in the tutorial [here](https://github.com/krharsh17/react-uuid-demo).

## Conclusion

UUIDs are handy when it comes to identifying records uniquely across tables globally. With an infinitesimal chance of collision, UUIDs present you with a robust solution to the global identification problem. In this article, you saw four different methods of implementing a UUID in your React app.

UUIDs are used in many third-party tools internally too. It's essential that the third-party dependencies you include in your app create UUIDs reliably to ensure the proper functioning of your app.

[Clerk](/) is an auth provider that makes it easy to add authentication and user management to your application. As for its data, Clerk uses [K-Sortable Globally Unique IDs, or KSUIDs,](https://github.com/segmentio/ksuid) for generating unique identifiers. These extend UUIDs to add time-based ordering and friendlier representation formats for simplicity. If you're looking for an auth solution for your app, make sure to [check out Clerk](https://dashboard.clerk.com/sign-up)!

---

# Setting and Using Cookies in React
URL: https://clerk.com/blog/setting-and-using-cookies-in-react.md
Date: 2023-04-14
Category: Guides
Description: Learn how to set up cookies in React with this guide! You'll create a login page and store user information using cookies.

Web cookies consist of data generated by a server and sent to a user's web browser (such as Chrome or Firefox). These small pieces of information are then stored by the website on the user's device. Cookies can be used to keep track of things like items in a shopping cart. If the user leaves the website and comes back later, the items will still be there waiting for them.

They can also be used for security purposes, such as user authentication, and for tracking a user's behavior, which allows websites to personalize the user's experience. For instance, if a user logs out of your site, they can simply log back in without needing to enter their username and password again. It's important to note, however, that cookies can be stolen by hackers who can use them to impersonate the user on your website.

In this article, you'll explore how to set up cookies in a ReactJS application. You'll create a [simple login page](/blog/building-a-react-login-page-template) and use cookies to store information about the user's logged-in session.

> For secure cookie management and session handling, [learn more about our React support](/react-authentication).

## What Are Web Cookies?

As mentioned, web cookies are small pieces of data that are stored on a user's computer by a website. They're typically used to store information about the user, such as their preferences, login information, and other data. Cookies are created and stored by the website when the user visits the site. The website can then retrieve the cookies from the user's computer when they visit the site again, allowing the website to "remember" the user and their preferences.

Cookies are typically stored in plain text, which means that they can be read and modified by anyone who has access to the user's computer. Therefore, it's important to use cookies carefully and securely to protect the user's data.

Before you start the tutorial below, make sure you have [npm and Node.js installed](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) on your machine. Once this is done, you can begin working on your React application.

## Set Up Your React Application

Open a terminal and create a new React application using the following command: `npx create-react-app my-app`. Once the application is created, open the directory with your favorite code editor (such as VS Code) and start working on your application. You'll see a bunch of files and folders that look like the image below.

![Setting And Using Cookies In React guide illustration](./d8c90582f6e552dc9d106a689e443d62fa2ad78a-2000x1140.png)

To test that your React application is properly set up, open a terminal and navigate to the `my-app` project folder. Start the server by running `npm start`; open your web browser and enter the specified port in the terminal (`3000`) to view your React application.

By completing these steps, you can verify that your React application is running as expected. You can then proceed with writing code and building your application without any issues. You should see a web page like the image below.

![Setting And Using Cookies In React guide illustration](./8670f2974e4e75421a43abce7a396b50109abe56-2000x917.png)

## Create a Simple Welcome Page

In your React project, create a new file called `WelcomePage.js` inside the `src` folder and add the following code inside:

```jsx
import React from 'react'

export default function WelcomePage() {
  return <div>WelcomePage</div>
}
```

To render the welcome page, first navigate to the `App.js` file inside the `src` folder. Import the `WelcomePage.js` file using the following code:

```jsx
import WelcomePage from './WelcomePage.js'
```

Then, inside the return statement, remove everything and add this code:

```jsx
<WelcomePage />
```

In the above instructions, you imported the `WelcomePage.js` file and used the `<WelcomePage />` tag inside the return statement of the `App.js` file. This allows the `App.js` file to render the welcome page in a web browser. When the page is rendered, you should see a white page with the word "WelcomePage" on it.

## Create a Login Page

Create another file inside the src folder called `LoginPage.js` and add the following block of code:

```jsx
import React, { useState } from 'react'

function LoginPage({ onLogin }) {
  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')

  function handleSubmit(event) {
    event.preventDefault()
    onLogin({ username, password })
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Username:
        <input type="text" value={username} onChange={(e) => setUsername(e.target.value)} />
      </label>
      <br />
      <label>
        Password:
        <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
      </label>
      <br />
      <input type="submit" value="Submit" />
    </form>
  )
}

export default LoginPage
```

This `LoginPage` component has fields for a username and a password as well as a submit button. When the user fills out the form and clicks Submit, the `onLogin` callback function is called with their username and password. The parent component (`App` in this case) can then use this information to set the user cookie and render the `WelcomePage` component.

## Set Up Cookie Handling

To use cookies in your app, you'll need to import the react-cookie library from the React library. This library allows you to set, get, and delete cookies in your app.

First, install the library by running the command `npm install react-cookie` in the root folder of your app in the terminal.

Now change your **App.js** file to match the following code:

```jsx
import React from 'react'
import WelcomePage from './WelcomePage.js'
import LoginPage from './LoginPage.js'
import { CookiesProvider, useCookies } from 'react-cookie'

function App() {
  const [cookies, setCookie] = useCookies(['user'])

  function handleLogin(user) {
    setCookie('user', user, { path: '/' })
  }

  return (
    <CookiesProvider>
      <div>
        {cookies.user ? <WelcomePage user={cookies.user} /> : <LoginPage onLogin={handleLogin} />}
      </div>
    </CookiesProvider>
  )
}

export default App
```

In the code above, the `App` component uses the `useCookies` hook to manage cookies. The `handleLogin` function is called when a user logs in, and it sets a cookie named "user" with the user's information.

The `LoginPage` and `WelcomePage` components are wrapped in the `CookiesProvider` component, which provides a global context for cookies. This allows the `WelcomePage` component to access the user cookie and display the user's information.

The `App` component uses a ternary operator to decide which component to render based on the presence of the user cookie. If the cookie exists, the `WelcomePage` component is rendered. If the cookie does not exist, the `LoginPage` component is rendered instead.

Now, if you check your page on your browser, you should see a login form that looks like the image below.

![Setting And Using Cookies In React guide illustration](./c4cf9f020742bf3b2413a6b041d8a5f11e5ff057-2000x929.png)

Before you test your application, first change the `WelcomePage.js` file to match the following block of code:

```jsx
import React from 'react'

function WelcomePage({ user }) {
  return <h1>Welcome, {user.username}!</h1>
}

export default WelcomePage
```

This `WelcomePage` component simply displays a welcome message with the user's username. It receives the user object as a prop, which contains the user's username and password. The parent component (`App` in this case) passes the user object to the `WelcomePage` component when `WelcomePage` is rendered.

## Test Your Application

To test your application, go to the browser and fill in the login form with your username and password. When you click **Submit**, the welcome page should be displayed with the words "Welcome" followed by your username. This indicates that the login was successful and the `WelcomePage` component was rendered. It should look like the image below.

![Setting And Using Cookies In React guide illustration](./d5d11e71535fcdefecf7fc0c2a5e362a4cbfcade-2000x654.png)

To check if a cookie has been set in your Chrome browser, you can use the developer tools. Open your browser, and if you're on Chrome, go to the page where the cookie is set by pressing F12 on your keyboard to open the developer tools.

Click on the **Application** tab in the developer tools. In the left panel, expand the **Cookies** section and click on the domain where the cookie is set—in this case, it's `http://localhost:3000`. In the right panel, you should see a cookie that has been set for the domain like in the image above.

You can find the complete code for this tutorial on [GitHub](https://github.com/gitnyasha/using-cookies-in-react).

## Conclusion

In this tutorial, you learned how to create a login page and a welcome page in a React app and how to store the user's login information in a cookie. You also learned how to only display the welcome page if the user is logged in and how to check if a cookie has been set in the Chrome browser.

Using cookies in a React app can make the login process more user-friendly as it allows users to access the welcome page without having to enter their login information every time they visit the page.

Clerk provides an easy way to add authentication and user management to your application. Clerk handles session management, including setting cookies on your behalf, saving you time and effort. This allows you to focus on building the features of your app without having to worry about implementing the authentication and session management features from scratch. [Give Clerk a try by signing up today](https://dashboard.clerk.com/sign-up).

---

# Adding JWT Authentication to React
URL: https://clerk.com/blog/adding-jwt-authentication-to-react.md
Date: 2023-04-14
Category: Guides
Description: Learn how to implement JSON Web Token (JWT) authentication in a React app using a standard flow, and how Clerk can make the process even easier.

JSON Web Token (JWT) authentication is a method of securely authenticating users and allowing them to access protected resources on a website or application. It's a popular and widely used method of web authentication as it allows for easy and secure user authentication without the need for the server to maintain a session state.

In this process, the server generates a signed JWT and sends it to the client. The client then includes this token in subsequent requests to the server to authenticate themselves. The JWT is usually stored in the browser's localStorage and sent as part of the request's headers.

However, the JWT mechanism can be arduous and error-prone, especially if you're building it from scratch. In this article, you'll learn how to implement JWT in a React application using a standard flow, and then you'll see how much easier it gets when repeating the exercise using [Clerk's React authentication](/react-authentication).

## What Is JWT Authentication?

Before we discuss how a user is authenticated with JWT, let's take a closer look at what it contains:

1. `The header:` consists of two parts—the token type, which is JWT, and a signing algorithm, such as HMAC-SHA256 or RSA
2. `The payload:` contains the claims—in other words, the statements about an entity (typically, the user) and additional data
3. `The signature:` used to verify the JWT's integrity

To authenticate a client using JWT, the server first generates a signed JWT and sends it to the client. The client then includes the JWT in the header (usually the [authorization header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization)) of subsequent requests to the server.

The server then decodes the JWT and verifies the signature to ensure that a trusted party sent it. If the signature is valid, the server can then use the information contained in the JWT to authenticate the client and authorize their access to specific resources. The diagram below shows a standard JWT authentication flow.

![JWT authentication flow](./ce92a5f67e79db690f9dffa38d625decebf8da3e-2025x1178.png)

### Advantages and Downsides of Using JWT

Using JWT authentication offers the following advantages:

1. `JWT authentication is stateless:` A JWT contains all the information regarding the user's identity and authentication, including the claims. This can be more efficient than storing session information on the server as it reduces the amount of data that needs to be stored and retrieved for each request.

2. `Create anywhere:` Another advantage of JWT authentication is that the token can be generated from anywhere, including external services or third-party applications. This allows for flexibility in terms of where and how the token is generated, which can be useful in a microservices architecture where different services may need to authenticate users.

3. `Fine-grained access control:` JWT can contain information about the user's role and permissions in the form of claims. This gives the application developers a lot of control over what actions a user is allowed to take.

However, there are also some disadvantages to using JWT authentication:

1. `Hard to invalidate:` Invalidating JWTs is only possible if you maintain a list on a shared database, which introduces additional overhead. The database is necessary because if you need to revoke a token or if a user's permissions change, the server won't otherwise be able to determine the status of the token and might give access when it shouldn't. If the JWTs you're using are long-lived—in other words, they have a very long (or no) expiration time specified—it becomes even more important that they're stored in an accessible database.

2. `Size and security concerns:` JWTs can sometimes contain unnecessary information that might be useless for the application and, at the same time, make the token larger and more cumbersome to work with. If the JWT is unencrypted, it can also end up revealing too much about the user.

Given these challenges, some would say that using cookies over JWT works better in some instances as a method of authentication; for example, when the application needs to keep track of the user's activity across multiple pages, as cookies can be easily read and written on the server side. Let's compare the two in detail.

### Are Cookies Better Than JWT?

To start with, you can create session-based cookies, which automatically expire after the user session is closed, or you can easily set an expiration time for a cookie, which gives more control over session invalidation. You can also use HttpOnly cookies to prevent JavaScript from accessing the cookie information.

However, it's important to note that cookies come with their own flaws. Specifically, as the cookie data is stored on the server and the cookie identifier is stored on the client, they're not entirely stateless like JWTs. This means that the server needs to store and retrieve the cookie data for each request, which would be additional overhead to the authentication process and slow down the application's performance, especially if the number of concurrent users increases.

They're also not ideal for non-browser-based applications, such as mobile and desktop applications. Additionally, cookies can be more vulnerable to certain attacks, such as [cross-site scripting (XSS)](https://owasp.org/www-community/attacks/xss) and [cross-site request forgery (CSRF)](https://owasp.org/www-community/attacks/csrf).

Now that we've covered the advantages and some of the potential challenges of JWT authentication, let's see the process in action. In the following section, you'll see how to implement JWT authentication in your React application.

## Implementing JWT Authentication in Your React Application

In this tutorial, you'll build a simple full-stack application with [authentication in Next.js](/nextjs-authentication). Next.js allows you to implement frontend applications using React and a backend API server without setting up another Node.js project. You'll also understand the pitfalls of creating a JWT authentication from scratch and learn to overcome those limitations using the Clerk SDK.

> For pure React applications (without Next.js), check out our [React authentication solution](/react-authentication) which handles JWT and other auth methods seamlessly.

The application stores the key to the user's safehouse (a protected resource) and uses JWT authentication to verify their identity. The application shows the user a welcome page, where they can sign in with a username and password. It generates a JWT for the user, which they can use to verify their identity. Once signed in, users will see their safehouse's secret key by exchanging the JWT with the server.

Before you begin, you'll need a code editor like [Visual Studio Code](https://code.visualstudio.com/download). You'll also need Node.js (version 16 or newer) and npm installed. If you want to check out the completed application, you can clone this [GitHub repository](https://github.com/Anshuman71/clerk-jwt-example).

### Setting Up the Project

To set up a Next.js project, run the following command:

```bash
npx create-next-app clerk-jwt-example
```

You'll be prompted on whether you'd like to use TypeScript and ESLint. For simplicity, choose `No` for TypeScript and then `Yes` for ESLint.

After you complete the npm installation, open the project in your code editor and change the directory to the project by running `cd clerk-jwt-example` in your terminal.

To use the browser's default styling, remove all existing styles from `styles/globals.css` and `styles/Home.module.css`.

### JWT Authentication Using a Standard Flow

In this example, you'll create two pages: `/jwt-home` and `jwt-safehouse`. The former will be the [login page](/blog/building-a-react-login-page-template) to collect credentials, and the latter will be the secured page showing secret information.

More specifically, the `/jwt-home` page accepts the user credentials and requests the `/api/auth` API endpoint to generate the signed JWT. The application stores the returned JWT in localStorage as the `jwt-token` key. The `/jwt-safehouse` acts as the secured page and requests the secret information from the `/api/safehouse` API endpoint in exchange for the signed JWT. The `/jwt-safehouse` page then displays the secret information to the signed-in user.

In Next.js, you can create a new application route by creating a new file with the route name under the `pages/` folder. Similarly, to create a new API endpoint, you need to create a new file under the `pages/api/` folder.

#### Update the Application Home Page

To access different parts of your application, update the application home page (`pages/index.js`) to show links to other pages in the application. The code below uses the `Link` component from `next/link`, which is the Next.js version of the `<a>` tag:

```jsx
import Link from 'next/link'

export default function Home() {
  return (
    <div>
      Home
      <br />
      <ol>
        <li>
          <Link href={'/jwt-home'}>JWT Home</Link>
        </li>
        <li>
          <Link href={'/jwt-safehouse'}>JWT Safe house</Link>
        </li>
      </ol>
    </div>
  )
}
```

Now start the application by running `npm run dev` in the terminal. Open `http://localhost:3000` in a web browser to see the application. You'll see the page, as shown below.

![Initial layout](./16fed00772a7f2c1491216696a6e9303ee7a7121-1606x900.png)

#### Create a Signed JWT

To create a signed JWT, you first need to install the `jsonwebtoken` package. `jsonwebtoken` provides utilities to sign and verify JWTs. Run `npm i jsonwebtoken` to install the package in your project.

You'll need a JWT signing secret to use with `jsonwebtoken`. For this, create a new file, `.env.local`, to store the application's secret credentials. In this file, add a new environment variable, `DIY_JWT_SECRET`, with a random hash string as a value:

```txt
DIY_JWT_SECRET=2182312c81187ab82bbe053df6b7aa55
```

To generate the signed JWT with the user's `signInTime` and `username`, create an API route `/api/auth` by creating the new file `pages/api/auth.js`. The API route accepts the user credentials, and if the provided password is `pikachu`, it returns a `200` response with the signed JWT. Otherwise, it returns a `401` response with an error message:

```js
import jwt from 'jsonwebtoken'

export default function handler(req, res) {
  const jwtSecretKey = process.env.DIY_JWT_SECRET
  const { username, password } = req.body
  // confirm if password is valid
  if (password !== 'pikachu') {
    return res.status(401).json({ message: 'Invalid password' })
  }
  let data = {
    signInTime: Date.now(),
    username,
  }

  const token = jwt.sign(data, jwtSecretKey)
  res.status(200).json({ message: 'success', token })
}
```

#### Create a Login with JWT

Now that the `/api/auth` API endpoint is ready, create the new file `pages/jwt-home.jsx` and implement a login form component to send user credentials to `/api/auth`.

The code below implements a React component, `Home`, that displays a form to collect the user credentials and, on form submission, makes an HTTP POST request to the `/api/auth` endpoint with the collected credentials.

If the response message is `success`, it saves the received JWT in localStorage under the `jwt-token` key. Otherwise, it shows a browser alert with the response message:

```jsx
import { useState } from 'react'
import { useRouter } from 'next/router'

export default function Home() {
  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')
  const router = useRouter()

  function submitUser(event) {
    event.preventDefault()
    fetch('/api/auth', {
      method: 'POST',
      headers: {
        'content-type': 'application/json',
      },
      body: JSON.stringify({ username, password }),
    })
      .then((res) => res.json())
      .then((data) => {
        if (data.message === 'success') {
          localStorage.setItem('jwt-token', data.token)
          setUsername('')
          setPassword('')
          router.push('/jwt-safehouse')
        } else {
          alert(data.message)
        }
      })
  }
  return (
    <>
      <main style={{ padding: '50px' }}>
        <h1>Login </h1>
        <br />

        <form onSubmit={submitUser}>
          <input
            value={username}
            type="text"
            placeholder="Username"
            onChange={(e) => setUsername(e.target.value)}
          />
          <br />
          <br />

          <input
            value={password}
            type="password"
            placeholder="Password"
            onChange={(e) => setPassword(e.target.value)}
          />
          <br />
          <br />

          <button type="submit">Login</button>
        </form>
      </main>
    </>
  )
}
```

![JWT flow login page](./63ecc4b12a117163fbd6f89f7b2eaba5c5cd44e9-1604x900.png)

#### Exchange the JWT for the Secret Data

The next step is to implement an API endpoint to verify the JWT from the incoming request header. If it's valid, the endpoint should return a `200` response with the secret data; otherwise, it will return a `401` response with an error message.

Create a new file, `pages/api/safehouse.js`. In this file, copy and paste the following code to verify the incoming JWT from the `jwt-token` request header:

```js
import jwt from 'jsonwebtoken'

export default function handler(req, res) {
  const tokenHeaderKey = 'jwt-token'
  const jwtSecretKey = process.env.DIY_JWT_SECRET
  const token = req.headers[tokenHeaderKey]
  try {
    const verified = jwt.verify(token, jwtSecretKey)
    if (verified) {
      return res.status(200).json({ safehouseKey: 'under-the-doormat', message: 'success' })
    } else {
      // Access Denied
      return res.status(401).json({ message: 'error' })
    }
  } catch (error) {
    // Access Denied
    return res.status(401).json({ message: 'error' })
  }
}
```

#### Display the Safehouse Secret Data

The final step in the flow is to request the secret data from the `/api/safehouse` API endpoint and display it if the JWT is valid.

To show the secret safehouse data, create the new file `pages/jwt-safehouse.jsx` with the following code:

```jsx
import { useEffect, useState } from 'react'
import Link from 'next/link'

export default function SafeHouse() {
  const [token, setToken] = useState('')
  const [userData, setUserData] = useState({})

  useEffect(() => {
    const token = localStorage.getItem('jwt-token')
    setToken(token)
    fetch('/api/safehouse', {
      headers: {
        'jwt-token': token,
      },
    })
      .then((res) => res.json())
      .then((data) => setUserData(data))
  }, [])

  function logout() {
    setToken('')
    localStorage.removeItem('jwt-token')
  }

  if (!token) {
    return (
      <>
        <main style={{ padding: '50px' }}>
          <p>You&apos;re not logged in.</p>
          <Link href={'/jwt-home'}>Home</Link>
        </main>
      </>
    )
  }

  return (
    <>
      <main style={{ padding: '50px' }}>
        <h1>Safehouse </h1>
        <p>
          You Safehouse key is <strong>{userData?.safehouseKey || 'Loading...'}</strong>
        </p>
        <button onClick={logout}>Logout</button>
      </main>
    </>
  )
}
```

The above code implements a `SafeHouse` component that renders the secret data if the JWT is available in localStorage. Otherwise, it prompts the user to log in with a link to the `/jwt-home` page.

The component gets the `jwt-token` from localStorage and makes a `fetch` request to the `/api/safehouse` in the `useEffect` hook that runs on the initial render in the browser.

The `Logout` button triggers the `logout()` function that clears the `token` state variable and removes the localStorage item.

The standard JWT authentication flow is ready.

Note that the solution you implemented above is very naive for a number of reasons. First, to make this system work, you'll need to implement and maintain additional code to track any updates to the JWT and pass the JWT in the request headers.

Next, you can't invalidate the stored JWT from outside the user's browser, which is a critical security issue—if a user's account is suspended or deleted, a JWT issued before that action would still be valid and could be used to authenticate as that user.

Further, if a user's password is changed, a JWT that was issued before the password change would still be valid and could be used to authenticate as the user with the old password.

### Authentication Using Clerk

By using the [Clerk](/) SDK, you can overcome the limitations discussed above. In the following section, you'll find the steps to implement a more secure and scalable solution for your JWT authentication while retaining the same functionality.

#### Set Up the Clerk SDK

Below are the steps to setting up the Clerk SDK:

1. Sign up for a [free account on Clerk.com](https://dashboard.clerk.com/sign-up).

2. On your [Clerk dashboard](https://dashboard.clerk.com), click `Add application` to create a new application.

3. In the Application name field, type in "JWT Example" and click `Finish`.

   ![Create new Clerk application](./9bc39e68dcb1236d17db7bf4602b43485385313c-2520x1816.png)

4. On the application dashboard, click on `API Keys` in the left navigation. Then copy the `Frontend API key`, `Backend API key`, and `JWT verification key`.

   ![Copy Clerk credentials](./5eb8d5a378ea0897a7c10b8581d0b9b8a4d7db8b-3154x1628.png)

5. Save the keys in the file `.env.local` inside your project:

   ```
   NEXT_PUBLIC_CLERK_FRONTEND_API=<frontend-key>
   CLERK_API_KEY=<backend-api-key>
   CLERK_JWT_KEY=<jwt-verification-key>
   ```

6. Install the Clerk SDK by running `npm i @clerk/nextjs` inside your project.

7. Add the `ClerkProvider` in the `pages/_app.js` file to use the authentication state throughout the application:

   ```jsx
   import { ClerkProvider } from '@clerk/nextjs'

   export default function App({ Component, pageProps }) {
     return (
       <ClerkProvider {...pageProps}>
         <Component {...pageProps} />
       </ClerkProvider>
     )
   }
   ```

#### Implement Sign In and Sign Up

With the Clerk SDK installed, you can easily set up your sign-in and sign-up pages.

*Note:* In Next.js, files named `pages/sign-in/[[...<anything>]].jsx` create a catch-all route that will match /sign-in, /sign-in/a, /sign-in/a/b, and so on.

For the sign-in page, create the new file `pages/sign-in/[[...index]].jsx` and use the prebuilt `<SignIn>` component from `@clerk/nextjs`:

```jsx
import { SignIn } from '@clerk/nextjs'

export default function SignInPage() {
  return <SignIn path="/sign-in" routing="path" signUpUrl="/sign-up" />
}
```

For the sign-up page, create the new file `pages/sign-up/[[...index]].jsx` and use the prebuilt `<SignUp>` component from `@clerk/nextjs`:

```jsx
import { SignUp } from '@clerk/nextjs'

export default function SignUpPage() {
  return <SignUp path="/sign-up" routing="path" signInUrl="/sign-in" />
}
```

#### Fetch the Secret Data from the API

To use the Clerk SDK with the API endpoints, you must create the file `middleware.js` at the project root with the following code:

```js
import { withClerkMiddleware } from '@clerk/nextjs/server'
import { NextResponse } from 'next/server'

export default withClerkMiddleware((req) => {
  return NextResponse.next()
})

// Stop Middleware running on static files
export const config = { matcher: '/((?!.*\\.).*)' }
```

To create the API endpoint `/api/clerk-safehouse`, create a new file, `pages/api/clerk-safehouse.js`. If the user is signed in, the API handler returns a `200` response with the `safehouseKey`. Otherwise, it returns a `401` response with an error message.

This API handler function uses the `getAuth` utility function from `@clerk/nextjs/server` to get the user's authentication state on the server:

```jsx
import { getAuth } from '@clerk/nextjs/server'

export default async function handler(req, res) {
  try {
    const { userId } = getAuth(req)
    if (!userId) {
      return res.status(401).json({ message: 'error' })
    }
    return res.status(200).json({ safehouseKey: 'under-the-doormat', message: 'success' })
  } catch (err) {
    return res.status(401).json({ message: 'error' })
  }
}
```

#### Display the Secret Data

To display the data from the `/api/clerk-safehouse` API endpoint, create the new file `pages/safehouse.jsx`.

In this file, create a `SafeHouse` component that uses the `useUser` hook from `@clerk/nextjs` to get the authentication state. If the user isn't signed in, it returns the prebuilt component `<RedirectToSignIn>` from `@clerk/nextjs` that redirects the user to the `/sign-in` page.

However, if the user is signed in, it'll display the `safehouseKey` fetched from the API call to the `/api/clerk-safehouse` endpoint. It also returns the `<SignOutButton>` that the user can click to sign out of the application:

```jsx
import { useEffect, useState } from 'react'

import { SignOutButton, RedirectToSignIn, useUser } from '@clerk/nextjs'

export default function SafeHouse() {
  const { isSignedIn } = useUser()
  const [userData, setUserData] = useState({})

  useEffect(() => {
    fetch('/api/clerk-safehouse')
      .then((res) => res.json())
      .then((data) => setUserData(data))
  }, [])

  if (!isSignedIn) {
    return <RedirectToSignIn />
  }

  return (
    <>
      <main style={{ padding: '50px' }}>
        <h1>Safehouse </h1>
        <p>
          You Safehouse key is <strong>{userData?.safehouseKey || 'Loading...'}</strong>
        </p>
        <SignOutButton />
      </main>
    </>
  )
}
```

#### Update Application Home Page

Finally, update the application home page (`pages/index.js`) to include the new `/safehouse` link in the list:

```jsx
import Link from 'next/link'

export default function Home() {
  return (
    <div>
      Home
      <br />
      <ol>
        <li>
          <Link href={'/jwt-home'}>JWT Home</Link>
        </li>
        <li>
          <Link href={'/jwt-safehouse'}>JWT Safe house</Link>
        </li>
        <li>
          <Link href={'/safehouse'}>Clerk Safe house</Link>
        </li>
      </ol>
    </div>
  )
}
```

Your React application is ready with end-to-end authentication.

### Traditional JWT Authentication vs. Clerk

Now that you've implemented authentication in your React application using the traditional JWT flow and with Clerk, you can see how easy it is to implement a full-fledged authentication using the latter approach.

In the do-it-yourself JWT approach, all responsibilities regarding authentication—such as storing the password, verifying user identity, and crafting a beautiful user experience—fall on your shoulders.

Clerk lifts this burden by offering a full-stack solution for managing user authentication. It not only provides easy integrations on the frontend with prebuilt components but also authentication utilities for the backend API routes. With Clerk, you don't have to worry about password management, user session management, or signing and storing the JWT. It's all managed for you automatically.

Apart from its simplicity, the Clerk SDK also uses short-lived JWTs and HttpOnly cookies to provide an additional layer of security for your application. While short-lived JWTs help to protect against replay attacks and limit the window of opportunity for an attacker to use a compromised token, HttpOnly cookies help to protect against XSS attacks.

## Conclusion

In this article, you've successfully set up JWT authentication in a React application. While doing so, you learned more about JWT authentication and how to overcome some of its challenges. In particular, you saw how using a solution like Clerk can tremendously simplify JWT authentication in React and make the process more secure at the same time.

Clerk is a one-stop solution for authentication and customer identity management. It can help you build a flawless user authentication flow that supports login with password, multifactor authentication, and social logins with providers like Google, LinkedIn, Facebook, GitHub, and many more.

Clerk provides beautiful components ready to plug into your application and build the authentication flow in no time. Sign up to try [Clerk](https://dashboard.clerk.com/sign-up) today.