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

NestJS集成Keycloak遇wrong ISS/audience错误的排查解决

NestJS集成Keycloak时JWT验证错误(wrong audience/wrong ISS)

你遇到的错误日志如下:

WARN [Keycloak] Cannot validate access token: Error: Grant validation failed. Reason: invalid token (wrong audience)
WARN [Keycloak] Cannot validate access token: Error: Grant validation failed. Reason: invalid token (wrong ISS)

1. wrong ISS和wrong audience错误的区别

  • wrong ISS:令牌的签发者(iss字段)与服务端配置的签发地址不匹配。iss是Keycloak生成令牌时携带的地址,格式为{Keycloak服务地址}/realms/{realm名},比如你的场景下应为http://service.serveraws.io/realms/user-service。如果服务端配置的authServerUrl和该地址不一致,就会触发此错误。
  • wrong audience:令牌的受众(aud字段)未包含当前服务的客户端ID。aud代表令牌的目标接收方,Keycloak生成的令牌默认会将客户端ID加入aud列表;若服务端开启了verifyTokenAudience: true,但令牌里没有当前服务的clientId,就会触发该错误。

2. 错误原因分析

结合你的配置与代码,核心问题包括:

  • 环境变量重复定义:.env中重复设置了KEYCLOAK_AUTH_SERVER_URL,第二个值http://service.serveraws.io/覆盖了带realm的正确地址,导致服务端用错误地址验证令牌iss,触发wrong ISS错误。
  • Guard混用冲突:你同时注册了nest-keycloak-connect的AuthGuard和自定义JwtAuthGuard,控制器又使用了自定义Guard,但错误日志来自Keycloak模块,说明两个Guard同时生效,验证逻辑冲突。
  • 受众验证配置问题:开启verifyTokenAudience: true后,若Keycloak客户端未正确配置受众,或令牌生成时未包含你的clientId(user-kundali),就会触发wrong audience错误。
  • 自定义Guard缺失关键验证:你的JwtAuthGuard仅验证签名有效性,未校验iss和aud字段,无法确保令牌来源和目标的合法性。

3. 解决步骤

步骤1:修正环境变量

删除重复的KEYCLOAK_AUTH_SERVER_URL,保留带realm的正确地址:

## Authentication-related values
PEM_KEY_PATH='./src/auth/user-service.pem'
KEYCLOAK_AUTH_SERVER_URL='http://service.serveraws.io/realms/user-service'
KEYCLOAK_REALM='user-service'
KEYCLOAK_CLIENT_ID='user-kundali'
KEYCLOAK_SECRET='test'

步骤2:统一Guard使用

选择一种验证方式,避免混用:

方式一:仅使用nest-keycloak-connect的Guard

  • 控制器中替换@UseGuards(JwtAuthGuard)为@UseGuards(AuthGuard)(来自nest-keycloak-connect)
  • 删除自定义JwtAuthGuard,避免冲突
  • 调整KeycloakConnectModule配置为严格模式:
    KeycloakConnectModule.register({
      authServerUrl: process.env.KEYCLOAK_AUTH_SERVER_URL,
      realm: process.env.KEYCLOAK_REALM,
      resource: process.env.KEYCLOAK_CLIENT_ID,
      verifyTokenAudience: true,
      secret: process.env.KEYCLOAK_SECRET,
      policyEnforcement: PolicyEnforcementMode.ENFORCING, // 改为严格验证模式
      tokenValidation: TokenValidation.ONLINE,
    })
    

方式二:仅使用自定义JwtAuthGuard

  • 在KeyCloakModule中移除APP_GUARD的注册(AuthGuard和RoleGuard),避免干扰
  • 完善自定义Guard的验证逻辑,添加iss和aud校验:
    @Injectable()
    export class JwtAuthGuard extends PassportStrategy(Strategy) {
      constructor(private configService: ConfigService) {
        const authServerUrl = configService.get('KEYCLOAK_AUTH_SERVER_URL');
        const clientId = configService.get('KEYCLOAK_CLIENT_ID');
        super({
          jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
          ignoreExpiration: false,
          secretOrKey: key,
          issuer: authServerUrl, // 验证签发者
          audience: clientId, // 验证受众
        });
      }
    
      async validate(payload: any) {
        const clientId = this.configService.get('KEYCLOAK_CLIENT_ID');
        // 额外校验:确保aud包含当前客户端ID
        if (!payload.aud.includes(clientId)) {
          throw new UnauthorizedException('Invalid audience');
        }
        return { ...payload.user };
      }
    }
    

步骤3:检查Keycloak客户端配置

登录Keycloak后台,进入user-service realm的user-kundali客户端:

  • 确保Access Type设置为confidential(因你使用了client secret)
  • 在Settings中,检查Valid Redirect URIs和Web Origins包含你的NestJS服务地址(在线验证需要)
  • 在Advanced Settings中,开启Include Audience选项,确保令牌生成时将客户端ID加入aud字段

步骤4:验证令牌内容

取出请求中的Bearer Token,用JWT解码工具查看:

  • 确认iss字段与KEYCLOAK_AUTH_SERVER_URL完全一致
  • 确认aud字段包含你的KEYCLOAK_CLIENT_ID(user-kundali)
  • 若字段不匹配,回到Keycloak客户端配置调整生成逻辑

内容的提问来源于stack exchange,提问作者Shalabh Negi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 12:20:40