NestJS自定义Keycloak服务:携带Token访问端点遭拒绝求助
Keycloak返回access_denied:携带Token无法访问端点问题
背景
- 初期NestJS后端项目,未搭建e2e测试
- 因OpenID Connect Node.js适配器弃用,自行实现Keycloak服务
- Keycloak与MySQL均部署在Docker容器中
- Keycloak作为中间件负责路由保护与用户登录,已配置专属realm,包含客户端和用户(暂未设置自定义角色/分组)
- 使用Insomnia进行端点测试
问题现象
携带Token访问端点时失败,Keycloak日志返回access_denied错误:
keycloak-1 | 2024-03-13 09:37:16,675 WARN [org.keycloak.events] (executor-thread-1) type="USER_INFO_REQUEST_ERROR", realmId="55542514-fc71-4e4e-be3e-42af869de2a7", clientId="null", userId="null", ipAddress="172.18.0.1", error="access_denied", auth_method="validate_access_token"
通过curl测试userinfo端点同样返回access_denied:
curl http://localhost:8080/realms/myapp/protocol/openid-connect/userinfo -H "Authorization: Bearer <mytoken>"
(附相关截图:Insomnia获取Token及访问路由操作流程、Keycloak配置界面、Insomnia报错界面)
排查与解决步骤
1. 验证Token有效性
- 使用Keycloak的Token Introspection端点校验Token状态:
查看返回结果中的curl -X POST http://localhost:8080/realms/myapp/protocol/openid-connect/token/introspect \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "client_id=<你的客户端ID>" \ -d "client_secret=<你的客户端密钥>" \ -d "token=<mytoken>"active字段,若为false则说明Token已过期或无效。 - 用JWT解码工具解析Token,检查:
aud(受众)是否包含你的客户端IDiss(签发者)是否与Keycloak的realm地址完全一致exp(过期时间)是否未超出当前时间
2. 检查Keycloak客户端配置
- 确认客户端Access Type设置:
- 若为
confidential,获取Token时必须提供客户端密钥;若为public,则无需密钥,但需确保Valid Redirect URIs、Web Origins配置正确(测试阶段可暂时设为*)。
- 若为
- 检查客户端权限:在
Client Scopes标签下,确认profile、email等默认scope已添加,且Full Scope Allowed选项已勾选。
3. 核对Token获取流程
- 确认获取Token时的grant类型正确:
- 若使用密码模式,请求参数必须包含
username、password、client_id(confidential类型需额外加client_secret)、grant_type=password、scope=openid(必须包含openid才能获取可用于userinfo接口的Token)。
- 若使用密码模式,请求参数必须包含
- 确保获取Token时使用的realm和客户端信息,与访问端点时的完全一致。
4. 检查NestJS自定义Keycloak服务
- 确认自行实现的中间件是否完整验证了Token的签名、受众、签发者,未遗漏关键验证步骤。
- 排查中间件是否在传递Authorization头过程中修改或丢失了Token。
内容的提问来源于stack exchange,提问作者Mowso
相关产品推荐
相关产品推荐

