oauth-wg / draft-ietf-oauth-attestation-based-client-auth

Other
12 stars 6 forks source link

Refresh token binding after attestation expiration #57

Closed cobward closed 9 months ago

cobward commented 1 year ago

Currently section 5.2 states:

The client MUST also use the same key that was present in the "cnf" claim of the client attestation that was used for client authentication when the refresh token was issued.

In the case that the original client attestation JWT has expired, what should happen? If it is acceptable for the client to re-use the same key in the "cnf" field across attestation JWTs, then the client can easily generate a new attestation JWT with the same "cnf" key. But if the client needs to use a fresh "cnf" key, then I can think of three options:

  1. Define a flow which endorses the new "cnf" key with the old "cnf" key.
  2. Define a field in the client attestation JWT that contains a unique identifier for the client instance, and use that identifier to bind the refresh token to the client instance.
  3. Explicitly don't permit this in the specification, add text to the specification that makes it clear that the "cnf" key must stay the same across refreshed client attestations.

My preference would be for option 2.

tplooker commented 1 year ago

In the case that the original client attestation JWT has expired, what should happen?

Currently the client instance needs to go back to the client backend and request a new client attestation JWT bound to the same key used in the old JWT.

In general because we are effectively using the client instance key to identify the instance at the authorization server this makes key rotation of the client instance key difficult with active refresh tokens.

1 feels too complex, 3 is an option and @bc-pi and I have discussed 2 before. The flip side to consider with option 2 is the privacy implications of formally electing to track client instances, personally i'm not convinced its a bad idea but we should carefully consider the impact.

tlodderstedt commented 1 year ago

In general because we are effectively using the client instance key to identify the instance at the authorization server

Do we? I had assumed the AS identifies the client by the sub value. I don't see a need to identify a client instance.

tlodderstedt commented 1 year ago

the forth option is to have long living client attestations, which in my opinion is no problem

the client should then use different attestations with different ASs

cobward commented 1 year ago

The flip side to consider with option 2 is the privacy implications of formally electing to track client instances, personally i'm not convinced its a bad idea but we should carefully consider the impact.

This just makes explicit the tracking of client instances that already existed through the requirement for the "cnf" key to stay the same over attestations.

the forth option is to have long living client attestations, which in my opinion is no problem

This is really a decision for the use-case in my opinion. In the context of software integrity being established through the client attestation, it is trivial to inject malware after the generation of the attestation, so some in some cases it may be a requirement to have fresh attestations.

paulbastian commented 1 year ago

Isn't the AS identifying the client also by the refresh token itself?

I dislike option 2 due to the privacy implications. As any optional fields in the client attestation JWT are valid, profiles could still use this option, but it should not be a good requirement in my opinion.

I see two options: A: the wallet initially gets one client attestation and uses the cnf key over a longer period to bind a sequence of refresh tokens to it. -> similar to option 4?

B: the Wallet initially gets one client attestation and the AS binds the first refresh token to the cnf key. When it uses the refresh token, it also provides a new client attestation with a new cnf key and the AS binds a new refresh token to this new key. -> similar to option 1?

tplooker commented 1 year ago

Do we? I had assumed the AS identifies the client by the sub value. I don't see a need to identify a client instance.

Well the current language doesn't actually guarantee that the AS can track the client instance (which is a good thing IMO), as the instance can in many common cases, rotate the keys it uses in between fetching tokens. But in the event a client instance is exchanging a refresh token for a fresh access token and potentially another refresh token, the client instance must authenticate using a client attestation JWT with the same key in the cnf claim that was in the original attestation used when the refresh token was obtained. This ensures one client instance can't use another client instances refresh token. So in this case the AS can track that the client instance who obtained the refresh token is the client instance now requesting to exchange it for a new access token, which is desired from a security perspective.

This just makes explicit the tracking of client instances that already existed through the requirement for the "cnf" key to stay the same over attestations.

