Keycloak令牌交换报错:客户端不在令牌受众范围内
看起来你遇到的是Keycloak令牌交换里很常见的受众不匹配问题,我之前处理过类似的场景,给你梳理下排查和解决的具体步骤:
首先先明确下你的场景:你已经在Keycloak实例开启了token_exchange和admin_fine_grained_authz功能,尝试用client1的访问令牌,通过令牌交换API获取client2的访问令牌,但遇到了“客户端不在令牌受众范围内”的报错。
可能的原因及解决步骤:
原因1:client1的原始令牌受众不包含client2
你可以先把client1的访问令牌拿到jwt.io上解析,查看aud字段是否包含client2的client_id。如果没有的话,需要进入Keycloak控制台,找到client1的配置:- 切换到「Advanced」标签页
- 在「Allowed Audience」里添加
client2的client_id - 保存配置后,重新获取client1的令牌再尝试交换
原因2:client2未配置允许接受来自client1的令牌交换
就算client1的令牌受众没问题,client2也需要授权接收来自client1的交换请求:- 进入client2的配置页面,切换到「Advanced」标签
- 确保「Enabled OAuth 2.0 Grant Types」里勾选了
urn:ietf:params:oauth:grant-type:token-exchange - 切换到「Settings」标签,在「Trusted Clients」里添加client1的client_id,把client1设为信任客户端
- 如果你开启了细粒度权限控制(admin_fine_grained_authz),还需要在client2的「Authorization」标签里添加一个策略:允许client1作为subject发起令牌交换请求
原因3:请求参数存在遗漏或错误
你的curl命令里requested_token_ty应该是没写完,完整的参数应该是requested_token_type=urn:ietf:params:oauth:token-type:access_token,修正后的完整请求示例如下:curl --location 'http://<URL>/realms/Genting/protocol/openid-connect/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id=client2' \ --data-urlencode 'client_secret=<client2 secret>' \ --data-urlencode 'subject_token=<client1 access token>' \ --data-urlencode 'audience=client2' \ --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \ --data-urlencode 'requested_token_type=urn:ietf:params:oauth:token-type:access_token'另外要确认
subject_token是client1的有效访问令牌(未过期、属于同一个Genting realm),client_id和audience的拼写和Keycloak里的配置完全一致。
额外排查建议:
如果还是不行,可以去Keycloak的日志里找更详细的报错信息,日志会明确指出是哪个环节的受众校验失败;另外要确保client1和client2都在同一个Genting realm下,跨realm的令牌交换需要额外的跨域配置。
备注:内容来源于stack exchange,提问作者Vinod Louis

