如何解码NextAuth的Cookie中JWT令牌,提取access_token用于RTK Query
解决方案
1. 识别NextAuth的JWT Cookie
NextAuth 默认将JWT存储在名为 next-auth.session-token(开发环境)或 __Secure-next-auth.session-token(生产HTTPS环境)的HttpOnly Cookie中。注意:HttpOnly Cookie无法在客户端JavaScript中直接读取——这是浏览器的安全限制,目的是防止XSS攻击窃取token。
如果业务允许,推荐在服务端处理token;若必须在客户端处理,需调整NextAuth配置,将JWT同时存入非HttpOnly Cookie(但会降低安全性,需谨慎)。
2. 服务端读取并解码JWT(推荐方案)
在服务端(Next.js API路由、Server Components、RTK Query服务端逻辑)可直接读取Cookie并解码:
步骤1:安装JWT处理库
使用NextAuth官方推荐的jose库替代旧版jsonwebtoken:
npm install jose
步骤2:服务端读取Cookie并解码
import { jwtVerify } from "jose"; import { cookies } from "next/headers"; async function getAccessTokenFromCookie() { const cookieStore = cookies(); const sessionToken = cookieStore.get("next-auth.session-token")?.value; if (!sessionToken) return null; // 使用NEXTAUTH_SECRET验证JWT签名 const secret = new TextEncoder().encode(process.env.NEXTAUTH_SECRET); try { const { payload } = await jwtVerify(sessionToken, secret); return payload.access_token; } catch (error) { // 签名验证失败或token过期,返回null return null; } }
步骤3:在RTK Query中集成
自定义RTK Query的baseQuery,自动为服务端请求添加token:
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { getAccessTokenFromCookie } from "./utils"; const baseQuery = fetchBaseQuery({ baseUrl: "https://your-external-api.com", async prepareHeaders(headers) { // 仅在服务端环境读取Cookie if (typeof window === "undefined") { const accessToken = await getAccessTokenFromCookie(); if (accessToken) { headers.set("Authorization", `Bearer ${accessToken}`); } } return headers; }, }); export const api = createApi({ baseQuery, endpoints: (builder) => ({ getSomeData: builder.query({ query: () => "/data", }), }), });
3. 客户端读取方案(不推荐,存在安全风险)
若必须在客户端处理,需修改NextAuth配置,将access_token存入非HttpOnly Cookie:
修改NextAuth配置
在jwt回调中添加自定义Cookie逻辑:
import { serialize } from "cookie"; import NextAuth from "next-auth/next"; import CredentialsProvider from "next-auth/providers/credentials"; export default NextAuth({ providers: [ CredentialsProvider({ type: "credentials", credentials: {}, authorize: async (user) => { return user; }, }), ], pages: { signIn: "/login", }, callbacks: { jwt: async ({ token, user, res }) => { if (user) { token.access_token = user.token; token.id = user.id; } // 设置非HttpOnly Cookie,允许客户端读取 res.setHeader( "Set-Cookie", serialize("custom-access-token", token.access_token, { path: "/", maxAge: 3600, httpOnly: false, secure: process.env.NODE_ENV === "production", sameSite: "lax", }) ); return token; }, session: async ({ session, token }) => { if (token) { session.id = token.id; } return session; }, }, session: { strategy: "jwt", }, });
客户端读取Cookie并在RTK Query中使用
const baseQuery = fetchBaseQuery({ baseUrl: "https://your-external-api.com", prepareHeaders(headers) { // 从客户端Cookie中提取token const cookieEntry = document.cookie.split("; ").find(row => row.startsWith("custom-access-token=")); const accessToken = cookieEntry ? cookieEntry.split("=")[1] : null; if (accessToken) { headers.set("Authorization", `Bearer ${accessToken}`); } return headers; }, });
关键注意事项
- HttpOnly Cookie是安全最佳实践:客户端可读取的Cookie易被XSS攻击窃取,非必要不使用客户端方案。
- 必须验证JWT签名:无论服务端还是客户端,解码时都要验证签名,防止伪造token。
- 处理token过期:需添加逻辑检测token过期,及时跳转至登录页重新认证。
内容的提问来源于stack exchange,提问作者Morri
相关产品推荐
相关产品推荐

