Tesseral for Next.js

Add B2B auth support to your Next.js app in just a few lines of code.

Tesseral’s Next.js SDK lets you add authentication to your Next.js application.

The Tesseral Next.js SDK is open-source and available on GitHub.

Getting Started

1

Sign up for Tesseral

Sign up for Tesseral at https://console.tesseral.com and create your project.

When signing up, you’ll be asked for your development URL. Choose http://localhost:3000.

2

Install @tesseral/tesseral-nextjs

In your Next.js codebase, add @tesseral/tesseral-nextjs to your project:

$npm install @tesseral/tesseral-nextjs
3

Add NEXT_PUBLIC_TESSERAL_PUBLISHABLE_KEY to your .env

Add the following line to your .env file:

NEXT_PUBLIC_TESSERAL_PUBLISHABLE_KEY=publishable_key_...

Replace publishable_key_... with your project’s Publishable Key. You get can your Publishable Key from the API Keys Settings settings in the Tesseral Console.

4

Add authMiddleware to your middleware.ts

Create a middleware.ts (or src/middleware.ts if you’re using the src directory) and make its contents be:

1import { NextRequest } from "next/server";
2import { authMiddleware } from "@tesseral/tesseral-nextjs/dist/middleware";
3
4export default authMiddleware;
5
6export const config = {
7 matcher: [
8 /*
9 * Match all request paths except for the ones starting with:
10 * - api (API routes)
11 * - _next/static (static files)
12 * - _next/image (image optimization files)
13 * - favicon.ico, sitemap.xml, robots.txt (metadata files)
14 */
15 "/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
16 ],
17};
5

Add TesseralProvider to your root layout

Go to app/layout.tsx (or src/app/layout.tsx if you use the src directory) and add TesseralProvider:

1import { TesseralProvider } from "@tesseral/tesseral-nextjs/dist/serverside";
2
3export default function RootLayout({ children }: { children: React.ReactNode }) {
4 return (
5 <html lang="en">
6 <body>
7 <TesseralProvider>
8 {children}
9 </TesseralProvider>
10 </body>
11 </html>
12 );
13}

TesseralProvider will redirect users to log in if they aren’t already. If your Next.js app serves both public and non-public pages, then add TesseralProvider at the layout for your non-public pages instead.

You’ve now added Tesseral to your Next.js application! From here, you can add auth checks to your:

Server Components (RSCs)

In Next.js layouts and pages, you can get the current User, and the Organization they work for, with await getUser() and await getOrganization().

getUser

To get the current User from a Server Component (RSC), use await getUser():

1import { getUser } from "@tesseral/tesseral-nextjs/dist/serverside";
2
3export default async function Page() {
4 const { id, email, displayName, profilePictureUrl } = await getUser();
5
6 return (
7 // ...
8 )
9}

getOrganization

To get the current Organization from a Server Component (RSC), use await getOrganization():

1import { getOrganization } from "@tesseral/tesseral-nextjs/dist/serverside";
2
3export default async function Page() {
4 const { id, displayName } = await getOrganization();
5
6 return (
7 // ...
8 )
9}

getUserSettingsUrl

Tesseral automatically provides a self-serve user settings UI to handle tasks like changing emails, resetting passwords, and configuring multi-factor authentication.

You can get a link to that UI using getUserSettingsUrl:

1import { getUserSettingsUrl } from "@tesseral/tesseral-nextjs/dist/serverside";
2
3export default async function Page() {
4 const userSettingsUrl = await getUserSettingsUrl();
5
6 return <a href={userSettingsUrl}>User Settings</a>;
7}

getOrganizationSettingsUrl

Tesseral automatically provides a self-serve organization settings UI to handle tasks like managing collaborators, creating and revoking user invites, and customizing login methods.

You can get a link to that UI using getOrganizationSettingsUrl:

1import { getOrganizationSettingsUrl } from "@tesseral/tesseral-nextjs/dist/serverside";
2
3export default async function Page() {
4 const organizationSettingsUrl = await getOrganizationSettingsUrl();
5
6 return <a href={organizationSettingsUrl}>Organization Settings</a>;
7}

Client Components

In Next.js Client Components, you can get the current User, and the Organization they work for, with useUser() and useOrganization().

useUser

To get the current User from a Client Component, use the useUser() hook:

1"use client";
2
3import { useUser } from "@tesseral/tesseral-nextjs/dist/clientside";
4
5export default function ClientComponent() {
6 const { id, email, displayName, profilePictureUrl } = useUser();
7
8 return (
9 // ...
10 )
11}

useOrganization

To get the current Organization from a Client Component, use the useOrganization() hook:

1"use client";
2
3import { useOrganization } from "@tesseral/tesseral-nextjs/dist/clientside";
4
5export default function ClientComponent() {
6 const { id, displayName } = useOrganization();
7
8 return (
9 // ...
10 )
11}

useHasPermission

To use useHasPermission, you’ll first need to set up Role-Based Access Control.

To check whether a user has permission to do an Action from a Client Component, use useHasPermission:

1import { useHasPermission } from "@tesseral/tesseral-nextjs/dist/clientside";
2
3export default function ClientComponent() {
4 const hasPermission = useHasPermission();
5
6 return (
7 <Button disabled={!hasPermission("acme.expense_reports.approve")}>
8 Approve Expense Report
9 </Button>
10 );
11}

hasPermission is a function that takes a string and returns a boolean.

