Next.js API路由及服务器组件中AccessToken无法访问问题
问题:NextAuth + Azure AD 场景下的 Token 访问问题
我用NextAuth结合Azure AD做登录提供商,登录功能正常。目前遇到两个核心问题:
- 在NextAuth的callbacks里能拿到
access_token,middleware.ts里用getToken也能正常获取,但内部API路由里调用getToken始终返回null,req.cookies.getAll()也拿不到任何数据; - 想在服务器组件里访问
access_token,但服务器组件没有request对象,不知道怎么操作。
已尝试的解决方案
auth.js 配置
callbacks: { async jwt({ token, account }) { if (account) { token.accessToken = account.access_token } return token }, async session({ session, token }) { session.token = token.accessToken ?? "No token found"; return session; // 期望在服务器组件中可用 }, async redirect() { return "/"; } }
page.tsx(服务器组件)
export default async function Page() { const session = await getServerSession(authOptions) const token = session?.token; return <pre>{session?.token}</pre> }
next-auth-d.ts(类型声明)
import NextAuth, { DefaultSession } from "next-auth"; import type { Session, Account,JWT } from "next-auth"; declare module "next-auth" { interface JWT { accessToken?: accessToken; user: { token?: accessToken; } & DefaultSession["user"]; } interface Session { token?: accessToken; user: { token?: accessToken; } & DefaultSession["user"]; } interface Account { access_token: accessToken; user: { token?: accessToken; } & DefaultSession["user"]; } }
补充说明
官方文档标注此为预期行为,但我仍不清楚如何在服务器组件中获取token。
我的当前配置代码
AuthConfig(authOptions)
import { NextAuthOptions } from "next-auth"; import AzureADProvider from "next-auth/providers/azure-ad"; import { CLIENT_ID, CLIENT_SECRET, TENANT_ID } from "./utils/envPublic"; const authOptions: NextAuthOptions = { providers: [ AzureADProvider({ clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, tenantId: TENANT_ID, authorization: { params: { scope: "openid profile email api://myapi/my.scope", } } }) ], secret: process.env.NEXTAUTH_SECRET, session: { strategy: "jwt" }, jwt: { secret: process.env.NEXTAUTH_SECRET }, callbacks: { async jwt({ token, account, user }) { token.accessToken = account?.access_token; return { ...token, ...user, ...account }; }, async session({ session, token, user }) { session.token = token.accessToken; session.user.token = token.accessToken; return session; }, async redirect() { return "/" } }, }; export default authOptions;
API 路由(app/api/xxx/route.ts)
import { getToken } from 'next-auth/jwt'; import { NextRequest, NextResponse } from 'next/server'; export const GET = async (req: NextRequest) => { const token = await getToken({ req: req, secret: process.env.SECRET }) console.log("token from API:") console.log(token); // 始终返回null const cookies = req.cookies.getAll(); console.log("cookies from API:") console.log(cookies.length); // 始终返回0 const response = await fetch('https://jsonplaceholder.typicode.com/todos/1') const json = await response.json(); return NextResponse.json(json); }
middleware.ts
import { getToken } from 'next-auth/jwt' import type { NextRequest, NextResponse } from 'next/server' export async function middleware(request: NextRequest) { const token = await getToken({ req: request, secret: process.env.SECRET }); console.log("token:"); console.log(token); // 能正常打印正确的token }
解决方案
问题1:API路由无法获取Token的修复
你在API路由里调用getToken时误用了process.env.SECRET,NextAuth的JWT验证必须使用和authOptions中一致的NEXTAUTH_SECRET。另外,客户端调用API时需确保请求携带Cookie凭证。
修改后的API路由代码:
import { getToken } from 'next-auth/jwt'; import { NextRequest, NextResponse } from 'next/server'; import authOptions from '@/path/to/your/authOptions'; // 导入你的authOptions export const GET = async (req: NextRequest) => { // 使用authOptions中的统一secret,避免环境变量不一致 const token = await getToken({ req, secret: authOptions.secret }) console.log("token from API:", token); const response = await fetch('https://jsonplaceholder.typicode.com/todos/1') const json = await response.json(); return NextResponse.json(json); }
客户端调用API时需添加凭证配置:
// 客户端组件内调用示例 const fetchData = async () => { const res = await fetch('/api/xxx', { credentials: 'include' }); const data = await res.json(); }
问题2:服务器组件中访问access_token的方法
你的思路是对的,通过getServerSession获取session再提取token,但需修正类型声明并确保getServerSession正确传入authOptions。
修正类型声明(next-auth-d.ts)
补充未定义的AccessToken类型,精简冗余声明:
import NextAuth, { DefaultSession } from "next-auth"; import type { Session, Account,JWT } from "next-auth"; type AccessToken = string; declare module "next-auth" { interface JWT { accessToken?: AccessToken; } interface Session { token?: AccessToken; user: { token?: AccessToken; } & DefaultSession["user"]; } interface Account { access_token: AccessToken; } }
服务器组件正确获取Token
确保导入正确的getServerSession并传入authOptions:
import { getServerSession } from "next-auth/next"; import authOptions from "@/path/to/your/authOptions"; export default async function Page() { const session = await getServerSession(authOptions); const accessToken = session?.token; return <div>{accessToken ? `Token: ${accessToken}` : "未登录"}</div>; }
额外注意事项
- 确保
NEXTAUTH_SECRET环境变量在所有环境中配置一致; - App Router下
getServerSession需从next-auth/next导入,而非next-auth/react; - 受保护的API路由建议用Middleware提前拦截未登录请求,避免无效调用。
内容的提问来源于stack exchange,提问作者joeboy
相关产品推荐
相关产品推荐

