NextAuth v4配置:以外端JWT的expiresAt为准自动登出
NextAuth v4 配置外部JWT过期时间自动登出
问题背景
在Next.js 14中使用NextAuth v4对接外部JWT认证后端,登录成功后会话中同时存在NextAuth自动生成的expires字段,以及后端返回的expiresAt时间戳。需要让NextAuth以外端返回的expiresAt作为令牌过期判断标准,到期后自动登出用户。
解决方案
需要修改authOptions中的JWT和Session回调,同时明确session策略,具体步骤如下:
1. 明确Session策略(可选但推荐)
在authOptions中添加session配置,指定使用jwt策略:
session: { strategy: "jwt", },
2. 修改JWT回调,同步外部过期时间
在jwt回调中,将后端返回的expiresAt转换为NextAuth JWT识别的exp字段(Unix时间戳),并添加过期检查逻辑:
async jwt({ token, user }) { if (user) { // 将后端返回的expiresAt赋值给token.exp,作为JWT过期判断依据 token.exp = user.authorization.expiresAt; // 保留用户其他信息 return { ...token, ...user }; } // 每次刷新JWT时,检查是否已过期 const now = Math.floor(Date.now() / 1000); if (token.exp && now > token.exp) { // 令牌已过期,返回null触发登出 return null; } return token; },
3. 修改Session回调,同步会话过期时间
在session回调中,将session.expires设置为expiresAt对应的ISO时间字符串,确保前端useSession能正确识别会话过期状态:
async session({ token, session }) { session.user = token.user; session.authorization = token.authorization; // 将expiresAt转换为ISO时间字符串,覆盖NextAuth自动生成的expires session.expires = new Date(token.authorization.expiresAt * 1000).toISOString(); return session; },
修改后的完整authOptions.ts
import NextAuth, { NextAuthOptions } from "next-auth" import CredentialsProvider from "next-auth/providers/credentials" import { JWT } from "next-auth/jwt" const API_ENDPOINT = process.env.NEXT_PUBLIC_API_URL || "http://myapp.test/api" class CustomError extends Error { status: number; constructor(message: string, status: number) { super(message); this.name = this.constructor.name; this.status = status; Error.captureStackTrace(this, this.constructor); } } const authOptions: NextAuthOptions = { providers: [ CredentialsProvider({ type: "credentials", name: "Email and Password", credentials: { email: { label: "Email", type: "email", placeholder: "Your Email" }, password: { label: "Password", type: "password" }, }, async authorize(credentials) { if (!credentials?.email || !credentials?.password) return null const { email, password } = credentials const res = await fetch(`${API_ENDPOINT}/auth/login`, { method: "POST", body: JSON.stringify({ email, password, }), headers: { "Content-Type": "application/json", Accept: "application/json", }, }) const response = await res.json() if (res.ok) { return response.data } else { throw new CustomError(response.message, response.status); } }, }), ], // 明确使用jwt会话策略 session: { strategy: "jwt", }, callbacks: { async jwt({ token, user }) { if (user) { // 用后端返回的expiresAt设置JWT过期时间 token.exp = user.authorization.expiresAt; return { ...token, ...user }; } // 检查令牌是否已过期 const now = Math.floor(Date.now() / 1000); if (token.exp && now > token.exp) { return null; } return token; }, async session({ token, session }) { session.user = token.user; session.authorization = token.authorization; // 同步会话过期时间为后端expiresAt对应的ISO字符串 session.expires = new Date(token.authorization.expiresAt * 1000).toISOString(); return session; }, }, pages: { signIn: "/auth/login", }, } export {authOptions}
原理说明
- NextAuth的JWT过期判断依赖
token.exp字段(Unix时间戳),通过将后端的expiresAt赋值给该字段,让NextAuth以外端令牌的过期时间为准。 - 每次JWT刷新时,会自动检查
token.exp,如果当前时间已超过该值,返回null会触发自动登出。 - 修改
session.expires是为了让前端的useSession钩子能正确显示会话的过期状态,确保前端逻辑和后端令牌过期时间一致。
内容的提问来源于stack exchange,提问作者psudo
相关产品推荐
相关产品推荐

