# Clerk Blog — Page 8

# Exploring Clerk Metadata with Stripe Webhooks
URL: https://clerk.com/blog/exploring-clerk-metadata-stripe-webhooks.md
Date: 2023-11-09
Category: Guides
Description: Utilize Clerk Metadata & Stripe Webhooks for efficient user data management and enhanced SaaS experiences with our step-by-step tutorial.

## Introduction to User Metadata

By putting Clerk’s user metadata types to work, developers can proficiently handle user data, making their SaaS integrations run smoother, and work harder. It's like adding a turbocharger to your product's engine, enhancing functionality and improving the user experience, for a more comprehensive, customizable, and synchronizing systems ready to build any SaaS product out there.

A great feature in the wild world of SaaS product development to power integrations powering integrations with other powerful products. We're talking about a sturdy, malleable means for handling user data.

You've got three types of User Metadata – [public, private, and unsafe](/docs/users/metadata#user-metadata). Each one has its own unique access level and use case.

- **Public**: It’s an accessible from both the frontend and backend. It's like the town bulletin board where you post things everyone can see but can't change. Think membership levels, user roles, stuff like that.
- **Private**: It’s like the secret stash of user data only reachable from the backend. Perfect for things like account identifiers or subscription details, you know, the stuff you don't want out in the open.
- **Unsafe**: It might sound a bit ominous, but it is super flexible; treat it like form data and validate any user inputs. It can be modified and accessed from both frontend and backend. Great for things like user preferences, setting or just any of the nitty-gritty details that make a user's experience unique.

## User Metadata Meets Stripe Webhooks

Harnessing the power of User Metadata in tandem with Stripe’s webhooks offers significant advantages in SaaS product development. Clerk Metadata's flexible user data management paired with Stripe webhooks' real-time transaction updates creates a robust, efficient system. This combination ensures both comprehensive user data handling and prompt responsiveness to transaction events. Utilizing Clerk Metadata alongside Stripe’s webhooks lends itself well for streamlined and user-friendly SaaS development.

Utilizing Clerk's public User Metadata offers significant advantages for managing user data and transactions in your SaaS product. It allows for real-time updates, such as including a "paid" field after a transaction, offering a clear snapshot of payment statuses. This use of public metadata improves transparency, boosts data management efficiency, and enhances the overall user experience.

## Tutorial: Implementing Stripe Webhook with Clerk User Metadata

