-
Bug
-
Resolution: Done
-
Undefined
-
None
-
False
-
-
False
-
-
Before reporting an issue
[x] I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.
Area
oidc
Describe the bug
I've sent an UserInfo request with invalid DPoP proof with headers like:
{
"endpoint" : "https://as.keycloak-fapi.org:8443/realms/test/protocol/openid-connect/userinfo",
"Headers" : {
"Authorization" : "DPoP eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJYUHlTRV9fQk9lY2pxTVA2V0FIemk5SEFQMFgyaWxpVDRfamVmV0paVGlzIn0.eyJleHAiOjE3NTgxMTU2MzIsImlhdCI6MTc1ODExNTMzMiwiYXV0aF90aW1lIjoxNzU4MTEyOTM1LCJqdGkiOiJvbnJ0cnQ6ZWM2N2E3NWEtMTBhNy0zOTBhLTQwZjYtYmQ4NTFjNjQwNmUyIiwiaXNzIjoiaHR0cHM6Ly9hcy5rZXljbG9hay1mYXBpLm9yZzo4NDQzL3JlYWxtcy90ZXN0IiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImVkYTk2ODNjLTljMWMtNGUzOS1hOTUyLTgwNGU2M2JjZWY5ZCIsInR5cCI6IkRQb1AiLCJhenAiOiI5OTAxYzZhYy00Yjc3LTRhZDYtODcyMS0wNTc5NmRjZTc2ZjkiLCJzaWQiOiI0Y2M1Njg3ZS1kMzU2LWNjZmYtYzk4MS04NWJhM2Q2MTBkODYiLCJhY3IiOiIwIiwiYWxsb3dlZC1vcmlnaW5zIjpbImh0dHBzOi8vYXBwLmtleWNsb2FrLWZhcGkub3JnOjg1NDMiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtdGVzdCIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJjbmYiOnsiamt0IjoiMXlOVnNMWS1oM0JSRFNHNVFsTDRFaFlFLTYyT0xONENWdFJUVWtkdHdzUSJ9LCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiSm9obiBCYXIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJqb2huIiwiZ2l2ZW5fbmFtZSI6IkpvaG4iLCJmYW1pbHlfbmFtZSI6IkJhciIsImVtYWlsIjoiam9obkBlbWFpbC5jeiJ9.R15ATuW3mCvRgk-4869m28vyc0jExqyxDr5ywMIfDxvZhfaQJsdkQ-dJPDSPVOW1JoIXtNTP_UqIQhz6C72FaestBSad3wdXowS6HcJyjvXNcLQWzZeyyB7hSRQOK8bC0FEhLRgK9bOe0BnzD09OPNXSAwh4oLmpjxLtuuHjhRUKJojlGBzwkSOmuH6JU1Kse2xACPszJtW1IMwv2knJnEitJUHvLBC0bqNMvIA7FApwy0BrR52OnjCSsaSyFqNhZDckDTgdV9iUDhcHlsiJVsLe5lY__it1yEJeHrRoY84oikZ0cuDYg7L-LkNl9ra-yW2Y9sF_By_w8dy69LVThA",
"Accept" : "application/json",
"DPoP" : "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiZHBvcCtqd3QiLCJraWQiIDogInFQcGFBQjllU0pXelc1czVYMmFFdkdTNlVlejhSNUw4N2hVVElORHBoa1UiLCJqd2siIDogeyJraWQiOiJxUHBhQUI5ZVNKV3pXNXM1WDJhRXZHUzZVZXo4UjVMODdoVVRJTkRwaGtVIiwia3R5IjoiUlNBIiwidXNlIjoic2lnIiwibiI6InFzMEFDNEljd1BzV3JFV1BxdEZiVXV1WTkxU2QwaDhBUXRWMEtrdzcxYkYxZW9NT3pVbWdQNkViaFFDdWxrbGFDejljd0ZudDdZbUFfQ0R3ZTRkWlRwQUVaNnNmMjgtSXVGX2tfZDFiangyM1ZNTDlndm80akViWUw0ay1lQzVnMTZuNklqTkZJbzZuZzh3cnBKR25YSTVoZ2t5Y2ZmY0NZMktHZG1wZFJYcDdQVHNGaWZBZEtLcGp6TUczR3R2cjVHLTNTa2RXUFRWU3JydW5mNFVBVGgyckcyZ0RvRUhKMGhoVXdDaUg0OUo3ckc5Q0FvMmZmZ3pkUkJuQnlRVzFVMWk3U2JYdGRtTjN4azNiZ1pYQ1NnOEhMN3E5UWVpVW00VmE2QTBpaWJ1ZnJwVF9uZ0twTE84WUg1NkZNMncxeVVuQUpxSk9mNnVMOVZKWUhMTHhDdyIsImUiOiJBUUFCIn19.eyJpYXQiOjE3NTgxMTUzODUsImp0aSI6IjRiNGIzMWI4LWM3ZTEtYjNiZi0xNjZjLWRlYmVmZWJmNDY3MCIsImF0aCI6IjNFOGF6cU9zblNGRzN5eV85bmplMWlCR3dIZTZUQ3J5dTZCajlBQ0pPTlEiLCJodG0iOiJHRVQiLCJodHUiOiJodHRwczovL2FzLmtleWNsb2FrLWZhcGkub3JnOjg0NDMvcmVhbG1zL3Rlc3QvcHJvdG9jb2wvb3BlbmlkLWNvbm5lY3QvdXNlcmluZm8ifQ.lntPWrJe6JC_obNKB5c0lXbu8I87_U78WZ-8f_l_BmE66XsGdLh4FVHJek-kqbRurEyfe3RI-MqoNtja3_D08UoNoZbnsAcL4liszE2zxlDbFD4i1ZDtrNyHLS-UNpaj1KcmB9y3zgGgIR9I6FsONIFn3iKt8A0ryJTUocoew_2bhej5tEmhMQVqW6Pc676OaIYVtIiqOpMdlfyhOQ08QsH1CmjkcfdqQd2D-GeP9mMzVrOZjvos2FRwczycahDSOPLLJQVBZkBWYyF0CwJegObN7RboH02fEjz4qZzWjlAEwj0db7YEu1VA4yrB4-Foy9aLryZpHIyJr6fHABo7iQ"
} }
The response looks like this:
{
"statusCode" : 401,
"headers" : {
"Referrer-Policy" : "no-referrer",
"content-length" : "0",
"Strict-Transport-Security" : "max-age=31536000; includeSubDomains",
"X-Content-Type-Options" : "nosniff",
"WWW-Authenticate" : "Bearer realm=\"test\", error=\"invalid_token\", error_description=\"Token verification failed\"",
"Content-Type" : "text/plain;charset=utf-8"
}, "success" : false }
The response did contains WWW-Authenticate header with the scheme Bearer, which is a bit strange as I've used Authorization: DPoP and hence I would expect WWW-Authenticate: DPoP ... response header instead.
The user-info endpoint is supposed to support rfc6750 according to the OIDC Core specification and the DPoP specification specifies that WWW-Authenticate: DPoP ... might be used in such cases. Especially in this section https://datatracker.ietf.org/doc/html/rfc9449#section-7.2 , it mentions that:
If the mechanism used to attempt authentication could be established unambiguously, then the corresponding challenge SHOULD be used to deliver error information (Figure 18).
Based on that, my understanding is, that it would be better to use WWW-Authenticate: DPoP ... in this challenge.
Per my understanding, I can imagine this behaviour:
- If user-info request was sent with Authorization: Bearer incorrect-access-token, I expect that WWW-Authenticate header will contain Bearer scheme as it is now.
- If user-info request was sent with Authorization: DPoP incorrect-access-token, I expect that WWW-Authenticate header will contain DPoP challenge instead of Bearer.
- If user-info request was sent without Authorization header (or with incorrect scheme), we might use WWW-Authenticate with both Bearer and DPoP . However for the backwards compatibility, it may be better to stick just with Bearer as it is possible that some clients might see compatibility issues if we start to include DPoP header automatically. Per my understanding, we are not required to include DPoP in such a case. So my vote is to still only use Bearer as we are doing today.
Version
nightly (from 2025-09-17)
Regression
[ ] The issue is a regression
Expected behavior
The WWW-Authenticate: DPoP header will be used in the case when 401 is returned from the userInfo request
Actual behavior
The WWW-Authenticate: Bearer header is used in the case when 401 is returned from the userInfo request
How to Reproduce?
See the details
Anything else?
This is specific to the user-info endpoint. The other Keycloak endpoints accepting Authorization: DPoP header (EG. admin REST API or account REST API) currently does not return WWW-Authenticate header at all and is not strictly treated as rfc6750 aware response.
- links to