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

使用Apollo Client+NextAuth从Hasura取数时JWT验证失败求助

解决Apollo Client携带NextAuth Token访问Hasura的JWT验证错误

错误根源分析

你遇到的Invalid number of parts: Expected 3 parts; got 5错误,本质是传给Hasura的不是标准三段式JWT。NextAuth默认的Session Token是自身加密格式(多段结构),不符合Hasura对JWT的解析要求,导致验证失败。

解决方案步骤

1. 配置NextAuth生成Hasura兼容的JWT

在NextAuth的配置文件([...nextauth].ts)中,通过jwt和session回调生成并传递符合Hasura要求的JWT:

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import jwt from "jsonwebtoken";

export default NextAuth({
  providers: [
    CredentialsProvider({
      async authorize(credentials) {
        // 替换为你的用户验证逻辑(比如数据库校验)
        return { id: "1", email: "user@example.com" };
      },
    }),
    // 若使用OAuth提供商(如Google/Auth0),需在这里配置对应Provider
  ],
  callbacks: {
    async jwt({ token, user }) {
      // 用户首次登录时,生成Hasura专用JWT
      if (user) {
        const hasuraJwt = jwt.sign(
          {
            sub: user.id,
            email: user.email,
            "https://hasura.io/jwt/claims": {
              "x-hasura-allowed-roles": ["user"],
              "x-hasura-default-role": "user",
              "x-hasura-user-id": user.id,
            },
          },
          process.env.HASURA_JWT_SECRET!, // 需与Hasura配置的密钥一致
          { expiresIn: "1d", algorithm: "HS256" } // 算法需匹配Hasura的JWT设置
        );
        token.hasuraToken = hasuraJwt;
      }
      return token;
    },
    async session({ session, token }) {
      // 将Hasura JWT注入Session,供前端调用
      session.hasuraToken = token.hasuraToken;
      return session;
    },
  },
});

2. 配置Apollo Client正确携带Hasura JWT

修改Apollo Client的请求拦截逻辑,从NextAuth Session中获取专用的Hasura Token并添加到请求头:

import { ApolloClient, InMemoryCache, createHttpLink } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import { getSession } from "next-auth/react";

const httpLink = createHttpLink({
  uri: process.env.NEXT_PUBLIC_HASURA_GRAPHQL_ENDPOINT,
});

const authLink = setContext(async (_, { headers }) => {
  const session = await getSession();
  // 注意:这里取的是session.hasuraToken,不是NextAuth默认的session.token
  const token = session?.hasuraToken;
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : "",
    },
  };
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
});

export default client;

3. 验证Hasura的JWT配置

确保Hasura的环境变量HASURA_GRAPHQL_JWT_SECRET格式正确,且与NextAuth中使用的密钥、算法一致:

  • 若使用HS256算法,配置示例:{"type":"HS256","key":"your-shared-secret-key"}
  • 若使用RS256,需配置公钥字段

关键检查点

  • 登录后打印前端Session,确认hasuraToken是三段式字符串(用.分隔)
  • 用jwt.io解析hasuraToken,检查https://hasura.io/jwt/claims字段是否包含正确的角色配置
  • 确认Hasura控制台中,对应角色拥有目标数据的访问权限

内容的提问来源于stack exchange,提问作者Yuki Sakiyama

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 01:45:46