useHasPermission is only for “look before you leap” use-cases. Only server-side code can ultimately enforce permissions.

To enforce permission checks from the server, see hasPermission from await auth().

useLogout

To force the current User to log out from a Client Component, use the useLogout() hook:

1"use client";
2
3import { useLogout } from "@tesseral/tesseral-nextjs/dist/clientside";
4
5export default function ClientComponent() {
6 const logout = useLogout();
7
8 return <button onClick={logout}>Log out</button>;
9}

useUserSettingsUrl

Tesseral automatically provides a self-serve user settings UI to handle tasks like changing emails, resetting passwords, and configuring multi-factor authentication.

You can get a link to that UI using useUserSettingsUrl:

1"use client";
2
3import { useUserSettingsUrl } from "@tesseral/tesseral-nextjs/dist/clientside";
4
5export default function ClientComponent() {
6 const userSettingsUrl = useUserSettingsUrl();
7
8 return <a href={userSettingsUrl}>User Settings</a>;
9}

useOrganizationSettingsUrl

Tesseral automatically provides a self-serve organization settings UI to handle tasks like managing collaborators, creating and revoking user invites, and customizing login methods.

You can get a link to that UI using useOrganizationSettingsUrl:

1"use client";
2
3import { useOrganizationSettingsUrl } from "@tesseral/tesseral-nextjs/dist/clientside";
4
5export default function ClientComponent() {
6 const organizationSettingsUrl = useOrganizationSettingsUrl();
7
8 return <a href={organizationSettingsUrl}>Organization Settings</a>;
9}

Route Handlers

To get authentication details about the current request in a Route Handler, call await auth():

1import { auth } from "@tesseral/tesseral-nextjs/dist/serverside";
2
3export async function GET(request: Request) {
4 const { organizationId, hasPermission } = await auth({ or: "return_404" });
5 // ...
6}

Server Actions

To get authentication details about the current request in a Server Action, you can use the same methods as in Server Components (RSCs):

1"use server";
2
3import { getUser } from "@tesseral/tesseral-nextjs/dist/serverside";
4
5export async function action() {
6 const user = await getUser();
7 // ...
8}

Using await auth()

The auth() function from Tesseral’s Next.js SDK works with both Users and API Keys. That’s why auth() is recommended for Next.js Route Handlers. You should also use auth() from code that gets called from both Server Components and Route Handlers.

auth() parameters

auth() takes one parameter, called or. or controls what happens if a request is not properly authenticated. It has three possible values:

  • await auth({ or: "throw" }) will throw a AuthError if the request is not properly authenticated. Use this if you want to have different behavior based on authenticated vs unauthenticated requests, using try / catch.

  • await auth({ or: "redirect" }) will redirect to the login page if the request is not properly authenticated. Use this for pages that are only meant to be used Users from their web browser.

  • await auth({ or "return_404" }) will call Next.js’s notFound() if the request is not properly authenticated. Use this if a 404 is the appropriate response for unauthenticated requests.

In all cases, you can always safely destructure the return value of await auth().

await auth() return value

await auth() returns an object with properties you can destructure:

1import { auth } from "@tesseral/tesseral-nextjs/dist/serverside";
2
3const {
4 organizationId,
5 credentialsType,
6 accessTokenClaims,
7 credentials,
8 hasPermission,
9} = await auth({ or: "throw" });

Getting the current Organization

To access the Organization the request is for from await auth(), use the organizationId property:

1import { auth } from "@tesseral/tesseral-nextjs/dist/serverside";
2
3const { organizationId } = await auth({ or: "throw" }); // returns a string like "org_..."

This is the most common identifier you’ll use in a B2B SaaS application.

Getting the request’s authenticated credentials

Anywhere your code wants to forward along the request’s credentials, use credentials:

1import { auth } from "@tesseral/tesseral-nextjs/dist/serverside";
2
3const { credentials } = await auth({ or: "throw" });

Do not log or expose this value. You usually don’t need to use this unless you’re building internal service-to-service calls.

Getting the type of credentials used

The credentialsType property is a string indicating how the request was authenticated. It will either be:

  • access_token if the request is from a User.
  • api_key if the request is from an API Key.
1import { auth } from "@tesseral/tesseral-nextjs/dist/serverside";
2
3const { credentialsType } = await auth({ or: "throw" });
4if (credentialsType === "access_token") {
5 // Handle logged-in user request
6} else if (credentialsType === "api_key") {
7 // Handle API key request
8}

Getting details about the current User

If the request is from a User, then accessTokenClaims will contain details about that User. If the request is from an API Key, then accessTokenClaims will be undefined.

1import { auth } from "@tesseral/tesseral-nextjs/dist/serverside";
2
3const { accessTokenClaims } = await auth({ or: "throw" });
4console.log(accessTokenClaims?.user?.email);

We recommend that you mostly use organizationId in the vast majority of your code; that is almost always the correct piece of information for most B2B SaaS code should pay attention to. For more details, see B2B Multitenancy.

Checking the requester’s permissions

To use hasPermission, you’ll first need to set up Role-Based Access Control.

To check whether a user has permission to do an Action, use hasPermission:

1import { auth } from "@tesseral/tesseral-nextjs/dist/serverside";
2
3const { hasPermission } = await auth({ or: "throw" });
4if (!hasPermission("acme.expense_reports.approve")) {
5 throw new AccessDeniedError();
6}

hasPermission is a function that takes a string and returns a boolean.