如何在NextJS项目中通过NextAuth获取JWT令牌用于后续API调用?
解决NextAuth.js(Credentials Provider)获取JWT令牌的问题
核心问题分析
你遇到的问题根源有两个:
- Credentials Provider的token传递逻辑和OAuth不同:OAuth的
account对象会自带accessToken,但Credentials模式下,需要你在authorize函数中手动把私有API返回的JWT挂载到返回的user对象上,才能在jwt回调中拿到。 - 未处理
sessionData的状态问题:useSession返回的sessionData在loading或unauthenticated状态下是undefined,直接解构会报错。
分步解决方案
1. 修正Credentials Provider的authorize函数
在api/auth/[...nextauth].ts中,确保登录成功后把私有API返回的JWT包含在返回的用户对象里:
import NextAuth from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; export default NextAuth({ providers: [ CredentialsProvider({ name: "Credentials", credentials: { // 根据你的登录字段调整,比如username/password username: { label: "Username", type: "text" }, password: { label: "Password", type: "password" }, }, async authorize(credentials) { // 调用私有API完成登录 const res = await fetch("https://your-private-api/login-endpoint", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(credentials), }); const loginResult = await res.json(); // 登录成功时,返回包含accessToken的用户对象 if (res.ok && loginResult.accessToken) { return { id: loginResult.userId, // 可选,根据你的API返回调整 name: loginResult.username, // 可选 accessToken: loginResult.accessToken, // 关键:把私有API的JWT带回去 }; } // 登录失败返回null return null; }, }), ], // 必须设置session策略为jwt,否则无法通过回调传递token session: { strategy: "jwt" }, // 修正jwt和session回调逻辑 callbacks: { async jwt({ token, user }) { // 登录时,user是authorize返回的对象,包含accessToken if (user) { token.accessToken = user.accessToken; } return token; }, async session({ session, token }) { // 将token中的accessToken注入到session中,供客户端使用 session.accessToken = token.accessToken; return session; }, }, });
2. 客户端安全获取accessToken
使用useSession时,先判断状态,避免sessionData为undefined的情况:
import { useSession } from "next-auth/react"; function YourComponent() { const { data: sessionData, status } = useSession(); // 处理加载状态 if (status === "loading") { return <div>加载中...</div>; } // 未登录状态 if (status === "unauthenticated") { return <div>请先登录</div>; } // 登录后安全获取accessToken const accessToken = sessionData?.accessToken; // 调用私有API时携带token const callPrivateAPI = async () => { const res = await fetch("https://your-private-api/protected-endpoint", { headers: { Authorization: `Bearer ${accessToken}`, }, }); const data = await res.json(); // 处理返回数据 }; return ( <div> <button onClick={callPrivateAPI}>调用私有API</button> </div> ); } export default YourComponent;
3. 优化TypeScript类型(可选但推荐)
避免使用any,定义扩展类型确保类型安全:
// 在项目根目录创建next-auth.d.ts文件 import type { DefaultSession, DefaultJWT } from "next-auth"; declare module "next-auth" { interface Session extends DefaultSession { accessToken?: string; } interface User { accessToken?: string; } } declare module "next-auth/jwt" { interface JWT extends DefaultJWT { accessToken?: string; } }
关键注意点
- 必须设置
session: { strategy: "jwt" },否则jwt和session回调不会生效。 - 不要依赖
account对象传递token,Credentials模式下account的结构和OAuth不同,优先从authorize返回的user对象中获取。 - 始终通过
status判断登录状态,再访问sessionData,避免解构undefined的错误。
内容的提问来源于stack exchange,提问作者japnoo
相关产品推荐
相关产品推荐

