You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解码NextAuth的Cookie中JWT令牌,提取access_token用于RTK Query

解决方案

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 03:36:31