If you want to interact with a working version of the Auth + Next integration that we'll be building in this guide, you can check the following GitHub repository, or clone it with the command below:

npx thirdweb create app --template thirdweb-auth-next

Auth Next example repository.

Installation & Setup

npm i thirdweb

Setup your .env file with the following:

# the DOMAIN is the domain of the application
# Get your client id from the thirdweb dashboard:
# Get your secret key from the thirdweb dashboard:
# A private key that will be used to sign the JWT for the `jwt-cookie` authentication method
# this does *not* need to hold any funds, just needs to be a valid private key to sign with

Client-side Setup

Create a lib directory inside src and create a client.ts file inside it:

// lib/client.ts
import { createThirdwebClient } from "thirdweb";
const clientId = process.env.NEXT_PUBLIC_THIRDWEB_CLIENT_ID!; // this will be used on the client
const secretKey = process.env.THIRDWEB_SECRET_KEY!; // this will be used on the server-side
export const client = createThirdwebClient(
? { secretKey }
: {

Add the ThirdwebProvider in your root layout:

// app/layout.tsx
import { ThirdwebProvider } from "thirdweb/react";
const Layout = ({ children }: { children: React.ReactNode }) => {
return <ThirdwebProvider>{children}</ThirdwebProvider>;
export default Layout;

There are two ways to setup Auth on the client-side of a Next.js application, the Connect Button or your own custom component. For both cases, we'll use a JWT in a cookie to store the user's session and authenticate across the app. The connect button will handle a lot of the underlying complexity for you, but if you would like to bring your own components the functions it uses are exposed for your custom use case.

Wherever you'd like your connect/login button, place the ConnectButton component.

// app/page.tsx
import type { NextPage } from "next";
import { ConnectButton } from "thirdweb/react";
import { client } from "@/lib/client";
import {
} from "@/actions/auth"; // we'll create this file in the next section
const Page = () => {
return (
isLoggedIn: async (address) => {
console.log("checking if logged in!", { address });
return await isLoggedIn();
doLogin: async (params) => {
console.log("logging in!");
await login(params);
getLoginPayload: async ({ address }) =>
generatePayload({ address }),
doLogout: async () => {
console.log("logging out!");
await logout();
export default Page;

Use this component anywhere in your application. To try it out, we'll put it in the root page.tsx:

// app/page.tsx
import ConnectButton from "@/components/ConnectButton";
const Home = () => {
return <ConnectButton />;
export default Home;

Server-side Setup

We'll use server functions to keep your login secure and concise.

Create an actions directory with a login.ts file with the following:

"use server";
import { VerifyLoginPayloadParams, createAuth } from "thirdweb/auth";
import { privateKeyAccount } from "thirdweb/wallets";
import { client } from "@/lib/client";
import { cookies } from "next/headers";
const privateKey = process.env.THIRDWEB_ADMIN_PRIVATE_KEY || "";
if (!privateKey) {
throw new Error("Missing THIRDWEB_ADMIN_PRIVATE_KEY in .env file.");
const thirdwebAuth = createAuth({
domain: process.env.NEXT_PUBLIC_THIRDWEB_AUTH_DOMAIN || "",
adminAccount: privateKeyAccount({ client, privateKey }),
export const generatePayload = thirdwebAuth.generatePayload;
export async function login(payload: VerifyLoginPayloadParams) {
const verifiedPayload = await thirdwebAuth.verifyPayload(payload);
if (verifiedPayload.valid) {
const jwt = await thirdwebAuth.generateJWT({
payload: verifiedPayload.payload,
cookies().set("jwt", jwt);
export async function isLoggedIn() {
const jwt = cookies().get("jwt");
if (!jwt?.value) {
return false;
const authResult = await thirdwebAuth.verifyJWT({ jwt: jwt.value });
if (!authResult.valid) {
return false;
return true;
export async function logout() {

You can include custom context in the JWT token with the context parameter:

const jwt = await thirdwebAuth.generateJWT({
payload: verifiedPayload.payload,
context: {
admin: true,

Now anywhere in your project, you can check a user's authentication status:

import { redirect } from "next/navigation";
import { isLoggedIn } from "../actions/auth";
const AuthenticatedPage = async () => {
// redirect back if user is not logged in
if (!(await isLoggedIn())) {
return (
<h1>Logged In Page</h1>
<p>You are logged in, so you can see this page!</p>
export default AuthenticatedPage;