Next JWT Auth
raw JSON →Next JWT Auth is a lightweight React/Next.js library for integrating custom JWT authentication services hosted separately from your Next.js app. Version 1.5.0 provides a simple provider-based pattern to manage JWT access and refresh tokens, using browser cookies for storage and automatically refreshing tokens when they expire. Unlike NextAuth.js, it does not create API routes inside your Next.js app, avoiding an extra hop between frontend and auth service, and focuses solely on JWT auth without support for social login or database adapters. The library requires Next.js ^16.2.4, React >=18, and Axios ^1.6.8 as peer dependencies. It ships with TypeScript types and is actively maintained, with frequent releases (latest v1.5.0 as of April 2025). Key differentiators: direct frontend-to-auth-service calls, automatic token refresh and logout, and minimal boilerplate.
Common errors
error Uncaught TypeError: Cannot read properties of undefined (reading 'token') ↓
error next-jwt-auth: Failed to parse token expiry. Please provide a valid date string or timestamp. ↓
error Module not found: Can't resolve 'next-jwt-auth' in '/path/to/project' ↓
error Error: Invalid hook call. Hooks can only be called inside of the body of a function component. ↓
error TypeScript error: 'AuthUser' is declared but its value is never read. ↓
Warnings
breaking Requires Next.js ^16.2.4 (previously supported ^14.1.4). Update Next.js or pin to older version. ↓
deprecated The 'login' method no longer accepts a callback URL; use the 'redirect' config option instead. ↓
deprecated The 'logout' method no longer logs out automatically on refresh token expiry; you must manually check 'isTokenExpired'. ↓
gotcha Axios peer dependency must be exactly ^1.6.8. Using a different version may cause import errors. ↓
gotcha Cookies are set with httpOnly: false by default, making them accessible to JavaScript (XSS risk). ↓
Install
npm install next-jwt-auth yarn add next-jwt-auth pnpm add next-jwt-auth Imports
- JWTAuthConfig wrong
const { JWTAuthConfig } = require('next-jwt-auth')correctimport { JWTAuthConfig } from 'next-jwt-auth' - AuthUser wrong
import AuthUser from 'next-jwt-auth'correctimport { AuthUser } from 'next-jwt-auth' - createJWTAuthProvider
import { createJWTAuthProvider } from 'next-jwt-auth' - useJWTAuth wrong
import { useAuth } from 'next-jwt-auth'correctimport { useJWTAuth } from 'next-jwt-auth'
Quickstart
// src/types/Auth.ts
import { AuthUser } from 'next-jwt-auth'
export interface LoggedInUser extends AuthUser {
email: string
firstName: string
lastName: string
phone: string
}
// src/config/Auth.ts
import { JWTAuthConfig, createJWTAuthProvider, useJWTAuth } from 'next-jwt-auth'
const authConfig: JWTAuthConfig = {
apiBaseUrl: process.env.NEXT_PUBLIC_API_BASE_URL ?? 'http://localhost:4000',
user: { property: 'user' },
accessToken: { property: 'access.token' },
refreshToken: { property: 'refresh.token' },
login: {
url: '/auth/signin',
method: 'POST',
body: { email: '', password: '' }
},
refresh: { url: '/auth/refresh', method: 'POST' },
logout: { url: '/auth/logout', method: 'POST' },
cookieOptions: { httpOnly: false, secure: true, sameSite: 'strict' }
}
export const { AuthProvider, useAuth } = createJWTAuthProvider<LoggedInUser>(authConfig)
// pages/_app.tsx
import { AuthProvider } from '../config/Auth'
function MyApp({ Component, pageProps }) {
return (
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
)
}
export default MyApp
// pages/profile.tsx
import { useAuth } from '../config/Auth'
export default function Profile() {
const { user, login, logout, isAuthenticated } = useAuth()
const handleLogin = async () => {
await login({ email: 'user@example.com', password: 'pass123' })
}
return (
<div>
{isAuthenticated ? (
<>
<p>Welcome, {user?.firstName}</p>
<button onClick={logout}>Logout</button>
</>
) : (
<button onClick={handleLogin}>Login</button>
)}
</div>
)
}