Cookie-based JWT authentication for Next.js apps backed by a NestJS API.
@next-nest-auth/nextauth is the frontend half of a matched
authentication pair for full-stack TypeScript apps: this package handles
login, session, and token refresh on the Next.js (App Router) side, and
@next-nest-auth/nestauth
handles issuing and validating JWTs on the NestJS side. Together they
give you secure, httpOnly-cookie-based authentication with automatic
access/refresh token handling, without wiring it up from scratch.
Not related to Auth.js / NextAuth.js. This is a lightweight, purpose-built package for pairing a Next.js frontend with a NestJS backend β it is not a fork of, or drop-in replacement for, the popular
next-authpackage.
- π httpOnly cookie sessions β access and refresh tokens never touch
client-side JavaScript or
localStorage. - π Built-in refresh flow β a middleware-ready
refreshToken()helper for silently renewing expired sessions. - π§© Drop-in with
@next-nest-auth/nestauthβ matches its/nestauth/loginand/nestauth/refresh-tokenendpoint contract out of the box. - πͺͺ JWT claim decoding β read the logged-in user's claims with
getUserInfo(), no extra API call required. - π¦ TypeScript-first β ships its own type declarations, no
@typespackage needed. - π Authenticated fetch helpers β
get/postwrappers that attach the bearer token automatically.
- Next.js 13.4+ using the App Router (this package uses
next/headersand Next.js middleware APIs, which are not available in the Pages Router). - A backend implementing the
@next-nest-auth/nestauthlogin/refresh contract (or a compatible API β see Prerequisites).
npm install @next-nest-auth/nextauth
# or
yarn add @next-nest-auth/nextauth
# or
pnpm add @next-nest-auth/nextauthThis package is the client counterpart to
@next-nest-auth/nestauth.
Read that package's documentation first β it defines the backend endpoints
(/nestauth/login, /nestauth/refresh-token) and token response shape
this package expects.
Set the following in your Next.js app's .env:
| Variable | Required | Description |
|---|---|---|
NEXT_AUTH_API_URL or NEXT_PUBLIC_AUTH_API_URL |
Yes (one of the two) | Base URL of your NestJS backend. |
NODE_ENV |
Recommended | development or production. Controls whether auth cookies are marked secure (production only). |
AUTOEXPIRE_REFRESH_TOKEN |
No | When set, the refresh-token cookie's expiry is not extended on each token refresh β it expires on its original schedule. Default: unset (sliding expiry). |
BASE_URL |
No | Your Next.js frontend's own URL, for reference in redirect flows. |
NODE_ENV=development
BASE_URL=http://localhost:3000
NEXT_AUTH_API_URL=http://localhost:3001
# or
NEXT_PUBLIC_AUTH_API_URL=http://localhost:3001import { authenticate } from "@next-nest-auth/nextauth";
const response = await authenticate({
username: "user",
password: "password",
});import { NextRequest, NextResponse } from "next/server";
import { checkAuth, refreshToken } from "@next-nest-auth/nextauth";
export async function middleware(req: NextRequest) {
const protectedRoutes = ["/dashboard", "/profile", "/settings"];
if (protectedRoutes.some((route) => req.nextUrl.pathname.startsWith(route))) {
const authenticated = await checkAuth();
if (!authenticated) {
try {
return await refreshToken(req);
} catch (error) {
return NextResponse.redirect(new URL("/", req.url));
}
}
}
return NextResponse.next();
}
export const config = {
matcher: ["/dashboard/:path*", "/profile/:path*", "/settings/:path*"],
};import { getUserInfo, logout } from "@next-nest-auth/nextauth";
const user = await getUserInfo();
await logout();Authenticates the user against your NestJS backend and stores the returned
access and refresh tokens as httpOnly cookies.
import { authenticate } from "@next-nest-auth/nextauth";
const response = await authenticate({
username: "user",
password: "password",
});Renews the access token using the refresh token cookie. Designed for use in
Next.js middleware (it reads from req.cookies and returns a
NextResponse, since next/headers cookies() is not available there).
import { refreshToken } from "@next-nest-auth/nextauth";
const refreshedResponse = await refreshToken(req);Decodes the current access token and returns its claims, or null if
there is no valid token.
import { getUserInfo } from "@next-nest-auth/nextauth";
const userInfo = await getUserInfo();This reads claims from the JWT locally and does not re-verify the token's signature. Treat it as a convenience read, not an authorization check β your NestJS backend remains the source of truth for whether a token is actually valid.
Read the raw token values from cookies.
import { getAccessToken, getRefreshToken } from "@next-nest-auth/nextauth";
const accessToken = await getAccessToken();
const refreshToken = await getRefreshToken();Returns true if an access token cookie is present.
import { checkAuth } from "@next-nest-auth/nextauth";
const authenticated = await checkAuth();Deletes the access and refresh token cookies.
import { logout } from "@next-nest-auth/nextauth";
await logout();Axios-based helpers that automatically attach Authorization: Bearer <access_token> when secured is true (the default).
import { get, post } from "@next-nest-auth/nextauth";
const data = await get("/some-api-endpoint");
const postData = await post("/some-api-endpoint", { someData: "value" });- Tokens are stored as
httpOnlycookies, never exposed to client-side JavaScript. - The
securecookie flag is enabled automatically whenNODE_ENVis exactlyproductionβ make sure that's set correctly in your deployment environment, or cookies won't be markedsecurethere. - If your Next.js frontend and NestJS backend are on different origins,
configure CORS on the backend to allow credentials
(
Access-Control-Allow-Credentials: true) from your frontend's specific origin β this package sends requests withwithCredentials: true. getUserInfo()decodes but does not verify the JWT signature; don't use it as your only authorization gate for sensitive actions.
@next-nest-auth/nestauthβ the NestJS backend counterpart to this package.
Issues and pull requests are welcome at github.com/tanvir0604/nextauth.
This package is licensed under the MIT License.