The first step will be setting up accounts at [Clerk](https://dashboard.clerk.com/sign-up?utm_source=DevRel\&utm_medium=blog\&utm_campaign=devrel-blog-signups) & [Stripe](https://dashboard.stripe.com/register). Once you have those accounts you will follow the well documented [Clerk’s Next.js Quickstart Guide](/docs/quickstarts/nextjs). To have access to the correct data from the Clerk session you will need to access the [custom session data](/docs/backend-requests/making/custom-session-token#click-the-edit-button) on the Dashboard, we will edit the session data to look like this:

```json
{
  "publicMetadata": "{{user.public_metadata}}"
}
```

The last part will be setting up from the Stripe quickstart, the basic [Stripe webhook](https://stripe.com/docs/webhooks/quickstart). We will modify it later for our own needs, and there will also be a repo for you to grab afterwards! By the end of the quickstarts, you should have something in your **.env.local** that looks like this.

```bash {{ title: 'Environment Variables' }}
# CLERK
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_***
CLERK_SECRET_KEY=sk_test_***

# STRIPE
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_***
STRIPE_SECRET_KEY=sk_test_***
STRIPE_WEBHOOK_SECRET=whsec_***
```

## Auth Middleware Setup

Once we have everything installed we are going to jump into a very basic app, with one private route **/members**, and the homepage route will serve as our public route where all the fun stuff will happen. Our [Middleware](/docs/references/nextjs/auth-middleware) is going to be handling the access.

```typescript {{ title: 'Middleware Routes' }}
export default authMiddleware({
  // Making sure homepage route and API, especially the webhook, are both public!
  publicRoutes: ['/', '/api/(.*)'],
  afterAuth: async (auth, req) => {
    // Nice try, you need to sign-in
    if (!auth.userId && !auth.isPublicRoute) {
      return redirectToSignIn({ returnBackUrl: req.url })
    }
    // Hey! Members is for members 😆
    if (
      auth.userId &&
      req.nextUrl.pathname === '/members' &&
      auth.sessionClaims.publicMetadata?.stripe?.payment !== 'paid'
    ) {
      return NextResponse.redirect(new URL('/', req.url))
    }
    // Welcome paid member! 👋
    if (
      auth.userId &&
      req.nextUrl.pathname === '/members' &&
      // How we get payment value "paid" is next, in the webhook section!
      auth.sessionClaims.publicMetadata?.stripe?.payment === 'paid'
    ) {
      return NextResponse.next()
    }
    // If we add more public routes, signed-in people can access them
    if (auth.userId && req.nextUrl.pathname !== '/members') {
      return NextResponse.next()
    }
    // Fallthrough last-ditch to allow access to a public route explicitly
    if (auth.isPublicRoute) {
      return NextResponse.next()
    }
  },
})
```

We can simplify the Middleware access logic for this app, but this explicit example can show how you can have far more complex access handling. Where do we get **paid** from!? That is coming up next.

### Webhook Endpoint

Since this app is our SaaS with member access, we need to provide a way for the user to pay and gain access. Let’s start with setting up the tokens for Clerk & instantiating Stripe.

```typescript
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY as string, {
  apiVersion: '2023-10-16',
})
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET as string
```

After we have the credentials, the rest of the code should look very similar to the Stripe default logic for webhooks.

```typescript
export async function POST(req: NextRequest) {
  if (req === null) throw new Error(`Missing userId or request`, { cause: { req } })
  // Stripe sends this for us 🎉
  const stripeSignature = req.headers.get('stripe-signature')
  // If we don't get it, we can't do anything else!
  if (stripeSignature === null) throw new Error('stripeSignature is null')

  let event
  try {
    event = stripe.webhooks.constructEvent(await req.text(), stripeSignature, webhookSecret)
  } catch (error) {
    if (error instanceof Error)
      return NextResponse.json(
        {
          error: error.message,
        },
        {
          status: 400,
        },
      )
  }
  // If we dont have the event, we can't do anything again
  if (event === undefined) throw new Error(`event is undefined`)
  switch (event.type) {
    case 'checkout.session.completed':
      const session = event.data.object
      console.log(`Payment successful for session ID: ${session.id}`)
      break
    default:
      console.warn(`Unhandled event type: ${event.type}`)
  }

  return NextResponse.json({ status: 200, message: 'success' })
}
```

So what is next!? We need a way to know when a Clerk User has "paid." Well, let's extract that switch statement and add the secret sauce. That'll make this all work when we are done!

```typescript {{ title: 'Adding Clerk User Metadata to Event' }}
switch (event.type) {
  case 'checkout.session.completed':
    const session = event.data.object
    console.log(`Payment successful for session ID: ${session.id}`)
    // That's it? Yep, that's it. We love UX 🎉
    clerkClient.users.updateUserMetadata(event.data.object.metadata?.userId as string, {
      publicMetadata: {
        stripe: {
          status: session.status,
          // This is where we get "paid"
          payment: session.payment_status,
        },
      },
    })
    break
  default:
    console.warn(`Unhandled event type: ${event.type}`)
}
```

Some of you may have noticed **event.data.object.metadata?.userId** (where did that come from!?). We will get to that one too. The reason for this is that we can’t access Clerk’s session in the webhook, so we will get a little creative.

### Session Endpoint

We will now need to create an endpoint that will generate our Stripe session that will be used to make our payment and turn our Clerk User into a paid **Member**. This is where the **userId** in the webhook will also be coming from! Instantiate **stripe** the same as before, it will again be a Next.js POST endpoint.

```typescript {{ title: 'Stripe Session' }}
// This is our Clerk function for session User
const { userId } = auth()
// We are receiving this from the Client request, thats next!
const { unit_amount, quantity } = await req.json()

try {
  const session = await stripe.checkout.sessions.create({
    payment_method_types: ['card'],
    line_items: [
      {
        price_data: {
          currency: 'usd',
          product_data: {
            name: 'Membership',
          },
          unit_amount,
        },
        quantity,
      },
    ],
    // This is where "event.data.object.metadata?.userId" is defined!
    metadata: {
      userId,
    },
    mode: 'payment',
    success_url: `${req.headers.get('origin')}/members`,
    cancel_url: `${req.headers.get('origin')}/`,
  })

  return NextResponse.json({ session }, { status: 200 })
} catch (error) {
  // ...
}
```

We have now laid the groundwork for a SaaS leveraging Clerk’s User Metadata to manage User specific data! So, to really focus on the versatility and potential of this feature, the UI portion has been kept really simple. We have the Homepage with a button to navigate to **/members** page and to become a paid member, let’s take a look at the homepage.

```tsx {{ title: 'Homepage Implementation' }}
export default function Home() {
  const { isSignedIn } = useAuth()

  return (
    <main>
      {!isSignedIn ? (
        <div className="...">
          <SignIn redirectUrl="/" />
        </div>
      ) : (
        <div>
          <div className="...">You are signed in!</div>
          <div className="...">
            <CheckoutButton />
            <a className="..." href="/members">
              Go to members page
            </a>
          </div>
        </div>
      )}
    </main>
  )
}
```

## Wrap up!

This pattern can be used with any other transactions or user specific data you would like to handle in the backend and then utilize in the client. This keeps your User Management pragmatic & versatile, offloading the burden across multiple systems. This is only the beginning with what we can do with Clerk’s toolset, this time we only leveraged User Metadata! What should we do next? Let us know in the [Discord](https://clerk.com/discord) and on [X(Twitter)](https://x.com/clerk)!

Not forgetting, you will want the [complete codebase](https://github.com/JacobMGEvans/stripe-with-webhooks-and-metadata) to check out, and learn from!

---

# The Ultimate Guide to Next.js Authentication
URL: https://clerk.com/blog/nextjs-authentication.md
Date: 2023-11-02
Category: Guides
Description: In this guide, you will learn best practices for implementing secure authentication in your Next.js app.

[Next.js](https://nextjs.org) has become the go-to framework for JavaScript and React development. It has become so popular because of the superior developer experience, performance optimization features, and its ability to facilitate different rendering options and serverless functions with ease. The combination of these attributes makes it an appealing choice for both new and experienced developers.

In Next.js 13, the Next.js team significantly upgraded the capabilities of the framework. Moving to what they call the “App Router,” Next.js is now based on [React Server Components](https://nextjs.org/docs/app/building-your-application/rendering/server-components) which boast performance upgrades over the previous client-server architecture.

But this shift has also led to a change in how authentication works in Next.js. In this article we want to provide an up-to-date guide on how authentication now works on Next.js so you can easily understand the concepts involved and **easily add secure authentication to your Next.js applications**.

## The Next.js App Router

The [App Router paradigm was introduced in Next.js 13](https://nextjs.org/docs/app) and is a significant shift in how the Next.js framework works.

Next.js was initially built as a React framework to facilitate server-side rendered and statically generated sites. But as the framework grew, more options became available:

1. **Client-Side Rendering (CSR)** is where content is rendered on the client side, after the initial page load. This is ideal for pages that don’t require SEO or initial content served by the server. Common for user dashboards or pages behind authentication. You use React state and effects (`useState`, `useEffect`, etc.) as you would in a regular React app.
2. **Static Site Generation (SSG)** is where pages are pre-rendered at build time and served statically. Each request receives the same HTML. This is good for content that doesn’t change often and doesn’t need to be updated with every request, such as blogs, marketing pages, and documentation, etc. Here, you use `getStaticProps` to fetch the required data at build time.
3. **Incremental Static Regeneration (ISR)** lets you statically generate pages with the option to update them in the background. Once updated, subsequent requests get the new version. This is useful for content that updates periodically but doesn’t need real-time updates. Like with SSG, you can use `getStaticProps`, but this time you add a `revalidate` property. The `revalidate` interval (in seconds) determines how often the page should be updated.
4. **Server-Side Rendering (SSR)** means each request is rendered on-the-fly on the server, providing fresh data. It is ideal for pages that need real-time data or when content changes frequently. Also beneficial for SEO. You use `getServerSideProps` to fetch data on each request.

You could have some pages work with CSR, some SSG, and some SSR. But this also led to confusion and performance issues with sites not optimally built.

Next.js 13 and the App Router are designed to simplify the developer experience within Next.js, and rebuild the framework around [React Server Components](https://nextjs.org/docs/app/building-your-application/rendering/server-components). With RSC, the default for the entire site is server-side rendering, with each page being opted-in to CSR as needed. This leads to performance gains, as rendering on the server is faster, and you don’t have to send heavy JavaScript payloads over the network for hydration. It also means more sites can work on the ‘edge’ network, where sites are served from multiple servers close to users.

But this does mean that the way developers have been using Next.js thus far has now changed. The old, Pages Router continues to work, and can be used side-by-side with the App Router, but significant changes in how data is served, such as no request/response objects being passed means developers will need to rethink how they work, and how their authentication works.

Here, we’re going to go through:

1. How authentication works with the pages router in Next.js
2. How authentication works with the App Router in Next.js

This will give you the ability to use either as you need, and to see the differences in each paradigm when it comes to authentication.

## Authentication With the Next.js Pages Router

Before we get into authentication with the App Router, let’s look at how authentication works with the Pages Router in Next.js.

Let’s create a Next.js project. To do this, we use:

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

You will be prompted to choose different options, but given that we are explicitly using the Pages Router, you’ll want to select “no” when asked if you would like to use the App Router.

With that done, we can install Clerk:

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

Next, we want to add our API keys as environmental variables in an `.env.local` file. To get these, sign up for a free [Clerk account](/):

```sh
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_*****
CLERK_SECRET_KEY=sk_test_*****
```

Before we go any further, we’ll also make some small changes to our homepage, at `pages/index.js`:

```jsx
import Head from 'next/head'

export default function Home() {
  return (
    <div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-blue-500 to-purple-500">
      <Head>
        <title>Hello Pages Router with Next.js & Clerk</title>
        <meta
          name="description"
          content="A simple Hello World homepage using Next.js and TailwindCSS"
        />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <div className="rounded-xl bg-white p-8 shadow-lg">
        <h1 className="mb-4 text-2xl font-bold text-blue-500">Hello, Pages Router!</h1>
        <p className="text-gray-600">This is a simple homepage built with Next.js and Clerk</p>
      </div>
    </div>
  )
}
```

If we now run `npm run dev`, we’ll get this homepage:

![Nextjs Authentication tutorial illustration](./e6980a8e3bf380cb0bdf8cac5a4ea4e503f0411e-2000x1264.png)

We’re now ready to start adding Clerk to our code. The first thing we need to do is mount the [ClerkProvider](/docs/components/clerk-provider#clerk-provider). The `ClerkProvider` is the core component of Clerk. It is what handles all the active session data and the user context. Whenever a Clerk hook (or any other components) needs authentication data, it is getting it from the `ClerkProvider`.

The `ClerkProvider` needs needs to access [headers](https://nextjs.org/docs/app/api-reference/functions/headers) to authenticate any user. This is important because:

`headers()` is a Dynamic Function whose returned values cannot be known ahead of time. Using it in a layout or page
will opt a route into dynamic rendering at request time.

To protect your entire application, it is recommended to wrap our main Component in the `_app.tsx|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
```

This will protect every page within the application and will make the user context accessible anywhere within the app, but will also opt every page into dynamic rendering.

If you have statically served pages or are using incremental static regeneration, you can wrap route groups further into your application. For example, you might want to leave your marketing site unprotected, but wrap your dashboard components in the `ClerkProvider`.

Clerk [requires middleware](/docs/references/nextjs/auth-middleware#auth-middleware) to determine the routes that need to be protected. This is in `middleware.js` in our root directory. This matcher will put every page and API route on the site behind authentication:

```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)(.*)'],
}
```

The entire application is now protected. Accessing any page while signed out will redirect you to the sign up page. If we go to the homepage again, we get redirected:

![Nextjs Authentication tutorial illustration](./f1c7e0f565e3b201cff729570d3fef5862539c02-2000x1264.png)

Usually, this isn’t what you want. Your homepage, product, and marketing pages aren’t very helpful if they are behind authentication!

If you navigate to the homepage now you’ll also get this warning:

The request to / is being redirected because there is no signed-in user, and the path is not included in ignoredRoutes
or publicRoutes.

To prevent this behavior, choose one of:

1. To make the route accessible to both signed in and signed out users, pass `publicRoutes: ["/"]` to `authMiddleware`
2. To prevent Clerk authentication from running at all, pass `ignoredRoutes: ["/((?!api|trpc))(_next.*|.+\\.[\\w]+$)", "/"]` to `authMiddleware`
3. Pass a custom [afterAuth](/docs/references/nextjs/auth-middleware#using-after-auth-for-fine-grained-control) to `authMiddleware`, and replace Clerk’s default behavior of redirecting unless a route is included in public routes

So let’s make a change to add a public route:

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

export default authMiddleware({
  publicRoutes: ['/'],
})

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

Now, when we head to the homepage, it is available again:

![Nextjs Authentication tutorial illustration](./e6980a8e3bf380cb0bdf8cac5a4ea4e503f0411e-2000x1264.png)

Great. But now there is no way for us to sign up or sign in. Clerk’s [Next.js Authentication SDK](/nextjs-authentication) provides helpers for determining whether a user is signed in or note, and conditionally changing the text. Let’s wrap our text in these components:

```jsx
import { SignedOut } from '@clerk/nextjs'
import Head from 'next/head'
import Link from 'next/link'

export default function Home() {
  return (
    <div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-blue-500 to-purple-500">
      <Head>
        <title>Hello Pages Router with Next.js & Clerk</title>
        <meta
          name="description"
          content="A simple Hello World homepage using Next.js and TailwindCSS"
        />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <div className="rounded-xl bg-white p-8 shadow-lg">
        <h1 className="mb-4 text-2xl font-bold text-blue-500">Hello, Pages Router!</h1>
        <p className="text-gray-600">This is a simple homepage built with Next.js and Clerk</p>

        <SignedOut>
          <Link href="/sign-up">
            <div>
              <h3 className="mb-4 text-xl font-bold text-blue-500">
                Sign in or sign up for an account
              </h3>
            </div>
          </Link>
        </SignedOut>
      </div>
    </div>
  )
}
```

Here, if a user is signed out, they’ll see a link to a sign up page. This page doesn’t exist yet, so lets create it. It will live at `pages/sign-up/[[...index]].jsx`:

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

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

Not much to it. If you try to go that page, you’ll be redirected to sign in/sign up, so it will look like its working. But you are actually being redirected because that page hasn’t been defined as a public route in the middleware, so it itself is behind authentication. To get around this, we’re actually going to add it to our environment variables as a special page:

```sh
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/
```

Now, if we go to that sign up page, we’ll get the modal where we can sign up:

![Nextjs Authentication tutorial illustration](./98d8928b270f39bf6cbc462d88899e026b7f96c1-2000x1264.png)

Then, as our environment variables say, we’re redirected to the home page:

![Nextjs Authentication tutorial illustration](./d52c43bd5ba929652ae9b6563b8ea9cf9882c950-2000x1264.png)

As you can see, the link to sign in as gone, as it was wrapped in the component that only shows it if you are signed out.

We now have a problem. We are now signed in (great!), but we can’t sign out (uh oh!). We could create a specific link for this as well, but Clerk provides a [UserButton component](/docs/references/javascript/clerk/user-button#user-button-component) that allows us to do this easily. Let’s add that to the homepage:

```jsx
import { SignedOut } from '@clerk/nextjs'
import Head from 'next/head'
import Link from 'next/link'

export default function Home() {
  return (
    <div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-blue-500 to-purple-500">
      <Head>
        <title>Hello Pages Router with Next.js & Clerk</title>
        <meta
          name="description"
          content="A simple Hello World homepage using Next.js and TailwindCSS"
        />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <div className="rounded-xl bg-white p-8 shadow-lg">
        <h1 className="mb-4 text-2xl font-bold text-blue-500">Hello, Pages Router!</h1>
        <p className="text-gray-600">This is a simple homepage built with Next.js and Clerk</p>

        <SignedOut>
          <Link href="/sign-up">
            <div>
              <h3 className="mb-4 text-xl font-bold text-blue-500">
                Sign in or sign up for an account
              </h3>
            </div>
          </Link>
        </SignedOut>
        <SignedIn>
          <div>
            <UserButton afterSignOutUrl="/" />
          </div>
        </SignedIn>
      </div>
    </div>
  )
}
```

We’ve wrapped this `UserButton` within the [SignedIn component](/docs/components/control/signed-in#signed-in) so it’ll only show when the user is signed in:

![Nextjs Authentication tutorial illustration](./9ff4051f631c059104c26f01fc4cbb304f7a6f99-2000x1264.png)

Using that button, the user can easily adjust their profile as well as sign out of the application.

Now the user is signed in, they can visit other pages. Let’s create a `pages/protected.jsx` page:

```jsx
import { clerkClient } from '@clerk/nextjs'
import { getAuth, buildClerkProps } from '@clerk/nextjs/server'

const ProtectedPage = ({ user }) => {
  if (!user) {
    return (
      <div>
        <p>Please log in to view this content.</p>
        {/* Optionally add a login button or redirect logic here */}
      </div>
    )
  }

  return (
    <div>
      <h1>Welcome, {user.firstName}!</h1>
      <p>This is your protected page.</p>
      {/* Other user-specific JSX components/data can be added here */}
    </div>
  )
}

export default ProtectedPage

export const getServerSideProps = async (ctx) => {
  const { userId } = getAuth(ctx.req)

  if (!userId) {
    return { props: {} } // This will pass an empty props object and the component will handle the "not logged in" state
  }

  const userFromClerk = userId ? await clerkClient.users.getUser(userId) : null
  const user = userFromClerk
    ? {
        id: userFromClerk.id,
        firstName: userFromClerk.firstName,
        lastName: userFromClerk.lastName,
        // ... Add other necessary fields here
      }
    : null

  return { props: { user, ...buildClerkProps(ctx.req) } }
}
```

The code uses the `clerkClient`, `getAuth`, and `buildClerkProps` utilities from the `@clerk/nextjs` library to handle user authentication. If a user is not authenticated (determined by the absence of a `user` prop), the page prompts the user to log in. If authenticated, the page displays a personalized welcome message.

The server-side function `getServerSideProps` checks for the `userId` in the incoming request using the `getAuth` function; if the `userId` is present (indicating authentication), it fetches detailed user information from Clerk via `clerkClient.users.getUser`. The fetched data is then streamlined to a simpler format, extracting only necessary fields like the user’s first name and last name.

The `getServerSideProps` function concludes by returning the user data, if any, along with additional props sourced from `buildClerkProps`, ensuring the frontend receives the necessary data to render the page appropriately.

This renders as:

![Nextjs Authentication tutorial illustration](./7247464b939968d7317dd044b2e85c4301b073a6-2000x1264.png)

Here, the authentication is checked on the server before the page is rendered via `getServerSideProps`. We can also check whether the user is authenticated on the client. Let’s create a `pages/protected-client.jsx` page:

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

export default function Example() {
  const { isLoaded, isSignedIn, user } = useUser()

  if (!isLoaded || !isSignedIn) {
    return null
  }

  return (
    <div>
      <h1>Welcome, {user.firstName}!</h1>
      <p>This is your protected page on the client.</p>
      {/* Other user-specific JSX components/data can be added here */}
    </div>
  )
}
```

Which renders this page:

![Nextjs Authentication tutorial illustration](./8fd94b0e65832bf268c37a8aa92c170f6b27de49-2000x1264.png)

One final part of Next.js we can protect with authentication–[API routes](/docs/references/nextjs/get-auth#protecting-api-routes). With the pages router, any route within pages/api is returned as an API. Let’s protect an API route at `pages/api/auth.js`:

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

export default async function handler(req, res) {
  const { userId } = getAuth(req)

  if (!userId) {
    return res.status(401).json({ error: 'Unauthorized' })
  }

  const user = userId ? await clerkClient.users.getUser(userId) : null

  return res.status(200).json({ user })
}
```

This uses the `getAuth` helper that retrieves the authentication state to protect the API route. If we call this within the browser, we’ll get the user JSON:

![Nextjs Authentication tutorial illustration](./19003492bcb5eb596cd8de307703043ed506f2b6-2000x1264.png)

You now have a protected Next.js application using the pages router. Let’s move on to the App Router.

## Authentication with the Next.js App Router

We’re now going to work through an entire example with [the Next.js App Router.](/docs/quickstarts/nextjs#app-router) Some of this is the same as above, particularly, the set up, but once we get into the actual authentication, there are going to be some differences.

Let’s create a new Next.js project:

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

This time, when you are prompted to use the App Router, select “yes”.

Then install Clerk into this project:

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

And then add our API keys in an `.env.local` file:

```sh
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_*****
CLERK_SECRET_KEY=sk_test_*****
```

We’ll spool up another bare-bones homepage, this time at `app/page.js`:

```jsx
import Head from 'next/head'

export default function Home() {
  return (
    <div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-blue-500 to-purple-500">
      <Head>
        <title>Hello Pages Router with Next.js & Clerk</title>
        <meta name="description" content="A simple Hello World homepage using Next.js and Clerk" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <div className="rounded-xl bg-white p-8 shadow-lg">
        <h1 className="mb-4 text-2xl font-bold text-blue-500">Hello, Pages Router!</h1>
        <p className="text-gray-600">This is a simple homepage built with Next.js and Clerk</p>
      </div>
    </div>
  )
}
```

If we now run `npm run dev`, we’ll get this homepage:

![Nextjs Authentication tutorial illustration](./b25b2a50a76078b8517b027d0e5efed705d6576d-2000x1264.png)

Looks like we have some nicer default styling with the App Router.

Next up is to add the `ClerkProvider`. This is the first point at which there is a difference between the pages router and the App Router. With the App Router, we’re going to add the `ClerkProvider` to our `layout.js`:

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

export const metadata = {
  title: 'Next.js 13 with Clerk',
}

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

The App Router doesn’t use the `_app.js` file. Instead, layout.js lets you set a global layout for your application. Therefore you can add the `ClerkProvider` to e.g. the `dashboard/layout.js` file, and only the files within that route group would require a login. To repeat from above, this is important because the `ClerkProvider` requires dynamic rendering. If you nest the `ClerkProvider` at a lower level, this allows you to serve the landing and marketing pages statically.

The root layout is a server component. If you plan to use the `ClerkProvider` outside the root layout, it will need to
be a server component as well.

Next step is the middleware. Again, this is in `middleware.js` in our root directory. This time, we’ll start with our homepage as a public route:

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

export default authMiddleware({
  publicRoutes: ['/'],
})

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

Clerk is now protecting the entire application. Let’s change our homepage to use the [SignedOut component](/docs/components/control/signed-out#signed-out) so we can sign in to the app:

```jsx
import { SignedOut } from '@clerk/nextjs'
import Head from 'next/head'
import Link from 'next/link'

export default function Home() {
  return (
    <div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-blue-500 to-purple-500">
      <Head>
        <title>Hello Pages Router with Next.js & Clerk</title>
        <meta
          name="description"
          content="A simple Hello World homepage using Next.js and TailwindCSS"
        />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <div className="rounded-xl bg-white p-8 shadow-lg">
        <h1 className="mb-4 text-2xl font-bold text-blue-500">Hello, Pages Router!</h1>
        <p className="text-gray-600">This is a simple homepage built with Next.js and Clerk</p>

        <SignedOut>
          <Link href="/sign-up">
            <div>
              <h3 className="mb-4 text-xl font-bold text-blue-500">
                Sign in or sign up for an account
              </h3>
            </div>
          </Link>
        </SignedOut>
      </div>
    </div>
  )
}
```

The link now shows on the page:

![Nextjs Authentication tutorial illustration](./53272617b60538ee8c19d0a49d97c4f756342902-2000x1264.png)

Next we’ll add the two other components that will be important for signing up/in/out. First, the sign up page, which will be at `app/sign-up/[[...sign-up]]/page.jsx`:

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

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

Remember to also add these new endpoints to your `.env.local`:

```sh
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/
```

Second, we need the user button:

```jsx
import { SignedIn, SignedOut, UserButton } from '@clerk/nextjs'
import Link from 'next/link'

export default function Home() {
  return (
    <div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-blue-500 to-purple-500">
      <div className="rounded-xl bg-white p-8 shadow-lg">
        <h1 className="mb-4 text-2xl font-bold text-blue-500">Hello, App Router!</h1>
        <p className="text-gray-600">This is a simple homepage built with Next.js and Clerk</p>

        <SignedOut>
          <Link href="/sign-up">
            <div>
              <h3 className="mb-4 text-xl font-bold text-blue-500">
                Sign in or sign up for an account
              </h3>
            </div>
          </Link>
        </SignedOut>
        <SignedIn>
          <div>
            <UserButton afterSignOutUrl="/" />
          </div>
        </SignedIn>
      </div>
    </div>
  )
}
```

Now, when we click the sign up/in link we again go through to the Clerk modal:

![Nextjs Authentication tutorial illustration](./a018d5cc5de01bc8cbfed9e160a38a96c5808f5b-2000x1264.png)

Once we sign in we are redirected back to the homepage, now with the user button:

![Nextjs Authentication tutorial illustration](./d4a7445cd988fc8f664da1720c1ff78222daf6f8-2000x1264.png)

With the user signed in, let’s do the same as with the pages router: create a protected page and a protected API.

Again, for protected pages, we can check for authentication on the server or on the client. Let’s quickly do the client side as that is similar to the pages router:

```jsx
'use client'

import { useUser } from '@clerk/nextjs'

export default function Example() {
  const { isLoaded, isSignedIn, user } = useUser()

  if (!isLoaded || !isSignedIn) {
    return null
  }

  return (
    <div>
      <h1>Welcome, {user.firstName}!</h1>
      <p>This is your protected page on the client.</p>
      {/* Other user-specific JSX components/data can be added here */}
    </div>
  )
}
```

The only difference between the App Router and the pages router version here is the “use client” directive. By default, all components in the App Router are server components, so will render on the server. The “use client” directive opts this component into client-side rendering, so we can then use Clerk hooks.

This renders as:

![Nextjs Authentication tutorial illustration](./e3266ebf4b05b8bf25e26f448f46a325ff460408-2000x1264.png)

For server rendering, Clerk has two App Router-specific helpers that you can use with your Server Components:

1. [auth()](/docs/references/nextjs/auth) will return the [Authentication](/docs/references/nextjs/authentication-object) object of the currently active user. One of the fundamental differences with the App Router is that you don’t have to inspect the request object constantly for authentication headers. Instead they are available in the global scope through Next.js’s [headers()](https://nextjs.org/docs/app/api-reference/functions/headers) and [cookies()](https://nextjs.org/docs/app/api-reference/functions/cookies) functions, that ClerkProvider gives you access to.
2. [currentUser()](/docs/references/nextjs/current-user) will return the [User](/docs/references/javascript/user/user) object of the currently active user so you can render information, like their first and last name, directly from the server.

Here, we’re going to use both to get information about the user on a protected page:

```jsx
import { auth, currentUser } from '@clerk/nextjs'

export default async function Page() {
  // Get the userId from auth() -- if null, the user is not logged in
  const { userId } = auth()

  if (userId) {
    // Query DB for user specific information or display assets only to logged in users
  }

  // Get the User object when you need access to the user's information
  const user = await currentUser()

  // Use `user` to render user details or create UI elements
  return (
    <div>
      <h1>Welcome, {user.firstName}!</h1>
      <p>This is your protected page.</p>
      {/* Other user-specific JSX components/data can be added here */}
    </div>
  )
}
```

Which gives us a page with user information rendered:

![Nextjs Authentication tutorial illustration](./43cb7ef9a02b2d0a7c846269d2eb6e0214e64e92-3346x2114.png)

For API routes, the routing is different, but the code is similar. Let’s build an API route under `app/api/user/route.jsx`:

```jsx
import { NextResponse } from 'next/server'
import { auth, currentUser } from '@clerk/nextjs'

export async function GET() {
  const { userId } = auth()

  if (!userId) {
    return new NextResponse('Unauthorized', { status: 401 })
  }

  const user = await currentUser()

  // perform your Route Handler's logic

  return NextResponse.json({ user }, { status: 200 })
}
```

We don’t have the request and response objects with the App Router, so get all our authentication data from our Clerk helpers (which get it from the ClerkProvider which gets it from the global scope via the [Next.js headers() function](https://nextjs.org/docs/app/api-reference/functions/headers)). We can return a JSON of the user’s information:

![Nextjs Authentication tutorial illustration](./4503ac653efdf0ba31a88581dad9641ea6cff2e7-2000x1264.png)

And that’s it. You have server-side, client-side, and API route authentication using the Next.js App Router.

## Authenticating with the App Router

The Next.js App Router offers significant performance gains compared to the traditional pages router. However, you can absolutely continue leveraging the pages router in your Next.js applications – Clerk supports authentication with both routing approaches.

To learn more about the App Router, check out the official [Next.js documentation](https://nextjs.org/docs/app). If you would like to get started with Clerk, [sign up for a free account](https://dashboard.clerk.com/sign-up) and follow along with our [Next.js Quickstart](/docs/quickstarts/nextjs).

---

# Empower Your Support Team With User Impersonation
URL: https://clerk.com/blog/empower-support-team-user-impersonation.md
Date: 2023-10-18
Category: Guides
Description: User impersonation enables support teams to assist customers without compromising privacy and security, essential for delivering great CX.

Unfortunately, no product is perfect. Once in a while, a user will have a problem with your application and need some help from the support team.

But if the problem is specific to the user–something about their data or their permissions within the product–how can customer support help? They could screenshare with the user, but that requires a lot of setup. They could just get the user to describe their problem and then walk them through the steps to fix it, but that is open to all kinds of errors. They could share their credentials with the support team, but that is a huge security risk!

The answer is to implement **user impersonation** in the product.

User impersonation is an admin feature that allows one user, usually an admin or the support team, to take on the identity of another user without knowing their password or other authentication credentials.

It is one of those features that gets missed in an initial roadmap but is critical to the product's long-term success. Without it, your success team flies blind when trying to help customers. Let’s explain why it’s important and how you can implement user impersonation in your application.

## The Importance of User Impersonation

The core reason to use user impersonation is troubleshooting and support. If a user reports an issue specific to their account, admins or the support team can impersonate the user to experience the application exactly as the user does. This helps in identifying and resolving the issue more efficiently.

But user impersonation can go beyond just straightforward support. User impersonation can be important for:

- **User Experience Testing**: Developers can use impersonation to see how the application or platform appears to users with different roles or permissions. This can be particularly useful for platforms with different user tiers, allowing for testing the user experience at each level.
- **Training and Onboarding**: In some cases, particularly within enterprise applications, user impersonation can be helpful for training. A trainer can impersonate a user role to guide new users through specific functionalities of the platform.
- **Data Access and Recovery**: If a user cannot access specific data or files, a support team member might use impersonation to access and recover that data on the user's behalf.
- **Auditing and Compliance**: In certain regulated industries, there might be a need to audit user actions or verify data accuracy. Impersonation can allow an auditor to access the system as a specific user to ensure compliance with regulations.

Of course, impersonating users is fraught with risks. Impersonation can easily lead to privacy breaches if not handled carefully. Admins and support can see personal or sensitive information. Also, if not implemented securely, impersonation features can be a potential attack vector for malicious actors. Ensuring that only authorized personnel can use impersonation and that all impersonation activities are logged for auditing is essential.

Because of these concerns, any system implementing user impersonation should have stringent security controls, logging, and auditing. It's also essential to have clear policies about when and why impersonation is used.

## Implementing User Impersonation

Implementing user impersonation is tricky. Literally, you are tricking your application into thinking that you are someone else. Here are the steps to consider through as you add user impersonation to your product:

1. **Ensure Strong Permissions and Auditing**: Only certain roles, such as admins and the support team, should be allowed to impersonate. As we said above, you should log every impersonation attempt, including the user doing the impersonation, the impersonated user, and the timestamp.
2. **Authentication & Authorization**: Established libraries, like [Clerk](/docs/custom-flows/user-impersonation#user-impersonation), have user impersonation built in. Use these wherever possible to lessen the likelihood of mistakes–get this wrong, and you can have serious privacy breaches. You should store roles in JWT or sessions to check user permissions.
3. **Impersonation**: When an authorized user requests to impersonate another user, you should store the original user's ID somewhere safe (e.g., in their session or another token), then update the user session/token to reflect the impersonated user's ID. When the user finishes impersonation, you must restore their session/token using the stored original user ID.
4. **UI Indication**: To avoid confusion, the UI should indicate when impersonation is active. A simple banner or color change can be used to show that the admin is in impersonation mode.

Let’s show how this would work with a basic JavaScript application. We’re going to set up two core components to this:

1. A backend Express server that will handle the actual impersonation.
2. A frontend React application that will provide the UI for the support team to use.

### The backend server

The backend is where we will incorporate the logic for our impersonation.

```javascript
const express = require('express')
const cors = require('cors')

const PORT = 3000

const app = express()
app.use(express.json()) // Middleware to parse JSON requests

const users = [
  { id: 1, username: 'admin', password: 'pass', roles: ['admin'] },
  // ... other users
]

// Use the cors middleware and set the frontend origin
app.use(
  cors({
    origin: '<http://localhost:3001>',
    credentials: true,
    methods: ['GET', 'POST', 'PUT', 'DELETE'],
    allowedHeaders: ['Content-Type', 'Authorization'],
  }),
)

function ensureAdmin(req, res, next) {
  const roles = req.body.roles
  if (roles && roles.includes('admin')) {
    return next()
  } else {
    return res.status(403).json({ message: 'Access forbidden.' })
  }
}

app.post('/impersonate/:userId', ensureAdmin, (req, res) => {
  console.log(req)
  const userIdToImpersonate = req.params.userId
  const user = users.find((u) => u.id == userIdToImpersonate)
  if (!user) {
    return res.status(404).json({ message: 'User not found.' })
  }
  res.json({ message: 'Impersonation started.' })
})

app.post('/stop-impersonation', ensureAdmin, (req, res) => {
  res.json({ message: 'Impersonation stopped.' })
})

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`)
})
```

We start by importing the two modules needed:

- Express for the web server.
- cors for Cross-Origin Resource Sharing (useful when the frontend and backend are on different origins).

We then set up the Express server. We want to use the built-in `express.json()` middleware, enabling the server to parse incoming JSON payloads in requests.

After that, we set up a user array. This array simulates a database of users. Here, you would call your database to check users and roles. We then have to set up some CORS middleware. Without this, our server wouldn’t want to receive requests from our separate frontend.

ensureAdmin is the integral function of the server. This middleware checks if the user role includes "admin." If so, it allows the request to proceed. Otherwise, it sends back a forbidden status. This ensures the user is an admin before allowing them to impersonate another user.

We then have our two API Endpoints:

- `/impersonate/:userId`: An admin can attempt to impersonate another user by providing their ID.
- `/stop-impersonation`: An admin can stop the impersonation.

Finally, we start our server. Save this as `app.js` and you can run it with

```sh
node app.js
```

With that up and running, we can set up the frontend.

### The frontend application

The frontend will mimic the version of the application that an admin would see. When an admin chooses to impersonate, it makes a request to the `/impersonate/:userId` endpoint. It then updates the UI based on the response to show that impersonation is active. To stop impersonation, it makes a request to `/stop-impersonation`.

```jsx
import React, { useState } from 'react'
import './App.css'

function App() {
  const [isImpersonating, setIsImpersonating] = useState(false)
  const [message, setMessage] = useState('')

  const handleImpersonate = async (userId) => {
    try {
      const response = await fetch(`/impersonate/${userId}`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ roles: ['admin'] }),
      })

      if (!response.ok) {
        throw new Error(`HTTP error! Status: ${response.status}`)
      }

      const data = await response.json()
      setIsImpersonating(true)
      setMessage(data.message)
    } catch (err) {
      console.error('Impersonation failed:', err)
      setMessage('Impersonation failed. Check console for details.')
    }
  }

  const handleStopImpersonating = async () => {
    try {
      const response = await fetch('/stop-impersonation>', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ roles: ['admin'] }),
      })

      if (!response.ok) {
        throw new Error(`HTTP error! Status: ${response.status}`)
      }

      const data = await response.json()
      setIsImpersonating(false)
      setMessage(data.message)
    } catch (err) {
      console.error('Failed to stop impersonation:', err)
      setMessage('Failed to stop impersonation. Check console for details.')
    }
  }

  return (
    <div className="App">
      {isImpersonating ? (
        <div className="impersonation-banner">You are impersonating another user!</div>
      ) : null}
      <button onClick={() => handleImpersonate(1)}>Impersonate User with ID 1 (admin)</button>
      {isImpersonating ? (
        <button onClick={handleStopImpersonating}>Stop Impersonating</button>
      ) : null}
      <p>{message}</p>
    </div>
  )
}

export default App
```

After importing React and our CSS, the core App function starts by declaring two state variables:

- `isImpersonating`: A boolean state that tracks whether the admin is currently impersonating another user.
- `message`: A string state to store and display messages from server responses or errors.

We then have our impersonation functions. `handleImpersonate` is an async function to impersonate a user by sending a POST request to `/impersonate/:userId`. If successful, it sets the state `isImpersonating` to `true` and displays a message from the server.

`handleStopImpersonating` is also an async function, this time to stop impersonation by sending a POST request to `/stop-impersonation`. If successful, it sets the state `isImpersonating` to false and displays a message from the server.

We then render our component. A button allows the admin to impersonate a user with ID 1 , and then a banner is displayed when the admin is impersonating another user. If the admin is impersonating, another button appears to stop the impersonation.

So when an admin logs in initially, they see this:

![Empower Support Team User Impersonation guide illustration](./cde8309564132cecdf8143f73c286562746e24f2-2000x1243.png)

Once they press the button, they start the impersonation:

![Empower Support Team User Impersonation guide illustration](./4de7c80017e36f443145441e7398316b59faa87a-2000x1264.png)

Then, they can stop the impersonation again:

![Empower Support Team User Impersonation guide illustration](./461c595a3f3254daeb412a146c6649070e15a1c0-2000x1264.png)

## Using Clerk for User Impersonation

What are the problems with the solution above? They are myriad.

First, we don’t have any authentication. This not only means the whole system is insecure, but it also means the impersonation is insecure. We’re just sending a plain text ‘admin’ message to the backend to tell them we can impersonate a user. The correct way to do this is using JWT. The token would contain the role information and be authenticated by the backend.

We also don’t have the logic incorporated to actually do anything with the impersonation. Neither do we have all the security checks in place to securely audit and log any impersonation.

We’re missing all this because impersonation is difficult to get right. You are coding an entirely different way to access your application, and you have to do it perfectly to avoid any security or privacy issues.

This is where using a platform like Clerk becomes essential. [User impersonation](/docs/custom-flows/user-impersonation) is incorporated directly into Clerk. All you have to do is call our [backend API](/docs/reference/backend-api/tag/actor-tokens/POST/actor_tokens) with your user ID (`user_id`) and the user ID of the user to impersonate (`sub`):

```javascript
const url = 'https://api.clerk.com/v1/actor_tokens'

const data = {
  user_id: 'user_1o4qfak5AdI2qlXSXENGL05iei6',
  expires_in_seconds: 600,
  actor: {
    sub: 'user_21Ufcy98STcA11s3QckIwtwHIES',
  },
}

async function postData() {
  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(data),
    })

    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`)
    }

    const responseData = await response.json()
    console.log(responseData)
  } catch (error) {
    console.log('There was a problem with the fetch operation:', error.message)
  }
}

// Invoke the function to execute the fetch operation
postData()
```

This returns a token you can then use to impersonate the user for 10 minutes:

```json
{
  "sub": "user_1o4qfak5AdI2qlXSXENGL05iei6",
  "act": {
    "sub": "user_21Ufcy98STcA11s3QckIwtwHIES"
  }
}
```

You can then use this with the Clerk SDK for impersonation:

```javascript
import express from 'express'
import { ClerkExpressWithAuth } from '@clerk/clerk-sdk-node'

const app = express()

// Apply the Clerk express middleware
app.get(
  '/protected-endpoint',
  ClerkExpressWithAuth({
    // ...options
  }),
  (req, res) => {
    // The request object is augmented with the
    // Clerk authentication context.
    const { userId, actor } = req.auth

    res.json({ userId, actor })
  },
)

app.listen(3000, () => {
  console.log('Booted.')
})
```

There is an even easier way to use Clerk to impersonate a user–through your dashboard. Go to Users in your dashboard:

![Empower Support Team User Impersonation guide illustration](./b80a50270c2e867a35dd4822fa4c0fe576c3857e-2000x1090.png)

Then click to open the menu for the user you want to impersonate and choose "Impersonate user":

![Empower Support Team User Impersonation guide illustration](./a677bff1ae96063af5851ab123c37e66bd2aacfa-2000x1090.png)

Then, your support team is ready to impersonate a user straight away.

## More Support for Your Support Team

Adding user impersonation is a must for a well-functioning support team. It gives them to the tools they need to help your customers with their support needs without sacrificing privacy and security.

Getting it right in your application is a big challenge. Using an authentication solution such as Clerk with user impersonation built-in means you can easily have this embedded in your app, and you don’t have to worry about incorporating errors that lead to security issues. Check out the [Clerk user impersonation docs](/docs/custom-flows/user-impersonation#user-impersonation) to learn more about setting this up quickly with Clerk.

---

# Clerk Webhooks: Getting Started
URL: https://clerk.com/blog/webhooks-getting-started.md
Date: 2023-09-29
Category: Guides
Description: Learn how to get started with Webhooks to build integrations in a Nextjs application with Clerk's fully-featured authentication.

In an age of software that is composed of decoupled services built by specialized (often outsourced) teams, webhooks play an important architectural role. Webhooks enable us to outsource important user interactions and services to external platforms that are specifically designed for those purposes, and still have our applications be able to respond to those interactions.

For example, Clerk is specifically designed to handle authentication and user management related interactions on behalf of your applications. Webhooks allow Clerk to notify your application of these interactions so that you can implement custom follow-up logic. These interactions include (but are not limited to) signing in, changing profile information, creating an organization, or getting invited to an organization. Clerk ensures that all these important interactions are handled securely and responsively, while giving you a way to implement follow-up logic.

In this blog post we will build a simple webhook integration in a Next.js project. We will also explore the use cases of webhooks with Clerk and discuss how to best handle webhooks for production-ready applications.

This post assumes basic familiarity with Next.js and Clerk.

## Setting up Webhooks in Next.js

For this walkthrough we will start with a Next.js project that is already setup with Clerk. However, you can create a webhook subscription in any server-side web framework like Express or Fastify.

If you don’t already have a Next.js project setup with Clerk, you can start by cloning the Clerk Next.js App Router template.

```bash
git clone https://github.com/clerkinc/clerk-next-app.git
```

This will create a minimal Next.js project fully setup with Clerk’s embedded components and a secured dashboard page.

Create a `.env.local` file in the root of the project and add your keys here from the Clerk dashboard.

```env {{ title: '.env.local' }}
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_clerk_pub_key
CLERK_SECRET_KEY=your_clerk_secret_key
```

Let’s create an API route that will handle the Clerk webhook. This handler will live in `app/api/clerk/route.ts` and will have the URL of `your-app.com/api/clerk`.

Webhooks are POST requests by default, so let’s create a handler for receiving POST requests.

```typescript {{ title: 'app/api/clerk/route.ts' }}
export async function POST(request: Request) {}
```

The webhook event data is available as the request payload. Let’s parse it out and log it to the console.

```typescript {{ title: 'app/api/clerk/route.ts' }}
import { WebhookEvent } from '@clerk/nextjs/server'

export async function POST(request: Request) {
  const payload: WebhookEvent = await request.json()
  console.log(payload)
}
```

Clerk provides a `WebhookEvent` type for strong typescript inference. For now we will simply assert the webhook payload to be of this type.

Let’s also create a simple GET handler to test if we can access this URL.

```typescript {{ title: 'app/api/clerk/route.ts' }}
import { WebhookEvent } from '@clerk/nextjs/server'

export async function POST(request: Request) {
  const payload: WebhookEvent = await request.json()
  console.log(payload)
}

export async function GET() {
  return Response.json({ message: 'Hello World!' })
}
```

Add this endpoint as a public route to the Clerk middleware

```typescript {{ title: 'middleware.ts' }}
import { authMiddleware } from '@clerk/nextjs'

export default authMiddleware({
  publicRoutes: ['/', '/api/clerk'],
})

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

Start the development server.

```bash
npm run dev
```

Now we can navigate to this endpoint in the browser.

![Endpoint GET response screenshot](./972a73b2d937d644c6bb5a9b2f0134f8d8106f22-4000x1256.png)

That’s all we need to setup a simple webhook endpoint! Now we can provide Clerk with a URL to this endpoint, and we can start receiving events.

However, we are not ready to test this locally yet. While the application is accessible on `localhost` in our machine, it’s not accessible to anything outside our local network. Since webhook requests are originated from Clerk’s servers, the `localhost` URL will just point back to the Clerk server instead of our machine.

![Local network firewall access diagram](./b791b1246f3bf158efb58bbe197a82e9c49f7481-4000x2400.png)

While we could provide Clerk with the public IP address of our machine, any incoming requests to our local home/work networks will be blocked by firewalls.

![Firewall blocking external access diagram](./9ed5794a6cf6a053731e4eb9154f320829866cf6-4000x2400.png)

To work around this problem, we can use a tunneling service like [localtunnel](https://theboroer.github.io/localtunnel-www), which creates a secure tunnel to our local machine from the cloud.

![Localtunnel architecture diagram](./5016844b43d4fc00cf02cd6daf6b815f3ce48f5f-4000x2400.png)

Let’s setup localtunnel in a new terminal window.

```bash
npm install -g localtunnel
```

Once the installation is complete, we can create a tunnel to our local server.

```bash
lt --port 3000
```

You should see an output in your terminal like this.

![Localtunnel terminal output screenshot](./1d3c3bc2a40be4e3231b8a4017a53fb5418915af-4000x1256.png)

Localtunnel will generate a random URL on the `loca.lt` domain that will point to your locally running server on port 3000. We can navigate to this new URL in our browser.

Localtunnel has a security mechanism built in to prevent abuse from malicious actors and phishing links. It asks for the public IP address of your local machine to ensure that it’s really you trying to access your application. Follow the instructions on this page to get your public IP address, and submit it on this page.

Once that’s done, we can access our application on this URL. We should also be able to access our webhook endpoint.

If the application doesn’t show up, make sure both the nextjs server and localtunnel are running on separate terminal windows.

Now we are ready to plug our endpoint into Clerk’s dashboard. Go to the Webhooks page, and click Add Endpoint. Enter the localtunnel URL here. You can also add a description for this endpoint.

![Add webhook endpoint in Clerk dashboard screenshot](./f593b54494ffd98bd34a4c372921c8a898a92199-4000x2596.png)

Here you can select which specific events you want to receive at this endpoint. Let’s leave these unselected for now so that we can receive webhooks for all events. Hit Create.

Once the webhook endpoint is created, we can navigate to the Testing tab. Here we can trigger an example event manually to test our webhook endpoint. Select any event from the dropdown, and hit Send Example.

![Send example webhook event screenshot](./4006a769624fd7e31d9e62b3e6381ca8ca55019f-4000x3972.png)

If your application is running locally and tunneling is set up correctly, you should see a message in your console with the example event.

![Webhook payload logged in console screenshot](./97d57b6839a70569bf7698ee2a479568f7ff92a2-4000x1904.png)

You will also see a log entry in the Testing tab that shows the status of the webhook.

![Webhook delivery status log screenshot](./7dbbcb838ce8602bce5cce8fb1610b0512a1de01-4000x1412.png)

Even though the webhook was correctly received and logged to the console, the dashboard marks the webhook delivery as failed. To ensure that the delivery is marked as succeeded, we need to return a success response from our endpoint.

```typescript {{ title: 'app/api/clerk/route.ts' }}
export async function POST(request: Request) {
  const payload: WebhookEvent = await request.json()
  console.log(payload)
  return Response.json({ message: 'Received' })
}
```

Let’s send another example event. This time it the webhook should be marked as succeeded.

![Successful webhook delivery screenshot](./d1f7fd540f886be2559a152cd905f86e7a7bb64b-4000x1636.png)

Now we can test the webhook with real events. Navigate to your application and sign up with a new account. This should log two webhook events in the console - a `user.created` and a `session.created` event.

Congratulations, we now have a functioning webhook receiver in our application! We can now further explore what events are triggered by Clerk. For example,

- Updating the user profile sends a `user.updated` event
- Signing out of the application sends a `session.ended` event
- Remotely signing out a different device will result in a `session.revoked` event
- Creating a new organization will trigger an `organization.created` and an `organizationMembership.created` event

We can also see logs for real webhook events in the dashboard.

![Clerk dashboard webhook logs screenshot](./08a50b64eb3680e584d89b53cb1fd01c34db2fcf-4000x2636.png)

When you deploy this app to a cloud environment like Vercel, you will need to create a new endpoint in the Clerk dashboard that points to the deployed application instead of a localtunnel URL.

Note that localtunnel will generate a random URL everytime we start the tunnel, which means everytime we are testing with webhooks locally, we will need to create a new endpoint in the Clerk dashboard. To solve this, we can ask localtunnel to provision a specific URL by adding a `--subdomain` argument.

```bash
lt --port 3000 --subdomain unique-url-name
```

If the requested URL is available, it will be provisioned for us instead of a randomly generated URL. This will allow us to reuse the same endpoint in the Clerk dashboard everytime we are testing locally.

## Webhook Use Cases

So now that we are receiving webhook events from Clerk, what can we do with it?

### Data Synchronization

While Clerk’s own database acts as the primary source of truth for authentication and user management, you can create a copy of this data in your own database which gets updated asynchronously through webhooks. This allows you to query your own database for user data instead of relying on Clerk’s APIs, along with flexibility with the data model, complex queries, transactional guarantees, and real time behavior. This mechanism is called **data synchronization**.

### Event Driven Systems

Some advanced use cases might rely on asynchronous workflows and background jobs, such as sending notifications to users or other external systems. These workflows can be triggered to execute when a webhook event is received, for example, sending new users an onboarding email to your application, or subscribing them to mailing lists for software updates and promotional campaigns. Such systems are called **event driven systems**.

### Bring Your Own Email/SMS

Clerk allows you to bring your own Email and/or SMS servers for delivering auth-related messages which would usually be delivered by Clerk. Whenever an auth-related message is created, Clerk sends a webhook event with that message to your application. You can configure Clerk to not deliver these messages in the Clerk dashboard, and instead handle the delivery yourself by listening to the webhook events. (add links to HWR and docs)

We will walk through implementing some of these use-cases in future articles.

## Webhook Best Practices

While setting up a simple webhook receiver for testing purposes is straightforward, operating a webhook-driven system in production requires some additional work. Clerk implements webhook deliveries through [Svix](https://www.svix.com), a service that specializes in handling webhook deliveries. Svix manages concerns like scalability, logging, retries, security, and delivery guarantees. However, we still need to ensure that our application is setup to receive and process webhooks correctly. Let’s explore some best practices for implementing webhook endpoints for production-ready applications.

### Error Handling

Webhook deliveries are marked as successful or failed depending on the HTTP response returned by our webhook endpoint. A failed webhook delivery is retried with exponential backoff until it succeeds, ensuring that our application will never miss an event. The exponential backoff ensures that our application servers are not overloaded with retries and explode server resources.

Our webhook endpoints should be setup to return a successful response (20x) if everything went well. But in case of an error during the processing of a webhook, we can simply throw an error response (40x or 50x) and expect a retry, which often succeeds. We can also monitor the webhook status in the Clerk dashboard, which provides observability into failed webhook deliveries and help discover issues.

```typescript {{ title: 'app/api/clerk/route.ts' }}
import { WebhookEvent } from '@clerk/nextjs/server'

export async function POST(request: Request) {
  try {
    const payload: WebhookEvent = await request.json()
    console.log(payload)

    // process the event

    // everything went well
    return Response.json({ message: 'Received' })
  } catch (e) {
    // something went wrong
    // no changes were made to the database
    return Response.error()
  }
}
```

### Security

Since webhooks requests can originate on any remote server, webhook endpoints are vulnerable to attacks from malicious actors. Securing webhook endpoints is important to ensure malicious actors cannot make unwanted changes to your application.

Svix adds security measures to webhook requests by adding a secure hash in the request headers created using a secret key. We can use the `svix` library in our webhook endpoint to validate that the request was sent by a legitimate Svix server and not a malicious actor.

```typescript {{ title: 'app/api/clerk/route.ts' }}
import { WebhookEvent } from '@clerk/nextjs/server'
import { headers } from 'next/headers'
import { Webhook } from 'svix'

const webhookSecret = process.env.CLERK_WEBHOOK_SECRET || ``

async function validateRequest(request: Request) {
  const payloadString = await request.text()
  const headerPayload = headers()

  const svixHeaders = {
    'svix-id': headerPayload.get('svix-id')!,
    'svix-timestamp': headerPayload.get('svix-timestamp')!,
    'svix-signature': headerPayload.get('svix-signature')!,
  }
  const wh = new Webhook(webhookSecret)
  return wh.verify(payloadString, svixHeaders) as WebhookEvent
}

export async function POST(request: Request) {
  const payload = await validateRequest(request)
  console.log(payload)
  return Response.json({ message: 'Received' })
}
```

We can get the webhook signing secret from the Clerk dashboard and store in a `CLERK_WEBHOOK_SECRET` environment variable.

![Webhook signing secret screenshot](./cb560fdd36109e0abd0ee80c2cdbc83ff625a859-4000x2596.png)

Now our webhook endpoint is fully secure and ready to be deployed to production servers.

### Selective Events

In our walkthrough, we configured Clerk to trigger the webhook endpoint for all events. While this was useful for testing, we want to minimize the use of server resources by only processing events that we actually care about.

For production endpoints, we can apply event filters in the Clerk dashboard by selecting the events that we are processing in the application, and leaving everything else unselected.

![Select webhook events screenshot](./0d52d69df0819bc7ac254509dddc9864c0764a63-4000x2176.png)

## Summary

Webhooks play an important role in creating unified user experiences through integrations like data sync and event driven systems. In this article we setup a simple webhook endpoint, explored some use cases, and addressed concerns like security and error handling.

We will dive deep into specific use cases around data sync and event driven systems in future blog posts and walk through implementing them into our projects.

To learn more about webhooks, check out [the ultimate webhooks guide](/blog/what-are-webhooks), or to learn more about the webhook events exposed by Clerk, [read the documentation](/docs/integrations/webhooks/overview).

---

# 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).

---

# How We Roll – Chapter 10: Roundup
URL: https://clerk.com/blog/how-we-roll-roundup.md
Date: 2023-08-11
Category: Company
Description: How We Roll is a deep dive into how Clerk implements authentication. This chapter provides a roundup of the topics discussed in this series.

Welcome to How We Roll! This series is meant to help product owners, developers, and security professionals understand exactly how we implement (or, *roll*) authentication at Clerk.

## **Chapter 10: Roundup**

Clerk is more than just a set of authentication APIs - it’s a tool that offers a comprehensive solution for user management with **User Experience**, **Application Security**, and **Developer Experience** as the core tenets. The last nine chapters of How We Roll have been in-depth explorations into Clerk’s auth implementation. For this 10th chapter, we will round up all the topics described thus far and see how everything fits together through the lens of these three core tenets.

If this is your first time reading a post in our How We Roll series, this chapter will serve as an index to this series and the topics covered within. From here, you can choose which topics you want to learn more about and visit the chapters dedicated to those topics.

## User Experience

Let’s jump into the shoes of a user and experience Clerk from a user’s perspective.

Clerk’s embeddable components handle every authentication-related user interaction. This goes beyond sign-up, password reset, and OAuth flows – the User Profile is one of Clerk's most comprehensive authentication components. We believe that the user should have complete control over their authentication data and sessions, which is reflected in the self-service capabilities of the User Profile. Users can access and modify their profile, OAuth accounts, passwords, multi-factor steps, and active devices, all from a single `<UserProfile />` component.

[Learn how Clerk rolls the User Profile](/blog/how-we-roll-user-profile)

Every embeddable component provided by Clerk is also used on [dashboard.clerk.com](https://dashboard.clerk.com), which allows us to study and optimize every interaction in depth and offer the best possible out-of-the-box experience. However, we also acknowledge that every company and product must assert its brand identity on every user interface. This is reflected in the extensive customization options provided for Clerk’s components.

[Learn how Clerk rolls Customization](/blog/how-we-roll-customization)

Avatars are a critical component of user identity but are usually treated as an afterthought. Clerk brings a lot of care into ensuring that user avatars are high quality and are present throughout the authentication interactions to build a sense of user identity. Little details like the shimmer effect on hover and beautifully marbled default avatars elevate the user experience.

[Learn how Clerk rolls Avatars](/blog/how-we-roll-avatars)

## Application Security

While user experience is something we put a lot of effort into, the biggest priority for an auth provider like Clerk is application security.

The web has been slowly moving towards a passwordless application experience by embracing various forms of Single Sign-On. However, passwords are still the most familiar form of authentication. While over half of all signups happen through Single Sign-On providers like Google, Clerk ensures that the users and developers who prefer passwords are not under-served. Clerk’s default password requirements ensure that passwords are strong and compliant with NIST guidelines, implement countermeasures to detect breached passwords, and provide developers the flexibility to configure password rules.

![How We Roll Roundup guide illustration](./a43eae985fcc2f06e8c87db46569fa470ff85f50-2400x1260.png)

[Learn how Clerk rolls Passwords](/blog/how-we-roll-passwords)

Email verification is an essential piece of authentication. Password reset, account management, and team invitations require the presence of an email, and verification is necessary to mitigate spam or bot accounts. Clerk is configured by default to verify user emails before allowing sign-ups and employs both link-based and OTP-based verifications. For OAuth flows, if there is a question as to whether the OAuth provider verified the user’s email, Clerk requires an additional email verification step.

[Learn how Clerk rolls Email Verification](/blog/how-we-roll-email-verification)

Clerk’s implementation of Sessions enables various security capabilities. Clerk tracks the client devices used to sign in, along with the timestamps of the most recent sign-in and user activity, so users can quickly identify devices that are not supposed to be signed into their account and promptly sign out of them. Clerk also ensures that the application will never be in an invalid auth state (signed out, changed permissions, etc.) for more than 60 seconds through short-lived tokens.

![How We Roll Roundup guide illustration](./eefb254ce7a5410af709348cd9ee05250aa25cad-2400x1260.png)

[Learn how Clerk rolls Sessions](/blog/how-we-roll-sessions)

Clerk provides Multifactor Auth through SMS verification, Authenticator apps, and physical security keys for the more security-conscious folks. Users can choose to use their preferred factor for MFA within the options developers enable.

[Learn how Clerk rolls Multifactor](/blog/how-we-roll-multifactor)

## Developer Experience

Authentication should not be a hassle for developers to implement. Clerk makes it ridiculously easy for developers to get up and running with fully functioning auth.

A secure and scalable authentication infrastructure goes beyond simple client-server systems. Clerk’s robust infrastructure delivers the end-to-end authentication user experience and makes onboarding extremely easy for front-end developers. Clerk also eliminates specific configuration steps until developers are ready to release to production, ensuring absolute security across all authentication flows.

![How We Roll Roundup guide illustration](./145b05891db45736be24882aa1ac20a187db1fe6-1200x671.png)

[Learn how Clerk rolls Infrastructure](/blog/how-we-roll-infrastructure).

While Clerk’s SDKs provide easy integration with backend applications, developers might wish to leverage a Backend-as-a-Service provider like Supabase instead of building their own. Clerk also offers seamless integration with these providers with minimal effort from the developers through JWT Single Sign-On.

[Learn how Clerk rolls JWT SSO](/blog/how-we-roll-jwt-sso)

## Summary

The nine topics covered in this series are by no means an exhaustive list of how Clerk implements authentication. However, these topics demonstrate the care and effort put into making Clerk applications secure, easy to start, and a great user experience.

---

# How We Roll – Chapter 9: Infrastructure
URL: https://clerk.com/blog/how-we-roll-infrastructure.md
Date: 2023-08-04
Category: Company
Description: How We Roll is a deep dive into how Clerk implements authentication. This chapter covers the infrastructure that powers Clerk’s authentication capabilities.

Welcome to How We Roll! This series is meant to help product owners, developers, and security professionals understand exactly how we implement (or, roll) authentication at Clerk.

## Chapter 9: Infrastructure

A system that provides secure authentication with a great user experience requires a lot of complex infrastructure. This goes beyond the typical client-server systems developers are familiar with and build.

- Sensitive data needs to be protected both in transmit and at rest
- Integrations with third party services need to be configured and orchestrated
- Work needs to be delegated to background to keep the application responsive
- Failures and timeouts need to be handled and observable to developers
- Operations need to be scalable to handle millions of users

In this chapter of How We Roll, we will explore the infrastructure that is required to build and operate an authentication system, and dive into the infrastructure that allows Clerk to offer an authentication experience that can be integrated into a project within minutes.

### Self-Hosted Auth

An application that implements auth directly or through imported libraries is self hosted, which means the developers have to manage the auth infrastructure on their own.

We can imagine an application with self-hosted auth that would look like this.

![How We Roll Infrastructure setup guide](./c8dbf4c3c324efaeef80269f07617b0418861410-1200x504.png)

The client would be a web, mobile, desktop, or console application that users interact with. The server provides the ability to sign in and check passwords, and the database is where the user data is stored securely.

The ability to send emails becomes a requirement very early, and is basically table-stakes for most consumer-facing applications. SMS is usually optional but is essential to many industries, and offering flexibility to the users to choose between email and phone is great experience.

![How We Roll Infrastructure setup guide](./5fefabb160b8972d644daa3ae2b5c793a8890727-1200x508.png)

This adds the infrastructure cost of either self-hosted servers or integrating with third-parties like [Sendgrid](https://sendgrid.com) and [Twilio](https://www.twilio.com).

Along with the development cost spent into the integration, sending email and text notifications is often high latency and failure-prone. If these operations are performed in the regular request-response cycle, it results in bad user experience since requests take too long to get a response.

![How We Roll Infrastructure setup guide](./832787cf55ca55b172cbe0da0c52ff262f687fe5-1200x554.png)

Delegating these operations to asynchronously-scheduled background jobs becomes necessary to ensure the application is snappy and responds to user interactions quickly. The jobs must ensure that all notifications are delivered, retried on failure, and offer developers observability into failures and bottlenecks. This can also be delegated to a provider like [Upstash](https://upstash.com), which again adds more cost of integration.

OAuth integration requires acquiring credentials and building adapters for each OAuth provider. The latter can usually be delegated to an open-source library like [NextAuth](https://next-auth.js.org).

This is not an exhaustive list. Some use-cases require additional infrastructure like SAML integration, blockchain adapters, compliance guarantees, or bot detection.

### Clerk-Hosted Auth

Clerk is designed to allow developers to build applications that look like this.

![How We Roll Infrastructure setup guide](./c07d33983423a94d4161a25b242ad4af255d3440-1200x339.png)

Clerk offers complete authentication capabilities directly on the client. Developers are not required to host a server to enable Clerk’s auth. This also allows Clerk to offer a great user experience and developer experience through pre-built components.

That said, many applications will have their own server and database. However, all auth-related responsibilities are delegated to Clerk, and Clerk’s backend package makes integration on the server easier and supports all non-node environments.

![How We Roll Infrastructure setup guide](./bb3661a1bd785eecaba37c2323a94239af4d73d3-1200x463.png)

But since the server is optional, developers can decide to not host one at all, and leverage a Backend-as-a-Service solution like [Firebase](https://firebase.com). Clerk also offers integrations to popular BaaS providers through [JWT Single Sign-On](/blog/how-we-roll-jwt-sso).

![How We Roll Infrastructure setup guide](./e53ed34009c8057fc66521edb69b09c7846222b3-1200x350.png)

Let’s zoom into the diagram and explore the infrastructure that powers the Client-Server integrations.

![How We Roll Infrastructure setup guide](./b9f130f6f7268d2037d6ff77cd3edf63b7dfaf8b-1200x630.png)

The [Javascript library](/docs/reference/clerkjs/installation) and [pre-built components](/docs/components/overview) interact with Clerk’s [Frontend API](/docs/reference/frontend-api), which is where the user signs in. For magic-link and OAuth based flows, the API redirects the user back to the Client after a sign in. Clerk is responsible for syncing the sign-in session with the Client.

The [Backend API](/docs/reference/backend-api) powers the [backend SDKs](/docs/references/javascript/overview) that authenticate client requests and access user data stored in Clerk’s database. The backend also delivers events to the application Server through [Webhooks](/docs/integrations/webhooks/overview) to enable asynchronous and event-based systems.

![How We Roll Infrastructure setup guide](./6e05d46aeec5d06570e9db1d684142c8cda6d648-1200x630.png)

Internally Clerk is split into the Frontend and Backend API services that run on the highly scalable and efficient runtime of [Google Cloud Run](https://cloud.google.com/run). The API services share access to the data, which is managed by [Google Cloud SQL](https://cloud.google.com/sql) and stored with security and integrity guarantees. Clerk also manages background jobs to delegate any non-critical work to. The background jobs also leverage Cloud Run and are configured with various priority levels, which are determined by the urgency of the operation being delegated (e.g. sending a message is high priority, cleanup tasks are low priority). This helps Clerk provide extremely responsive APIs, which is essential to ensure the authentication UX is fast and snappy.

![How We Roll Infrastructure setup guide](./32a8c39a636852fc2ee6866f4b28720d9b0e4ab9-1200x696.png)

Clerk also takes on the cost of integrating with other external services. SMS, Emails, and Webhooks are automatically delivered through [Sendgrid](https://sendgrid.com), [Twilio](https://www.twilio.com), and [Svix](https://www.svix.com) respectively, without any additional cost of integration. OAuth provisioning is also completely eliminated, as Clerk provides shared OAuth credentials and adapters for most popular OAuth services that can be enabled with a simple switch.

Since Clerk powers the complete end-to-end authentication flow, any additional infrastructure that might be required for special use-cases, like SAML, blockchain, or security compliance, can be added by Clerk without developers having to build any extra integrations. [A recent release](/blog/changelog-2023-07-07) of Clerk included built-in bot detection, that allows developers to build AI applications that offer free credit to new users, while Clerk ensures that malicious actors cannot spam create new accounts and abuse free credits.

![How We Roll Infrastructure setup guide](./12bacf949d2dd15dcdb8cd4acb5dcb238632efe5-1200x786.png)

Bot detection capabilities are enabled by a combination of Clerk’s in-house countermeasures and [Cloudflare](https://cloudflare.com), which are made available to Client applications out of the box.

### Bring your own Infra

Thanks to this infrastructure, getting up and running with fully functional auth in an application is a matter of minutes with Clerk. However, for various reasons, developers will prefer to leverage some of their own infrastructure. Clerk can be configured to not deliver messages if the developers wish to use their existing Email or SMS servers. Clerk sends webhook events for those messages to the application server, which can then integrate with self-provisioned Email and SMS servers to deliver the message to the user.

### Bring your own Configuration

Another contributor to Clerk’s quick onboarding experience is shared DNS and OAuth configurations.

![How We Roll Infrastructure setup guide](./9e7145464a1c7845cb548d9d7e621c4962f3d8c2-1200x630.png)

In a development instance, Clerk’s Frontend API is hosted on a subdomain of `accounts.dev`. This subdomain is a randomly generated slug unique to each application, e.g. `random-dove-45.accounts.dev`. The API is fully functional cross-origin, so the client application can be running on any domain, including `localhost` and [preview deployments](/docs/deployments/vercel), and will have full access to all of Clerk’s auth. Emails are automatically sent from an address like `no-reply@accounts.dev`, and OAuth flows use shared credentials.

While the cross-origin authentication capability contributes to the extremely quick onboarding DX of Clerk, it opens up vulnerabilities to certain cross-site scripting attacks, since sensitive authentication tokens are being shared across origins. This also means that [magic links](/blog/magic-links) and emails use a Clerk-owned `accounts.dev` URL instead of the application URL, which is a non-starter for production applications. Similarly, OAuth consents are provided to a third-party (Clerk) instead of to the application directly.

In a [production instance](/docs/deployments/overview), Clerk requires developers to add some DNS settings to their production domain, which allows Clerk to host the Frontend API at a subdomain of the application’s own origin. This eliminates cross-site vulnerabilities and guarantees absolute security of the application across all authentication flows. All links and email addresses also use the application’s domain so the risk of users mistaking

Clerk also requires production instances to have their own OAuth credentials so that all OAuth consents are provided directly to the application owner.

![How We Roll Infrastructure setup guide](./2e3b8c93ba1f2a09ed6364463caf39a8b54845f4-1200x630.png)

In addition to full security, hosting the API as a subdomain of the Client origin allows any other subdomain to access the same sign-in sessions as the primary Client. Users only need to sign-in once, and the session is automatically made available Clients on any subdomain by the Frontend API.

![How We Roll Infrastructure setup guide](./fa6fe5bacac768babc9a82ae80521aaeb3c9c1b3-1200x630.png)

## Summary

Clerk is designed not only to serve all the authentication needs of modern web applications, but to provide developers with an extremely easy onboarding experience along with the flexibility to turn off certain parts and integrate with their own systems. Clerk goes above and beyond with infrastructure to ensure that no compromises are made in terms of user and developer experience.

## How We Roll Series Index

- [How We Roll – Chapter 1: Passwords](/blog/how-we-roll-passwords)
- [How We Roll – Chapter 2: Avatars](/blog/how-we-roll-avatars)
- [How We Roll – Chapter 3: Multifactor](/blog/how-we-roll-multifactor)
- [How We Roll – Chapter 4: Email Verification](/blog/how-we-roll-email-verification)
- [How We Roll – Chapter 5: Customization](/blog/how-we-roll-customization)
- [How We Roll – Chapter 6: User Profile](/blog/how-we-roll-user-profile)
- [How We Roll – Chapter 7: JWT Single Sign-On](/blog/how-we-roll-jwt-sso)
- [How We Roll – Chapter 8: Sessions](/blog/how-we-roll-sessions)
- [How We Roll – Chapter 9: Infrastructure](/blog/how-we-roll-infrastructure)
- [How We Roll – Chapter 10: Roundup](/blog/how-we-roll-roundup)

---

# 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) 👋

---

# How We Roll – Chapter 8: Sessions
URL: https://clerk.com/blog/how-we-roll-sessions.md
Date: 2023-07-21
Category: Company
Description: How We Roll is a deep dive into how Clerk implements authentication. This chapter covers how Sessions unlock security and performance capabilities for Clerk.

Welcome to How We Roll! This series is meant to help product owners, developers, and security professionals understand exactly how we implement (or, roll) authentication at Clerk.

## Chapter 8: Sessions

One of the primary objectives of Clerk is to ensure application security while providing the developer with ways to adjust it. Clerk’s auth is configured for a smooth user experience by default, but developers can enable additional layers of security like [multi-factor auth](/docs/authentication/custom-flows/multifactor) depending on the needs of the business.

Sessions is another tool in the authentication toolkit that allows fine-tuning of application security and user experience. A session is an abstract concept that refers to the period of time that a user is signed-in to an application. Like most abstract concepts, it can be modeled and designed to fit your needs.

Before describing Sessions, it’s helpful to grasp the idea of Clients.

### Clients

If a Session is the period of time a user is logged in, the Client is the device with which the user is logged in. Clients can be browsers, native applications, or any other medium that is usually the requesting part in a request/response architecture.

It’s also helpful to think of a Client as a running instance of ClerkJS. When the ClerkJS library is loaded into a browser by an application, it creates an active Client instance. A Clerk Client supports connecting to multiple sessions. This allows users to be logged in to multiple accounts at the same time and easily switch between them.

To learn more about multi-session handling [read the documentation](/docs/authentication/multi-session-applications).

Clerk stores information about the Client and the device it’s running on. This allows users to easily identify which devices they have logged in with and sign that device out of their account. This feature is crucial in case the device gets lost or stolen, or an account gets compromised.

![How We Roll Sessions guide illustration](./142db168fc61365864c470ef858a2001e034bc73-1818x1424.png)

### Creating a Session

To achieve the “Sign out of this device” functionality, Clerk stores the Session that is created when a user logs in. This Session object stores a reference to the Client that was used to create it. In the account security section, Clerk shows all the Sessions for the current user along with the Client information, and when the Session was created to further help identify what devices should and should not be signed in. Signing out from a Client is as simple as deleting the Session object.

Sessions have a maximum lifetime that can be adjusted on the Clerk Dashboard in the Sessions tab. If the application attempts to authenticate with an expired session, the authentication will fail and the user will have to log in again.

Upon sign-in, a reference to the created Session is stored in the `__client` cookie. This cookie is *Secure* and *HttpOnly*, so it’s inaccessible to [MitM](https://developer.mozilla.org/en-US/docs/Glossary/MitM) and [XSS](https://developer.mozilla.org/en-US/docs/Web/Security/Types_of_attacks#cross-site_scripting_xss) attacks.

From here, this cookie can be used to authenticate with an application. When an HTTP request is received, the cookie can be used to fetch the Session object which has the user ID. If the Session doesn’t exist, the user has signed out of this Client, and the request would throw an Unauthorized error.

However, this process adds extra overhead to the request by introducing a database call. Usually developers attempt to mitigate this overhead by storing the Session object in memory, or in a low-latency store such as a Redis cache. This reduces the cost of fetching the Session object, but requires additional infrastructure to scale.

### Web APIs love JWTs

[JWTs](/blog/guide-JWT-authentication-JSON-Web-Tokens) were invented primarily to solve this additional overhead problem. Since JWTs can be verified to have been generated on a trusted server, the contents of the JWT can be trusted. This means Clerk can encode the Session object into a JWT, which the Client will use to authenticate with the application. When the application receives an HTTP request, the verified token can be used to access the Session object and process the request, instead of having to fetch the Session object from Clerk’s Backend API. The overhead required to verify a JWT is significantly lower than fetching data over a network. This Session token is stored in the `__session` cookie where it’s accessible to the Client. Alternatively, the Client can store this Session token in the browser’s local storage or a native equivalent, and pass it to the server through the Authorization HTTP header.

**JWKS refresher:** [JSON Web Key Set (JWKS)](https://medium.com/javarevisited/json-web-key-set-jwks-94dc26847a34) is a way for an application to advertise the public key that can be used to verify that a token was generated and signed by that application. Clerk applications expose their public keys at the `clerk.your-site.com/.well-known/jwks.json` endpoint.

When an API receives a request with a token, the JWKS is used to verify that the token was generated by Clerk. The API server fetches the JWKS at startup time and stores it in memory to save the network latency of fetching JWKS on demand. JSON Web Keys are stable and don’t need to be refreshed.

However, since the Session object is now stored on the Client that created it, only this Client is able to invalidate or terminate the session. This removes the ability to remotely sign out from a specific device. So while JWT Sessions solve the extra overhead, they disable a key security feature.

### It Always Comes Down To Cache Invalidation

Since the ability to remotely sign out of devices is a crucial feature, the source of truth has to be the Session object stored on the server. It cannot be the one stored on the Client. But fetching from the database is expensive. Whereas the JWT essentially acts as a cached version of the Session object that can never be programmatically invalidated. It’s the other extreme of the spectrum.

Fortunately, JWTs have a lifetime of their own and can be set to expire at some point in the future. When Clerk generates a Session token for a sign-in, the token is set to expire 60 seconds into the future. This Session token can be used to authenticate for the next 60 seconds. A database fetch for the Session is only required once the token has expired and a new token needs to be generated.

When a Session is deleted (user signs out of a device), new tokens cannot be generated, but the most recently generated token can still be used if it was generated less than 60 seconds ago. This guarantees that authentication states in an application will never be invalid for more than 60 seconds.

This approach allows Clerk to offer highly performant authentication without compromising on the security benefits of persistent Sessions.

### Inactivity

Generating short-lived tokens for a long-lived session comes with an additional benefit - it is a great indicator of user activity. If the user stops interacting with the application for more than 60 seconds, a new Session token is not generated. The creation time of the most recent session token can be used by Clerk to determine when the user was last *using* the application instead of just being logged in.

Clerk allows developers to enable Inactivity timeout - this is the maximum amount of time the user can be away from the application and come back to it without having to log in again. Inactivity timeout can also be set on the Clerk Dashboard in the Sessions tab.

### Dynamic Permissions

Sessions are not only created and destroyed - they can also be mutated within their lifetime. The most common use case for mutating Sessions is changing permissions or authorization policies. While a user is logged into the application, they might get added to or removed from organizations, or their roles within an organization could change.

Clerk saves this information in the Session object and ensures it’s updated so that new Session tokens can cache it and the application can process the request without making additional calls to Clerk.

Clerk also allows customization of the Session tokens. Developers can add additional claims to the Session token in the Clerk Dashboard. Shortcodes can be used to inject user data and metadata. In this example, a new claim `verified` is added to the token. Users with an unverified email address will have this claim set to `false` in the token. Once they verify their email, the next Session token that is generated will have this set to true, so any access rules depending on this claim will work as expected.

To learn more about Session token customization [read the documentation](/docs/backend-requests/making/custom-session-token).

## Summary

Sessions are a very powerful tool for enabling security capabilities like multi-sign-in, inactivity timeout, remote sign-out, and dynamic permissions. Clerk takes on the burden of implementing the complex mechanism of Session handling so that developers have access to a performant and flexible authentication system that is easy to integrate.

To learn more about the elements of session management and relevant security concerns, check out [this blog post](/blog/what-is-session-management).

## How We Roll Series Index

- [How We Roll – Chapter 1: Passwords](/blog/how-we-roll-passwords)
- [How We Roll – Chapter 2: Avatars](/blog/how-we-roll-avatars)
- [How We Roll – Chapter 3: Multifactor](/blog/how-we-roll-multifactor)
- [How We Roll – Chapter 4: Email Verification](/blog/how-we-roll-email-verification)
- [How We Roll – Chapter 5: Customization](/blog/how-we-roll-customization)
- [How We Roll – Chapter 6: User Profile](/blog/how-we-roll-user-profile)
- [How We Roll – Chapter 7: JWT Single Sign-On](/blog/how-we-roll-jwt-sso)
- [How We Roll – Chapter 8: Sessions](/blog/how-we-roll-sessions)
- [How We Roll – Chapter 9: Infrastructure](/blog/how-we-roll-infrastructure)
- [How We Roll – Chapter 10: Roundup](/blog/how-we-roll-roundup)