IdentityModel.OidcClient获取的Keycloak Access Token验证失败求助
问题:IdentityModel.OidcClient获取的Keycloak Access Token introspect验证失败
使用IdentityModel.OidcClient的WindowsConsoleSystemBrowser示例从Keycloak获取Access Token后,通过curl调用<oidcServer>/token/introspect端点验证时返回{"active": false},但使用curl密码模式(grant_type=password)生成的Token,用相同验证命令却能正常返回{"active": true}。
获取到的Token相关信息
jti:1fdfa552-c745-41fe-ab98-c9cc18e84d14; sub:17826477-591d-46bc-b5da-5731ad3e10a4; typ:ID; azp:smxxxpm; sid:1ee4d385-4188-46dd-a65c-72504e47206f; acr:1; email_verified:False; name:nomeSmit cognomeSmxx; preferred_username:smxx; given_name:nomeSmxx; family_name:cognomeSmxx; email:smxx.xpm@common.it; email_verified:false; **AccessToken**:eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJUcWN1TUlTWEhSRGpReVBjT0pkc1g4WHpkNmNDVVBCQ052RndTOUstOXpJIn0.eyJleHAiOjE3MzQzNjE1NDUsImlhdCI6MTczNDM2MTI0NSwiYXV0aF90aW1lIjoxNzM0MzYxMjQ1LCJqdGkiOiJjYTkxYTViOC00NjkwLTQwNWEtOTRiOS04MDEyODcxMTViOTkiLCJpc3MiOiJodHRwczovL2dndWFpdGEtMjAxNS5vYmplY3R3YXkuaXQ6ODQ0My9yZWFsbXMvZ2d1YWl0YS0yMDE1IiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjE3ODI2NDc3LTU5MWQtNDZiYy1iNWRhLTU3MzFhZDNlMTBhNCIsInR5cCI6IkJlYXJlciIsImF6cCI6InNtaXRPcG0iLCJzaWQiOiIxZWU0ZDM4NS00MTg4LTQ2ZGQtYTY1Yy03MjUwNGU0NzIwNmYiLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbImh0dHA6Ly9sb2NhbGhvc3QiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJkZWZhdWx0LXJvbGVzLWdndWFpdGEtMjAxNSJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoib3BlbmlkIGVtYWlsIHByb2ZpbGUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiJub21lU21pdCBjb2dub21lU21pdCIsInByZWZlcnJlZF91c2VybmFtZSI6InNtaXQiLCJnaXZlbl9uYW1lIjoibm9tZVNtaXQiLCJmYW1pbHlfbmFtZSI6ImNvZ25vbWVTbWl0IiwiZW1haWwiOiJnaW9yZ2lvLmd1YWl0YUBvYmplY3R3YXkuaXQifQ.eeDnwjnfxP_vNgEK7W-ogE0r1qzDf_XA_LzDS5pQ-3sSGNN5YPTqv-rYk81g15q16NFQBzkopCGQ7ywRZpUfL7ov17YrDg3vwqdEjnL-h174XZstAAe25kYPzsEbREaDdHIaJYZzCQO88PwsrsgS6WccWMP7dRals9krZe0aNEnUHYtJ2EIWQUe2TRSOmpbcRW0f7fePbKCVQ9DTQ-_nYZJqAgTzpdwQyTbEV9tCeTf7FH3V9AlilnhdIg0-IEWgHDvUk36n2Q5ktQgsZB1bwWpwiMybQ4ynf7GI73cusXGXaQBaYPvwuQOX7khpJHC0w6ffB0LpmlrKXHvhBGeMOg; **TypeToken**:Bearer; RefreshToken:eyJhbGciOiJIUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxNGYzYjA5Ni04MzI4LTQxOTQtOTJmNy0xMzA3ODE0MDQxMzYifQ.eyJleHAiOjE3MzQzNjMwNDUsImlhdCI6MTczNDM2MTI0NSwianRpIjoiM2E5M2Q5MDktMDcwNS00YzJhLThiYTItMWJhMDY4NDQ4NTc2IiwiaXNzIjoiaHR0cHM6Ly9nZ3VhaXRhLTIwMTUub2JqZWN0d2F5Lml0Ojg0NDMvcmVhbG1zL2dndWFpdGEtMjAxNSIsImF1ZCI6Imh0dHBzOi8vZ2d1YWl0YS0yMDE1Lm9iamVjdHdheS5pdDo4NDQzL3JlYWxtcy9nZ3VhaXRhLTIwMTUiLCJzdWIiOiIxNzgyNjQ3Ny01OTFkLTQ2YmMtYjVkYS01NzMxYWQzZTEwYTQiLCJ0eXAiOiJSZWZyZXNoIiwiYXpwIjoic21pdE9wbSIsInNpZCI6IjFlZTRkMzg1LTQxODgtNDZkZC1hNjVjLTcyNTA0ZTQ3MjA2ZiIsInNjb3BlIjoib3BlbmlkIGJhc2ljIHJvbGVzIHdlYi1vcmlnaW5zIGVtYWlsIHByb2ZpbGUgYWNyIn0.1aQy6Q18cICSXCPTIACaNTsjPligEHepoEQco0z_j0LHQVVDkZ-aU0GrqcABdEMyU-OH97sswhwUuJb7ZqK5lw;
验证Token的curl命令
curl -s --insecure -X "POST" "<oidcServer>/token/introspect" ^ -H "accept: application/json" ^ -H 'Content-Type: application/x-www-form-urlencoded' ^ -d "client_id=smxxxpm" ^ -d "client_secret=<oidcClientSecret>" ^ -d "token=<AccessToken>"
验证结果
{ "active": false }
curl密码模式生成Token的命令
curl -s --insecure -X "POST" "<oidcServer>/token" ^ -H "accept: application/json" ^ -H 'Content-Type: application/x-www-form-urlencoded' ^ -d "username=<username>" ^ -d "password=<password>" ^ -d "grant_type=password" ^ -d "client_id=smxxxpm" ^ -d "client_secret=<oidcClientSecret>"
密码模式Token的验证结果
{ "exp": 1734362264, "iat": 1734361964, "jti": "ab514bb3-17e3-46b6-8da0-46ef03adf5a8", "iss": "<odicServer>+realms", "aud": "account", "sub": "17826477-591d-46bc-b5da-5731ad3e10a4", "typ": "Bearer", "azp": "smxxxpm", "sid": "0640bef6-7b49-4af0-bf8d-ab05745558ab", "acr": "1", "allowed-origins": [ "http://localhost" ], "realm_access": { "roles": [ "offline_access", "uma_authorization", "default-roles-xxxxxx-xxxx" ] }, "resource_access": { "account": { "roles": [ "manage-account", "manage-account-links", "view-profile" ] } }, "scope": "email profile", "email_verified": false, "name": "nomeSmxx cognomeSmxx", "preferred_username": "smxx", "given_name": "nomeSmxx", "family_name": "cognomeSmxx", "email": "smxx.xpm@common.it", "client_id": "smxxxpm", "username": "smxx", "token_type": "Bearer", "active": true }
排查与解决方案
核心问题
你标注为AccessToken的内容实际上是ID Token(从typ:ID字段可判断),而Keycloak的/token/introspect端点默认验证的是Bearer类型的Access Token,传入ID Token会直接返回active:false。
解决步骤
获取正确的Access Token
在OidcClient的调用中,确保从TokenResponse.AccessToken属性获取值,而非ID Token。WindowsConsoleSystemBrowser示例中,RequestTokenAsync返回的TokenResponse包含AccessToken、IdToken等字段,注意区分。确认OidcClient配置
- 确保客户端配置的
Scope包含openid(必须),以及所需的权限如email、profile - 检查
RedirectUri是否与Keycloak客户端配置的Valid Redirect URIs一致(通常为http://localhost:xxxx这类本地回调地址) - 客户端
Access Type需设置为confidential,因为你使用了client_secret
- 确保客户端配置的
修正introspect调用
将token参数替换为真正的Access Token,示例:curl -s --insecure -X "POST" "<oidcServer>/token/introspect" ^ -H "accept: application/json" ^ -H 'Content-Type: application/x-www-form-urlencoded' ^ -d "client_id=smxxxpm" ^ -d "client_secret=<oidcClientSecret>" ^ -d "token=<从TokenResponse.AccessToken获取的正确值>"额外检查
- 用JWT解析工具查看Token的
typ字段是否为Bearer,exp是否未过期 - 在Keycloak后台的
Realm Settings->Events中开启登录和Token事件,排查是否有授权错误日志
- 用JWT解析工具查看Token的
内容的提问来源于stack exchange,提问作者gguaita
相关产品推荐
相关产品推荐

