Server-side authentication in Next.js 14
You can set up your Next.js App Router app to have access to the authentication state on the server.
Next.js 15 is not supported yet.
Setup
Make sure your React providers and middleware are correctly set up first.
Require authentication for certain routes
By default, all routes can be accessed without authenticating. You can configure
which routes require authentication in your middleware.ts
:
import {
convexAuthNextjsMiddleware,
createRouteMatcher,
nextjsMiddlewareRedirect,
} from "@convex-dev/auth/nextjs/server";
const isSignInPage = createRouteMatcher(["/signin"]);
const isProtectedRoute = createRouteMatcher(["/product(.*)"]);
export default convexAuthNextjsMiddleware((request, { convexAuth }) => {
if (isSignInPage(request) && convexAuth.isAuthenticated()) {
return nextjsMiddlewareRedirect(request, "/product");
}
if (isProtectedRoute(request) && !convexAuth.isAuthenticated()) {
return nextjsMiddlewareRedirect(request, "/signin");
}
});
export const config = {
// The following matcher runs middleware on all routes
// except static assets.
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};
In general, you'll likely want to redirect when an unauthenticated user tries to access a route that requires authentication.
To do this, you can pass a function to convexAuthNextjsMiddleware
. This
function can also be used to compose other middleware behaviors.
This function has as arguments the NextRequest
, the NextFetchEvent
, and the
ConvexAuthNextjsContext
. convexAuth.isAuthenticated()
and
convexAuth.getToken()
function similarly to isAuthenticatedNextjs
and
convexAuthNextjsToken
, but should be used in middleware to ensure they reflect
any updates to the request context from convexAuthNextjsMiddleware
.
Convex Auth provides an API and helper functions for implementing your middleware:
-
createRouteMatcher
is a helper function that uses the same syntax (opens in a new tab) as the middlewareconfig
. You call it with a list of glob patterns, and it returns a function that given theNextRequest
returns whether the route matches. -
nextjsMiddlewareRedirect
is a simple shortcut for triggering redirects:export function nextjsMiddlewareRedirect( request: NextRequest, pathname: string, ) { const url = request.nextUrl.clone(); url.pathname = pathname; return NextResponse.redirect(url); }
You can inline this code if you need more control over the target URL.
Configure cookie expiration
You can configure the expiration of the authentication cookie by passing a
cookieConfig
option to convexAuthNextjsMiddleware
.
export default convexAuthNextjsMiddleware(
(request, { convexAuth }) => {
// ...
},
{ cookieConfig: { maxAge: 60 * 60 * 24 * 30 } },
); // 30 days
If you don't set this option, the cookie will be considered a "session cookie" and be deleted when the browser session ends, which depends from browser to browser.
Preloading and loading data
To preload or load data on your Next.js server from your Convex backend, you can
use
preloadQuery
and fetchQuery
(opens in a new tab)
and the convexAuthNextjsToken
function from @convex-dev/auth/nextjs/server
:
import { convexAuthNextjsToken } from "@convex-dev/auth/nextjs/server";
import { preloadQuery } from "convex/nextjs";
import { api } from "@/convex/_generated/api";
import { Tasks } from "./Tasks";
export async function TasksWrapper() {
const preloadedTasks = await preloadQuery(
api.tasks.list,
{ list: "default" },
{ token: convexAuthNextjsToken() },
);
return <Tasks preloadedTasks={preloadedTasks} />;
}
Calling authenticated mutations and actions
You can call Convex
mutations (opens in a new tab) and
actions (opens in a new tab) from Next.js
Server Actions (opens in a new tab)
and POST
or PUT
Route Handlers (opens in a new tab).
import { api } from "@/convex/_generated/api";
import { fetchMutation, fetchQuery } from "convex/nextjs";
import { revalidatePath } from "next/cache";
export default async function PureServerPage() {
const tasks = await fetchQuery(api.tasks.list, { list: "default" });
async function createTask(formData: FormData) {
"use server";
await fetchMutation(
api.tasks.create,
{
text: formData.get("text") as string,
},
{ token: convexAuthNextjsToken() },
);
revalidatePath("/example");
}
// render tasks and task creation form
return <form action={createTask}>...</form>;
}
Security notice: ConvexAuthNextjsServerProvider
uses cookies to store
authentication state. Therefore to prevent
CSRF attacks (opens in a new tab) you must not perform any
side-effects from the Next.js server on GET requests. This means that only
Convex queries are safe to call from Server Components and GET
Route Handlers.
Essentially, a malicious site might cause your user's browser to make an
authenticated GET
request without the user's permission, but it won't be able
to read the response. Outside of GET
requests, Convex Auth makes
authentication state available only to same-origin requests.
Convex Auth is not special here, and the same security considerations apply to most other authentication solutions.