适用版本: 7.x-8.x
1. 错误异常的基本描述 #
Failed to verify access token. ID Token doesn't contain at_hash claim 表示 Elasticsearch 在 OIDC(OpenID Connect)认证流程中,尝试对 Access Token 进行完整性校验时失败。根据 OIDC 规范,at_hash(Access Token Hash)是 ID Token 中的一个可选声明,用于让依赖方(Relying Party)校验 Access Token 的完整性。当 Elasticsearch 的 OIDC Realm 配置要求验证 Access Token,但 IdP(身份提供商)返回的 ID Token 中缺少 at_hash 声明时,就会触发此异常。
常见现象 #
- 用户通过 OIDC 登录 Elasticsearch 或 Kibana 时,在认证回调阶段失败,页面报错或无限重定向。
- Elasticsearch 日志中出现
Failed to verify access token. ID Token doesn't contain at_hash claim异常信息。 - 多见于
implicit flow或hybrid flow,且配置中同时返回了id_token与access_token的场景。 - 部分用户正常登录,部分用户失败,取决于 IdP 针对不同的授权请求是否签发了
at_hash。
典型报错与异常栈 #
if (Strings.hasText(idTokenClaimsSet.getStringClaim("at_hash")) == false) {
listener.onFailure(new ElasticsearchSecurityException(
"Failed to verify access token. ID Token doesn't contain at_hash claim"
));
}
实际日志中可能出现如下堆栈信息:
[2026-04-04T10:00:00,000][WARN ][o.e.x.s.a.o.OIDCIdpAuthenticator] [node-1] Failed to verify access token
ElasticsearchSecurityException: Failed to verify access token. ID Token doesn't contain at_hash claim
at org.elasticsearch.xpack.security.authc.oidc.OpenIdConnectAuthenticator.validateAccessToken(OpenIdConnectAuthenticator.java:XXX)
at org.elasticsearch.xpack.security.authc.oidc.OpenIdConnectAuthenticator.authenticate(OpenIdConnectAuthenticator.java:XXX)
2. 为什么会发生这个错误 #
at_hash 是 OIDC 规范(
OpenID Connect Core 1.0 - Section 3.3.2.11)中定义的一个声明。其作用是:当 ID Token 与 Access Token 同时返回时,客户端可以通过 at_hash 中的哈希值校验 Access Token 是否被篡改。
Elasticsearch 的 OIDC Realm 在以下情况下会触发 at_hash 校验:
- Realm 配置中启用了
opaque_id或 Access Token 验证相关的选项。 - 授权响应类型为
id_token token(implicit flow)或code token/code id_token token(hybrid flow)。
常见原因包括:
- IdP 未签发
at_hash:部分 IdP(如某些旧版本 Keycloak、Auth0 特定配置、或自定义 OIDC 实现)在返回 Access Token 时未按要求计算并写入at_hash声明。 - 授权流程配置不匹配:Elasticsearch OIDC Realm 的
response_type配置为id_token,但 IdP 实际返回了包含 Access Token 的响应,或反之。 - Token 被中间件修改:如果在 Elasticsearch 之前部署了网关、反向代理或自定义鉴权层(如 Nginx Lua、Envoy ext_authz),这些中间件可能对 ID Token 做了重签、解码再编码或裁剪,导致
at_hash声明丢失。 - ID Token 来源不正确:使用了非 IdP 直接签发的 ID Token(例如从缓存、Session 或第三方服务中获取的旧 Token)。
3. 如何排查此异常 #
建议按以下步骤逐一排查:
解码 ID Token:将登录回调中收到的 ID Token(JWT 格式)进行 Base64 解码,检查其 payload 中是否包含
at_hash字段。# 解码 ID Token(JWT 第二段) echo "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYXRfaGFzaCI6IndpVFRqMTVXSVFpWE1mZlB1YkRNdyIsImlzcyI6Imh0dHBzOi8vaWRwLmV4YW1wbGUuY29tIiwiYXVkIjoiY2xpZW50LWlkIiwiZXhwIjoxNzA4MDAwMDAwfQ.signature" \ | cut -d'.' -f2 | base64 -d | jq .核对 OIDC Realm 配置:检查
elasticsearch.yml中 OIDC Realm 的response_type设置,确认其与 IdP 侧配置的授权流程一致。检查 IdP 的 OIDC 配置:查阅 IdP 文档,确认在当前授权流程下是否应该返回
at_hash。例如,Keycloak 在implicit和hybridflow 下默认会签发at_hash,但某些配置可能禁用此行为。确认无中间件篡改:如果架构中存在网关或自定义鉴权层,检查是否对 Token 做了处理。可以对比客户端直接收到的原始 ID Token 与 Elasticsearch 侧收到的 Token 是否一致。
查看完整日志:在
elasticsearch.yml中临时开启 DEBUG 日志,获取更详细的 OIDC 认证上下文:logger.org.elasticsearch.xpack.security.authc.oidc: DEBUG
4. 如何解决这个错误 #
方案一:调整 IdP 配置,使其签发 at_hash
#
这是最推荐的解决方案。以 Keycloak 为例,确保:
- 客户端(Client)的
Standard Flow Enabled和Implicit Flow Enabled配置与 Elasticsearch OIDC Realm 的response_type匹配。 - 在客户端设置中,确认
ID Token Signature Algorithm和Access Token Signature Algorithm配置正确,且 IdP 在同时返回 ID Token 和 Access Token 时自动计算at_hash。
Keycloak 相关配置示例(通过 Admin Console):
Clients -> your-client -> Settings:
- Standard Flow Enabled: ON
- Implicit Flow Enabled: OFF(如使用 authorization_code flow)
- ID Token Signature Algorithm: RS256
方案二:调整 Elasticsearch OIDC Realm 配置 #
如果 IdP 确实无法签发 at_hash,可考虑调整 Elasticsearch 侧配置,避免触发 Access Token 校验。在 elasticsearch.yml 中检查 OIDC Realm 配置:
xpack.security.authc.realms.oidc.oidc1:
type: oidc
order: 2
idp.metadata.path: "https://idp.example.com/.well-known/openid-configuration"
idp.client_id: "elasticsearch-client"
idp.client_secret: "your-client-secret"
rp.response_type: "code" # 使用 authorization_code,避免 implicit/hybrid flow
rp.redirect_uri: "https://es.example.com/api/security/v1/oidc"
claims.principal: "sub"
将 rp.response_type 设置为 code(默认值),可以规避 at_hash 校验问题,因为 authorization_code flow 中 Access Token 通过后端 token endpoint 换取,不在 ID Token 中同时返回。
方案三:检查并修正中间件行为 #
如果使用 INFINI Gateway 或其他网关在 Elasticsearch 前端做认证预处理,确保:
- 不对 ID Token 进行重签或 payload 修改。
- 如需要注入自定义声明,使用
x-前缀的私有声明,不删除标准声明如at_hash、iss、sub、aud、exp、iat。
后续注意事项与推荐建议 #
- 统一 OIDC 授权流程:避免在同一个 IdP 客户端上同时启用多种不兼容的授权流程,减少配置歧义。
- 定期校验 Token 内容:在升级 IdP、网关或 Elasticsearch 版本后,重新解码 ID Token 确认关键声明(
iss、sub、aud、exp、iat、at_hash)完整无误。 - 监控认证失败率:通过 INFINI Console 监控 OIDC 认证失败趋势,及时发现因
at_hash缺失或其他 Token 问题导致的登录异常。
借助 INFINI 产品提升排障效率 #
- INFINI Console 适合查看 Elasticsearch 集群的认证日志、安全事件趋势和请求画像,帮助快速判断 OIDC 登录失败是配置问题还是 IdP 侧问题。
- INFINI Gateway 适合部署在 Elasticsearch 前面做请求观测、认证透传和流量治理。在 OIDC 场景下,Gateway 可以记录完整的 Token 交换过程,便于对比客户端与服务器端收到的 ID Token 是否一致。
5. 小结 #
Failed to verify access token. ID Token doesn't contain at_hash claim 是一个与 OIDC 协议实现细节高度相关的异常。核心问题始终是 at_hash 声明缺失,排查时应围绕 ID Token 内容、IdP 签发策略和 Elasticsearch OIDC Realm 配置三条线索展开。首选方案是调整 IdP 使其按规范签发 at_hash;其次是通过将 response_type 切换为 code 来规避该问题。
相关错误 #
参考链接 #
附:日志上下文 #
if (Strings.hasText(idTokenClaimsSet.getStringClaim("at_hash")) == false) {
listener.onFailure(new ElasticsearchSecurityException(
"Failed to verify access token. ID Token doesn't contain at_hash claim"
));
}





