Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

invalid signature key on standard flow callback with response_mode=query.jwt #30642

Closed
1 of 2 tasks
ninetz opened this issue Jun 21, 2024 · 6 comments
Closed
1 of 2 tasks
Labels
area/authentication Indicates an issue on Authentication area kind/bug Categorizes a PR related to a bug team/core-clients

Comments

@ninetz
Copy link

ninetz commented Jun 21, 2024

Before reporting an issue

  • 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

authentication

Describe the bug

After initiating a standard flow with Pushed Authorization Request with JAR ( https://openid.net/specs/oauth-v2-jarm-final.html ) with response_mode=query.jwt, user successfully logging in and after being redirected to callback url with response parameter, the JWT inside response is signed using an unknown key. The KID that keycloak puts the in header of the JWT is not what the JWT is actually signed with.

Version

25.0.1 ( latest )

Regression

  • The issue is a regression

Expected behavior

The JWT that is inside the "response" parameter after initiating flow with response_mode=query.jwt should be signed with the key (kid) that is inside the JWT header.

Actual behavior

JWT that is inside "response" after initiating flow with response_mode=query.jwt claims to be signed with the correct algorithm and KID, but when we get the public key/certificate of the specified KID in the JWT header from /certs endpoint and verify the signature using jwt.io or some other JWT claims parser, the signature doesn't match - the JWT isn't actually signed with the KID that is in the header.

How to Reproduce?

  1. Create a Pushed Authorization Request with JAR ( https://oauth.net/2/pushed-authorization-requests/ ) ( https://openid.net/specs/oauth-v2-jarm-final.html )
  2. Specify response_mode=query.jwt inside the Pushed Authorization Request JAR
  3. On sucessful login and callback, the "response" parameter JWT from Keycloak has an invalid signature - the KID that is in the header is not what the JWT is actually signed with - verify with public key/certificate exposed by /certs endpoint

Anything else?

It is really odd that the KID in the header actually exists in the /certs endpoint but when I retrieve the public key/certificate of the kid and attempt to verify the JWT, the signature does not match. Keycloak puts the correct KID in the header but using some different key to actually sign the JWT?

@ninetz ninetz added kind/bug Categorizes a PR related to a bug status/triage labels Jun 21, 2024
@keycloak-github-bot keycloak-github-bot bot added area/authentication Indicates an issue on Authentication area team/core-clients labels Jun 21, 2024
@ninetz ninetz changed the title invalid signature algorithm on standard flow callback with response_mode=query.jwt invalid signature key on standard flow callback with response_mode=query.jwt Jun 21, 2024
@rmartinc
Copy link
Contributor

Hi @ninetz!

I cannot reproduce this. I did the following to try to reproduce this:

  1. Keycloak 25.0.1 downloaded and started.
  2. Create a test-oidc client normally with valid redirects to http:https://localhost:8081/*.
  3. Create a login with the following URL: http:https://localhost:8080/realms/master/protocol/openid-connect/auth?client_id=test-oidc&redirect_uri=http%3A%2F%2Flocalhost%3A8081%2F&state=2657e0bb-08fc-453d-aa83-b8b35ab33378&response_mode=query.jwt&response_type=code&scope=openid
  4. After login it returns the response: http:https://localhost:8081/?response=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSaUpzbHhfM1ROem90MjJDUFdOOFprSW9ENlFTcDE4S2ZFdXo1T1pUakFjIn0.eyJleHAiOjE3MTg5NTU3MDgsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbWFzdGVyIiwiYXVkIjoidGVzdC1vaWRjIiwiY29kZSI6ImQ1YjIzZTQyLWFlMTgtNDgyYy1iYjA3LWNjYmUyZmZlZGRiZi5lOTk5YzVkMi1mMmMwLTQwZGEtOGQ5NS0zNWY4ZDIwMjdlOTMuZTEyYWUzNTctY2VmZi00MTE5LTk4MmMtMDMxYmJjZWNiMzBiIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy9tYXN0ZXIiLCJzdGF0ZSI6IjI2NTdlMGJiLTA4ZmMtNDUzZC1hYTgzLWI4YjM1YWIzMzM3OCIsInNlc3Npb25fc3RhdGUiOiJlOTk5YzVkMi1mMmMwLTQwZGEtOGQ5NS0zNWY4ZDIwMjdlOTMifQ.X9MTcg8tm1FOA-n_T4xoNcnmMP1R1puaVLXs48RoLFxbbD-4L1Qc8FQUH_0i59t31DhffWKdE9WqWlof2dfwROXtiJOLc3ac1DJPpb1SHhspbpBfq-m_glpWkE57sFA0AybEor2mJVNdNboYk_x6TwavM8vwRfO_P7bTsPqSh6io-l2YGEZE3LCYFjJilOD1CoruRHR_XG6iN0cH0Y7GkFubocANvt31E5fGah4T50hmxjKo8GiATWXXDPd-ON9A2I6W0HqmECxzpGOhi4SH9x9Stb7MA9O_HJ7lFIwbhFL62aZDvhe_cMQUwkfMa6EW3FjgtysbY3IulNGwgCWKGw
  5. With that response I went to jwt.io and pasted the response. It is marked as signature valid (it is downloaded from my jwks_uri using localhost).

Screenshot from 2024-06-21 09-44-24

So jwt.io detects the response as valid and it is using the jwks_uri of the well-known address to validate the signature. Besides we are testing this in the CI here. Am I missing something?

@ninetz
Copy link
Author

ninetz commented Jun 21, 2024

Hi @ninetz!

I cannot reproduce this. I did the following to try to reproduce this:

  1. Keycloak 25.0.1 downloaded and started.
  2. Create a test-oidc client normally with valid redirects to http:https://localhost:8081/*.
  3. Create a login with the following URL: http:https://localhost:8080/realms/master/protocol/openid-connect/auth?client_id=test-oidc&redirect_uri=http%3A%2F%2Flocalhost%3A8081%2F&state=2657e0bb-08fc-453d-aa83-b8b35ab33378&response_mode=query.jwt&response_type=code&scope=openid
  4. After login it returns the response: http:https://localhost:8081/?response=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSaUpzbHhfM1ROem90MjJDUFdOOFprSW9ENlFTcDE4S2ZFdXo1T1pUakFjIn0.eyJleHAiOjE3MTg5NTU3MDgsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbWFzdGVyIiwiYXVkIjoidGVzdC1vaWRjIiwiY29kZSI6ImQ1YjIzZTQyLWFlMTgtNDgyYy1iYjA3LWNjYmUyZmZlZGRiZi5lOTk5YzVkMi1mMmMwLTQwZGEtOGQ5NS0zNWY4ZDIwMjdlOTMuZTEyYWUzNTctY2VmZi00MTE5LTk4MmMtMDMxYmJjZWNiMzBiIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy9tYXN0ZXIiLCJzdGF0ZSI6IjI2NTdlMGJiLTA4ZmMtNDUzZC1hYTgzLWI4YjM1YWIzMzM3OCIsInNlc3Npb25fc3RhdGUiOiJlOTk5YzVkMi1mMmMwLTQwZGEtOGQ5NS0zNWY4ZDIwMjdlOTMifQ.X9MTcg8tm1FOA-n_T4xoNcnmMP1R1puaVLXs48RoLFxbbD-4L1Qc8FQUH_0i59t31DhffWKdE9WqWlof2dfwROXtiJOLc3ac1DJPpb1SHhspbpBfq-m_glpWkE57sFA0AybEor2mJVNdNboYk_x6TwavM8vwRfO_P7bTsPqSh6io-l2YGEZE3LCYFjJilOD1CoruRHR_XG6iN0cH0Y7GkFubocANvt31E5fGah4T50hmxjKo8GiATWXXDPd-ON9A2I6W0HqmECxzpGOhi4SH9x9Stb7MA9O_HJ7lFIwbhFL62aZDvhe_cMQUwkfMa6EW3FjgtysbY3IulNGwgCWKGw
  5. With that response I went to jwt.io and pasted the response. It is marked as signature valid (it is downloaded from my jwks_uri using localhost).

Screenshot from 2024-06-21 09-44-24

So jwt.io detects the response as valid and it is using the jwks_uri of the well-known address to validate the signature. Besides we are testing this in the CI here. Am I missing something?

Are you able to verify the signature only using the certificate or public key? I am not able to, but when I paste the whole key json object like you did, I am also able to verify the signature.

I am now unsure if this is intended behavior- that you CANNOT verify the signature using ONLY public certificate or ONLY public key

@rmartinc
Copy link
Contributor

@ninetz The jwks_uri endpoint is just the public key representation in a specific format. The jwt.io is just downloading it from the endpoint (http:https://localhost:8080/realms/master/protocol/openid-connect/certs in my case). My feeling is that you are doing something wrong trying to verify the signature.

@ninetz
Copy link
Author

ninetz commented Jun 21, 2024

@ninetz The jwks_uri endpoint is just the public key representation in a specific format. The jwt.io is just downloading it from the endpoint (http:https://localhost:8080/realms/master/protocol/openid-connect/certs in my case). My feeling is that you are doing something wrong trying to verify the signature.

@rmartinc It could be that I am doing something wrong - when I am verifying the signature in the application, I am verifying it only using the public certificate (x5c attribute) retrieved from the certs endpoint. This verification works fine when verifying access tokens but not when verifying the response. Is that intended behavior - that I am not able to verify this response JWT using only x5c cert?

@rmartinc
Copy link
Contributor

Can you please paste the code or something you are using to validate? Try to attach something easy to test just changing the token and the certificate. Not partial code or similar.

@ninetz
Copy link
Author

ninetz commented Jun 21, 2024

Can you please paste the code or something you are using to validate? Try to attach something easy to test just changing the token and the certificate. Not partial code or similar.

@rmartinc As I was writing the code to give to you and testing it further, in the end it was not Keycloak that was the problem but the function that I was using to parse the JWT that was causing issues. I used Claims parsing which could not be applied to the response JWT but could be applied to access token parsing which caused the issue.

Thanks for your help :)

@ninetz ninetz closed this as completed Jun 21, 2024
@martin-kanis martin-kanis closed this as not planned Won't fix, can't repro, duplicate, stale Jun 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/authentication Indicates an issue on Authentication area kind/bug Categorizes a PR related to a bug team/core-clients
Projects
None yet
Development

No branches or pull requests

3 participants