Next.js

Next.js integration uses middleware to refresh tokens on every request and the cookies() API from next/headers to apply auth cookies.

Middleware

The recommended approach is to call auth.refresh() in middleware.ts. This runs on every request before your pages render.

// middleware.ts
import { server } from "@robelest/convex-auth/server";
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

const auth = server({ url: process.env.CONVEX_URL! });

export async function middleware(request: NextRequest) {
  const { cookies, redirect, token } = await auth.refresh(request);

  // Handle OAuth redirects
  if (redirect) {
    const response = NextResponse.redirect(redirect);
    for (const cookie of cookies) {
      response.cookies.set(cookie.name, cookie.value, {
        path: cookie.path ?? "/",
        httpOnly: cookie.httpOnly,
        secure: cookie.secure,
        sameSite: cookie.sameSite as "lax" | "strict" | "none",
        maxAge: cookie.maxAge,
      });
    }
    return response;
  }

  const response = NextResponse.next();

  // Apply auth cookies
  for (const cookie of cookies) {
    response.cookies.set(cookie.name, cookie.value, {
      path: cookie.path ?? "/",
      httpOnly: cookie.httpOnly,
      secure: cookie.secure,
      sameSite: cookie.sameSite as "lax" | "strict" | "none",
      maxAge: cookie.maxAge,
    });
  }

  // Pass token via header for server components
  if (token) {
    response.headers.set("x-convex-token", token);
  }

  return response;
}

export const config = {
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};

Auth proxy route

Create app/api/auth/route.ts to handle client-side sign-in and sign-out:

// app/api/auth/route.ts
import { server } from "@robelest/convex-auth/server";

const auth = server({ url: process.env.CONVEX_URL! });

export async function POST(request: Request) {
  return auth.proxy(request);
}

Server component usage

In a server component or layout, read the token from cookies using next/headers and pass it into your app-owned client auth provider:

// app/layout.tsx
import { cookies } from "next/headers";
import { AuthProvider } from "./auth-provider";

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const cookieStore = await cookies();
  const token = cookieStore.get("convex-auth-token")?.value ?? null;

  return (
    <html>
      <body>
        <AuthProvider token={token}>{children}</AuthProvider>
      </body>
    </html>
  );
}

AuthProvider is your client component that creates the auth client with client({ convex, proxyPath: "/api/auth", tokenSeed: token }) and exposes it to the rest of your React tree.