Skip to content

Conversation

@EthanHeilman
Copy link
Collaborator

@EthanHeilman EthanHeilman commented Nov 2, 2025

This PR adds a short section on Token Refresh

  • non-normative examples

If an ID Token is returned as a result of a token refresh request, an additional requirement applies:

- its `cnf` claim MUST be the same as in the ID Token issued when the original authentication occurred.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are going to want to specify DPoP in the refresh request, and provide a non-normative example

@EthanHeilman EthanHeilman changed the title Token refresh, minor fixes Token refresh Nov 9, 2025
@JonasPrimbs
Copy link

To the best of my understanding, refreshing ID Tokens should not alter the ID Token's DPoP-bound JWK.

I like the idea of allowing the RP also to refresh the JWK. Do you have any security concerns, or is there a reason it should be prevented from doing that?

@dickhardt
Copy link
Collaborator

To the best of my understanding, refreshing ID Tokens should not alter the ID Token's DPoP-bound JWK.

I like the idea of allowing the RP also to refresh the JWK. Do you have any security concerns, or is there a reason it should be prevented from doing that?

@JonasPrimbs How are you thinking the RP would refresh the JWK?

@JonasPrimbs
Copy link

@JonasPrimbs How are you thinking the RP would refresh the JWK?

@dickhardt By sending another token request with authorization_grant=refresh_token (classic token refresh) and using a new JWK in the DPoP header.

@EthanHeilman
Copy link
Collaborator Author

@JonasPrimbs
I'm currently leaning towards not allowing the refresh flow to alter the JWK for following reason. I would really appreciate counter-arguments. I want to get it right.

There seem to be two ways to rotate JWKs during refresh.

  • First, you could simply introduce a new JWK key2 and perform a DPoP over key2 along with the refresh token. This would significantly weaken security because an attacker that steals the refresh token could now switch to a JWK of their choice.
  • Second, you could introduce a new JWK key2 and perform a DPoP over key1 and key2 along with the refresh token. This second option is significantly stronger as it proves the RP is holding both key1 and key2.

The second approach, while stronger than the first approach, is still to my mind weaker than the not allowing key rotation during refresh. Below I will explain my thinking on problems with the second approach.

If you are protecting the JWK signing key, key1, as a non-extractable key in a web browser, each time you change the key you introduce the risk that the new JWK signing key, key2, isn't setup to be non-extractable.

Consider the following attack:

  1. Alice generates key1 as a non-extractable key in her browser.

  2. Eve compromises Alice's javascript client via a XSS attack and can now request signatures from Alice's non-extractable key1, but can not extract/export key1. This means Eve can only impersonate Alice while Alice has the browser tab with the compromised javascript open. If Alice closes their tab, turns off her computer or refreshes, in most scenarios Eve loses access.

  3. IF we allow the ability to rotate JWKs, Eve generates a new key, key2 which is extractable and then does a DPoP Refresh flow with the refresh token and key1, to move to key2. Now Eve can use key2 and the refresh token to impersonate Alice indefinitely.

However if we do not allow the ability to rotate JWKs, Eve can not use the refresh flow to substitute an extractable key2 for Alice's original key1 which is non-extractable. This also applies to the use of HSM/passkeys in other settings. Remote attestation can be used to prove a key was generated inside an HSM, but this attacks complexity and additional security assumptions.

Normally we rotate keys to minimize the window of vulnerability after a compromise. I could be mistaken and I'm very interested in hearing disagreeing opinions, but in this case, I don't only see ways in which enabling key rotations in the refresh flow helps an attacker.

Appendix H Device Signing Keys and XSS Attacks in the OpenPubkey paper, has a deeper discussion of how to use JWKs with extractable keys to constraint XSS attackers. It isn't necessary for this discussion, but does provide more context.

@JonasPrimbs
Copy link

@EthanHeilman
I agree. Providing the opportunity to refresh the key allows cloning the session to a remote attacker, while fixing this key enables the RP to protect itself from this attack by using a non-extractable key.

Besides that, I'm not feeling well with not being able to rotate the key of a refresh token. However, specifically for the refresh token, I think this is fine if we use hardware-bound/non-extractable tokens (TPM- or HSM-backed). The tokens themselves can be rotated or revoked in the event of a compromised RP being detected, and I value the security advantage of not being able to move the refresh token to another device.

Maybe combining the following requirements can reduce this problem to an acceptable level:

  1. Binding the refresh token to a fixed non-extractable key.
  2. Allowing the RP to refresh the ID token with another key (explicitly NOT the refresh token key) by proving the possession of both keys (refresh token key to prove authorization + ID token key to prove possession).
  3. Short ID token lifetime (~1 minute).

Since the attacker would need the refresh token key to obtain a new ID token, the user must be online, as the refresh token key is non-extractable and can therefore not be transferred to the attacker's device.
The attacker could still use XSS to get a new ID token bound to the attacker's extractable key pair. However, the short validity period makes this ID token usable only within its lifetime. To obtain a new one, the attacker again requires an online user with an active XSS attack and cannot refresh the ID token from their device indefinitely.

Using separate key pairs for distinct use cases with different lifetimes (long-term refresh tokens for refreshing access tokens, short-term ID tokens for authentication, and short-term access tokens for authorization) is a nice pattern that should also be applied here, if we want to do everything right.
I have just discovered that there is an Internet Draft with the same purpose, but for access tokens (rotating short-term access token key pairs and fixing the long-term refresh token).
They use a dedicated DPoP-RT header for the DPoP proof of the refresh token. Perhaps we could also introduce a DPoP-ID header for this purpose.

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

Successfully merging this pull request may close these issues.

4 participants