As I said above in response to Torsten's point, using the key instead of an explicit claim means a single client instance could actually use multiple keys over time meaning the AS can't track the client instance across all of those interactions. The concern if we make an explicit claim in the client attestation JWT for identifying the client instance, is that implementations won't rotate this identifier over time thus meaning the instance would be tracked.

the forth option is to have long living client attestations, which in my opinion is no problem

Ironically if your goal is to reduce the ability of the AS to track the client instance over time, this option will in fact enable that as the attestation itself becomes the tracking vector.

Isn't the AS identifying the client also by the refresh token itself?

Agreed, the additional requirement of requiring the same client authentication method with the same key just means that obtaining the refresh token alone is not enough for another instance to be able to exercise the refresh token, it doesn't materially change the ability for the AS to track the client instance because as you highlight the refresh token itself creates the same possibility for correlation.

cobward commented 1 year ago

A: the wallet initially gets one client attestation and uses the cnf key over a longer period to bind a sequence of refresh tokens to it. -> similar to option 4?

I think this is basically my option 3.

Well the current language doesn't actually guarantee that the AS can track the client instance (which is a good thing IMO), as the instance can in many common cases, rotate the keys it uses in between fetching tokens.

a single client instance could actually use multiple keys over time meaning the AS can't track the client instance across all of those interactions

Unless there is a mechanism to issue a refresh token that I am not aware of, it is not possible to rotate keys according to the current language. The spec states:

Authorization servers issuing a refresh token in response to a token request using the "urn:ietf:params:oauth:client-assertion-type:jwt-client-attestation" client authentication method MUST bind the refresh token to the client instance, and NOT just the client as specified in section 6 {{RFC6749}}. To prove this binding, the client instance MUST authenticate itself to the authorization server when refreshing an access token using the "urn:ietf:params:oauth:client-assertion-type:jwt-client-attestation" authentication method. The client MUST also use the same key that was present in the "cnf" claim of the client attestation that was used for client authentication when the refresh token was issued.

This is what I mean by "This just makes explicit the tracking of client instances that already existed through the requirement for the "cnf" key to stay the same over attestations."

bc-pi commented 1 year ago

I don't think rotation of the key within the lifetime of a refresh token is something that needs to be accounted for. So my preference would be for option 3 (which is how it functionally is now but could be made more explicit in the text). Adding an explicit claim in the client attestation JWT which identifies the client instance, i.e. option 2, would be okay too. But I think it'd get complicated/confusing to describe it in the spec.

cobward commented 1 year ago

I don't think rotation of the key within the lifetime of a refresh token is something that needs to be accounted for.

By saying you can't rotate the key within the lifetime of a refresh token, I think this means that you cannot rotate the key without starting from scratch at the authorization endpoint. I just wanted to make sure that is what you meant?

bc-pi commented 1 year ago

I don't think rotation of the key within the lifetime of a refresh token is something that needs to be accounted for.

By saying you can't rotate the key within the lifetime of a refresh token, I think this means that you cannot rotate the key without starting from scratch at the authorization endpoint. I just wanted to make sure that is what you meant?

Basically yeah, I think so. Rotating the the key would mean you'd have to go back to the authorization endpoint. That seems acceptable/reasonable. Maybe it's too narrow of a view but it seems like if there's a reason to rotate that key then reauthorizing is probably needed or at least acceptable anyway.

cobward commented 1 year ago

if there's a reason to rotate that key then reauthorizing is probably needed

I'm not sure that's true. IMO authorization is more of a user-identification concern, the rotation of the key is a client-security concern.

Saying that, I think I agree that it's probably acceptable to say key-rotation isn't possible without returning to the authorization endpoint.

Given this I would suggest we add a sub-section to the Implementation Considerations section, something along the lines of this:

Rotation of confirmation key

This specification does not provide a mechanism to rotate the confirmation key identified in the Client Attestation JWT. If the client instance needs to use a new confirmation key for any reason, then it MUST begin the OAuth 2.0 flow from scratch.