适用版本: 7.x-8.9
1. 错误异常的基本描述 #
Failed to get user information from the UserInfo endpoint. Code=[...]; Description=[...] 表示 Elasticsearch 确实收到了 UserInfo Endpoint 的 HTTP 响应,但响应不是成功状态(非 2xx),并且还能提取出明确的错误码和描述。这类报错比通用的 UserInfo 失败更具体,因为它通常意味着身份提供方已经返回了可解释的认证或授权错误。
源码表明 Elasticsearch 会优先从 WWW-Authenticate 响应头解析 Bearer Token 错误;如果没有这个头,就回退到 HTTP 状态码和响应描述。
常见现象 #
- OIDC 登录失败,而且日志中会出现
invalid_token、insufficient_scope、invalid_request等错误码。 - 身份提供方访问正常(网络连通性没问题),但 Elasticsearch 仍然拒绝完成登录。
- 相同 Realm 下,不同用户或不同 token 的行为可能不一致:有些用户能登录,有些不能。
- 在 Kibana 或其他依赖 OIDC 的应用中,用户看到登录失败页面,但没有明确的错误提示。
- 从 Elasticsearch 日志可以看到完整的错误码和描述,例如:
Code=[401]; Description=[invalid_token]。
典型报错与异常栈 #
常见日志形态通常类似下面这样:
ElasticsearchSecurityException: Failed to get user information from the UserInfo endpoint. Code=[401]; Description=[invalid_token]
at org.elasticsearch.xpack.security.authc.oidc.OpenIdConnectRealm...
或者 scope 不足:
ElasticsearchSecurityException: Failed to get user information from the UserInfo endpoint. Code=[403]; Description=[insufficient_scope]
at org.elasticsearch.xpack.security.authc.oidc.OpenIdConnectRealm...
或者从 HTTP 状态码提取:
ElasticsearchSecurityException: Failed to get user information from the UserInfo endpoint. Code=[400]; Description=[Bad Request]
at org.elasticsearch.xpack.security.authc.oidc.OpenIdConnectRealm...
2. 为什么会发生这个错误 #
Failed to get user information from the UserInfo endpoint. Code=[...] 的根因是"OIDC UserInfo Endpoint 返回了错误响应"。Elasticsearch 向 IdP 的 UserInfo Endpoint 发起请求后,IdP 返回了非 2xx 的 HTTP 状态码,并在 WWW-Authenticate 头或响应体中提供了错误详情。
常见原因通常包括:
- access token 已过期:
access_token的有效期已过,IdP 返回invalid_token错误。 - access token 无效:
access_token格式错误、被篡改或不是由当前 IdP 签发的。 - token 受众(audience)不匹配:token 的
aud声明与 IdP 预期的受众不一致。 - scope 不足:当前 token 没有访问 UserInfo Endpoint 所需的
openid或profilescope。 - 身份提供方要求额外认证条件:如需要 MFA(多因素认证)、step-up authentication 等,但当前请求不满足。
- 反向代理或网关问题:反向代理、SSO 网关或 WAF 重写了认证头,导致 Elasticsearch 拿到的是不完整或错误的认证信息。
- 时钟偏移(clock skew):Elasticsearch 节点与 IdP 之间的系统时钟不一致,导致 token 的
iat(签发时间)或exp(过期时间)验证失败。 - token 缓存问题:客户端或中间件缓存了旧的、已失效的 token,并继续使用它访问 UserInfo Endpoint。
3. 如何排查和解决这个异常和解决这个异常 #
建议按"先解读错误码、再检查 token、后排查网络"的顺序处理:
解读错误码和描述:直接查看日志里的
Code和Description,先按身份提供方错误语义定位。# 查看 Elasticsearch 安全日志中的错误详情 grep -r "Failed to get user information from the UserInfo endpoint" /var/log/elasticsearch/ grep -r "Code=" /var/log/elasticsearch/ | tail -20检查 token 有效性:确认 token 的 scope、audience、过期时间和签发流程是否符合 UserInfo 要求。
# 解码 JWT token(如果使用的是 JWT 格式的 access_token) echo "your_access_token" | cut -d'.' -f2 | base64 -d | jq . # 检查 token 的 exp(过期时间)、aud(受众)、scope 等声明对照身份提供方日志:确认该请求为何返回了当前 HTTP 状态和认证头。
# 如果是 Keycloak,查看 Keycloak 日志 docker logs keycloak_container | grep -i "userinfo" # 如果是 Okta/Auth0,查看其管理控制台的事件日志检查中间代理:检查反向代理、SSO 网关或 WAF 是否透传了
Authorization与WWW-Authenticate相关头部。# 检查代理配置(以 Nginx 为例) grep -r "proxy_set_header" /etc/nginx/ # 确认 Authorization 头没有被过滤检查时钟同步:如果错误只在某些客户端或节点上出现,检查是否存在 clock skew。
# 检查节点时间 date # 与 NTP 服务器同步时间 ntpdate -q pool.ntp.org检查 token 缓存:如果错误只在某些客户端上出现,检查是否存在缓存旧 token 或错误回调地址。
排查时需要注意的问题 #
- 这个异常已经把线索收敛到了"身份提供方明确告诉你为什么失败"。排查时最有价值的信息就是
Code和Description,它们通常比通用堆栈更接近根因。 - 不同的错误码指向不同的问题:
invalid_token通常是 token 过期或无效,insufficient_scope是 scope 配置问题,invalid_request可能是请求格式问题。 - 需要同时检查 Elasticsearch 配置和 IdP 配置,问题可能出在任何一端。
4. 如何解决这个错误 #
常用修复思路 #
修复 OIDC 客户端配置:确保 scope、audience 和回调流程正确。
# elasticsearch.yml 中的 OIDC Realm 配置 xpack.security.authc.realms.oidc.oidc1: order: 2 rp.client_id: "your-client-id" rp.client_secret: "your-client-secret" rp.response_type: "code" rp.redirect_uri: "https://your-elasticsearch-domain:9243/api/security/v1/oidc" op.issuer: "https://your-idp-domain.com" op.authorization_endpoint: "https://your-idp-domain.com/oauth2/authorize" op.token_endpoint: "https://your-idp-domain.com/oauth2/token" op.userinfo_endpoint: "https://your-idp-domain.com/oauth2/userInfo" op.jwkset_path: "https://your-idp-domain.com/oauth2/jwks" # 确保请求的 scope 包含 openid 和 profile rp.requested_scopes: ["openid", "profile", "email"]缩短 token 缓存时间:避免使用已失效凭证访问 UserInfo Endpoint。
# 在 OIDC Realm 配置中调整缓存时间(如果支持) # 或者在客户端(如 Kibana)配置更短的 token 刷新间隔修复反向代理配置:确保代理、SSO 网关或 WAF 不会篡改或裁剪认证头。
# Nginx 代理配置示例(确保透传 Authorization 头) location / { proxy_pass http://elasticsearch:9200; proxy_set_header Authorization $http_authorization; proxy_pass_header Authorization; }解决时钟偏移问题:同步 Elasticsearch 节点和 IdP 的系统时钟。
# 安装并配置 NTP yum install ntp systemctl enable ntpd systemctl start ntpd # 手动同步 ntpdate pool.ntp.org联系 IdP 管理员:如果错误码指向 IdP 侧的问题(如用户状态异常、IdP 配置错误),需要联系 IdP 管理员解决。
后续注意事项与推荐建议 #
- 为 OIDC 认证配置合理的 token 刷新策略,避免 access_token 过期导致的认证失败。
- 建立对 IdP 服务可用性和错误响应的监控,在 IdP 返回异常错误时及时预警。
- 定期检查 OIDC 客户端配置,确保 scope、audience 等参数与 IdP 的要求保持一致。
- 在应用层(如 Kibana)实现适当的错误处理和用户提示,帮助用户理解认证失败的原因。
借助 INFINI 产品提升排障效率 #
- INFINI Console 适合查看集群的安全配置、认证日志和用户访问趋势,帮助快速判断
Code=[...]错误的分布和模式,并提供可视化的配置管理和审计功能,追踪 OIDC 配置变更历史。 - INFINI Gateway 适合部署在 Elasticsearch 前面做请求观测和流量治理,可以记录所有认证相关请求的详细日志,包括 OIDC 流程中每个步骤的请求和响应,帮助定位是 Elasticsearch 配置问题还是 IdP 返回问题,同时提供请求重试和熔断机制来提升认证稳定性。
- 建议将 OIDC 认证相关指标(成功率、错误码分布、token 过期率)统一接入监控面板,结合 INFINI Console 的告警功能,在认证质量下降时及时通知。
5. 小结 #
Failed to get user information from the UserInfo endpoint. Code=[...]; Description=[...] 已经把线索收敛到了"身份提供方明确告诉你为什么失败"。排查时最有价值的信息就是 Code 和 Description,它们通常比通用堆栈更接近根因。大多数情况下,这个问题可以通过解读错误码、检查 token 有效性和修复 OIDC 配置来解决。
只要把 OIDC 配置校验、token 管理和 IdP 监控固定下来,大多数认证错误码类异常都可以被快速定位和恢复,也更容易通过 INFINI Console 和 INFINI Gateway 实现持续防护。
相关错误 #
- failed-to-get-user-information-from-the-userinfo-endpoint-how-to-solve-this-elasticsearch-exception
- failed-to-get-claims-from-the-userinfo-endpoint-how-to-solve-this-elasticsearch-exception
- failed-to-get-claims-from-the-userinfo-endpoint-request-was-cancelled-how-to-solve-this-elasticsearch-exception
- failed-to-verify-access-token-how-to-solve-this-elasticsearch-exception
- failed-to-verify-access-token-id-token-doesnt-contain-at-hash-claim-how-to-solve-this-elasticsearch-exception
参考文档 #
- Elasticsearch OIDC Realm 官方文档
- OpenID Connect UserInfo Endpoint 规范
- OAuth 2.0 Bearer Token Usage 规范
- INFINI Console 文档
- INFINI Gateway 文档
附:日志上下文 #
下面保留当前页面中的源码或日志片段,便于继续结合异常调用栈定位问题:
} else {
final Header wwwAuthenticateHeader = httpResponse.getFirstHeader("WWW-Authenticate");
if (Strings.hasText(wwwAuthenticateHeader.getValue())) {
BearerTokenError error = BearerTokenError.parse(wwwAuthenticateHeader.getValue());
claimsListener.onFailure(
new ElasticsearchSecurityException("Failed to get user information from the UserInfo endpoint. Code=[{}]; " +
"Description=[{}]"; error.getCode(); error.getDescription()));
} else {
claimsListener.onFailure(
new ElasticsearchSecurityException("Failed to get user information from the UserInfo endpoint. Code=[{}]; " +
"Description=[{}]"; httpResponse.getStatusLine().getStatusCode();





