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

Token respose does not always include nonce #186

Open
Darkrael opened this issue Oct 31, 2024 · 4 comments
Open

Token respose does not always include nonce #186

Darkrael opened this issue Oct 31, 2024 · 4 comments

Comments

@Darkrael
Copy link

While upgrading to Keycloak version >25 , i've noticed, that exchanging the refresh token for a new access token and extracting the claims, the token verification fails due to the nonce not being included in refresh request responses anymore.
This is due to Keycloak now following the OpenID Connect Core 1.0 specification recommendation to not include the nonce in a refresh request: https://www.keycloak.org/docs/26.0.4/upgrading/#nonce-claim-is-only-added-to-the-id-token.
This can be "fixed" by adding the Nonce backwards compatible to the Keycloak configuration for the client, but i think it should be possible to get the claims without checking the nonce, which i think is not possible at the moment unless i've overlooked something.

@ramosbugs
Copy link
Owner

Hey @Darkrael, thanks for reporting this issue. The relevant portion of the spec is:

it SHOULD NOT have a nonce Claim, even when the ID Token issued at the time of the original authentication contained nonce; however, if it is present, its value MUST be the same as in the ID Token issued at the time of the original authentication

This crate's IdToken::claims method accepts a generic NonceVerifier trait when verifying the ID token and extracting the claims. I think it probably makes sense to add an IgnoreNonceForTokenRefresh struct to this crate that implements NonceVerifier and ignores the nonce. Users can pass this struct when reading ID tokens returned via a token refresh. Does that sound reasonable?

@Darkrael
Copy link
Author

This would certainly allow users to handle refreshes correctly, but it would not be immediatly clear to people that this should be used.
It would make more sense to me that this would be the "default" behavior. However, if i understand the code correctly, there is no difference between a token gained through refresh and a token gained through the initial authentication flow, where the nonce must be given.
Maybe the IdToken could have a property to store if it was gained through refresh or through the initial authentication flow.
The "default" verifier (meaning the one provided by the Client) could then take this into account when verifying the token and ignore an empty nonce for refresh token.
Since i don't know the code at all apart from quickly scrolling though, i don't know if this would be feasable to implement.
Otherwise the suggested solution together with a small note in the claims function to use the other verifier for refresh tokens should be good.

@ramosbugs
Copy link
Owner

if i understand the code correctly, there is no difference between a token gained through refresh and a token gained through the initial authentication flow, where the nonce must be given.

that's right. the provenance of the ID token isn't stored currently. I'll have to think about the best way to represent this in the type system, but that will probably be a more involved change.

I think for now, I'll introduce the IgnoreNonceForTokenRefresh nonce verifier and mention in the IdToken::claims docs to use it for ID tokens that came from a token refresh. I may also add an example.

@ramosbugs
Copy link
Owner

ramosbugs commented Nov 1, 2024

oh, I forgot NonceVerifier is also implemented for FnOnce(Option<&Nonce>) -> Result<(), String>. this means users can just do:

id_token.claims(&id_token_verifier, |_| Ok(()))

In that case, I think I'll just mention this in the docs for that method instead of adding a dedicated struct, which might be more likely to be misused for non-refresh tokens (a security vulnerability).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants