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

next-auth集成KeycloakProvider:JWT字段缺失且签名无效

问题原因与解决方案

核心差异原因

  • 浏览器存储的JWT是NextAuth自有Token:NextAuth默认会生成独立的Session Token存在浏览器中,并非直接转发Keycloak返回的原始ID Token。这个Token用NextAuth自身的密钥签名,而非Keycloak的密钥,所以在jwt.io用Keycloak公钥验证时会显示“Invalid Signature”,且长度更短(仅包含NextAuth默认保留的基础字段)。
  • useSession返回字段不全:KeycloakProvider默认只从用户信息中提取name和email,sub、roles等Keycloak特有字段不会自动被纳入,需要手动配置回调逻辑来获取。

具体解决步骤

1. 自定义KeycloakProvider的profile回调,提取目标字段

修改NextAuth配置,添加profile函数,从Keycloak返回的用户数据中抓取sub、roles等需要的字段:

import NextAuth from "next-auth";
import KeycloakProvider from "next-auth/providers/keycloak";

export const authOptions = {
  providers: [
    KeycloakProvider({
      clientId: process.env.CLIENT_ID,
      clientSecret: process.env.CLIENT_SECRET,
      issuer: process.env.ISSUER,
      // 自定义profile回调,提取Keycloak返回的字段
      profile(profile) {
        // Keycloak的角色通常存储在realm_access.roles下
        const roles = profile.realm_access?.roles || [];
        return {
          id: profile.sub, // 对应sub字段
          name: profile.name,
          email: profile.email,
          roles: roles,
          // 可按需添加其他Keycloak返回的字段
        };
      },
    })
  ],
  // 配置jwt与session回调,将自定义字段同步到前端可用的session中
  callbacks: {
    async jwt({ token, user }) {
      // 用户首次登录时,将profile提取的字段存入JWT
      if (user) {
        token.id = user.id;
        token.roles = user.roles;
      }
      return token;
    },
    async session({ session, token }) {
      // 将JWT中的字段同步到session,让useSession可以获取
      session.user.id = token.id;
      session.user.roles = token.roles;
      return session;
    },
  },
  // 可选:配置NEXTAUTH_SECRET固定签名密钥,避免开发环境重启后密钥变化导致Token失效
  secret: process.env.NEXTAUTH_SECRET,
}

export default NextAuth(authOptions);

2. 验证效果

重启应用并重新登录后,调用useSession()就能获取到包含id(对应sub)、roles等字段的完整用户信息。

如果需要直接获取Keycloak的原始ID Token,可以在jwt回调中额外保存:

async jwt({ token, user, account }) {
  if (user && account) {
    token.id = user.id;
    token.roles = user.roles;
    token.keycloakIdToken = account.id_token; // 保存Keycloak原始ID Token
  }
  return token;
}

这个原始Token在jwt.io验证时就能显示完整数据且签名有效。

内容的提问来源于stack exchange,提问作者Alexander Schoch

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 05:55:16