8000 DPoP: Refresh token created with DPoP can be refreshed without proof · Issue #36475 · keycloak/keycloak · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
DPoP: Refresh token created with DPoP can be refreshed without proof #36475
Closed
@ahus1

Description

@ahus1

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

oidc

Describe the bug

  • When I enable the DPoP feature, I can create a DPoP refresh token on any client, even if I don't enable "OAuth 2.0 DPoP Bound Access Tokens Enabled" for that client.
  • For a DPoP bound refresh token, I can then refresh it without DPoP proof for a non-DPoP bound refresh and access token as long as "OAuth 2.0 DPoP Bound Access Tokens Enabled" is not enabled, even though the spec says both the access and the refresh token should be bound to the DPoP key.

From a security point of view, this might be surprising: Assuminging someone enabled the DPoP feature, and didn't switch on the flag on the client level and then issued themselves a DPoP and a refresh token created with DPoP. Now they can still use the refresh token without a DPoP proof, which is against the spec.

Version

26.1

Regression

  • The issue is a regression

Expected behavior

  • Allow clients to opt in to use DPoP if the option is off, as it allows experimenting with DPoP and gradually rolling out DPoP
  • Option in the client config should be named "Require Demonstrating Proof of Possession (DPoP) header in token requests" (similar to Okta's configuation in https://developer.okta.com/docs/guides/dpop/nonoktaresourceserver/main/) or "Only issue DPoP bound access and refresh tokens" (which would take the perspective of Keycloak, and the help could reference the DPoP spec and the header requirements)
  • If a refresh token has been issued with DPoP, the next refresh needs to use enforce DPoP

Actual behavior

Already works as expected:

  • Allow clients to opt in to use DPoP if the option is off, as it allows experimenting with DPoP and gradually rolling out DPoP

Actual behavior (not yet as expected):

  • Option in the client config is named "OAuth 2.0 DPoP Bound Access Tokens Enabled"
  • If a refresh token has been issued with DPoP, the next refresh DOES NOT enforce DPoP, and the generated access tokens and refresh tokens are not bound to DPoP

How to Reproduce?

  • Start Keycloak with the DPoP feature enabled
  • Create a public client that is not enforcing DPoP
  • Use a DPoP client (like https://github.com/panva/openid-client) to create a DPoP bound access and refresh token
  • Then refresh the token without a DPoP headers -> this works, and the access and refresh tokens issued can be used without a DPoP header

Anything else?

As discussed on the Keycloak security mailing list, this is considered a hardening issue.

Comment from @mposolda:

  • Agree with your suggestion to rename the client option to something like "Enforce/require" instead of "Enable" . IMO we can rename the labels in the UI and java methods on OIDCAdvancedConfigWrapper, but still keep the name of the client attribute (to avoid issues with migration/backwards compatibility)
  • IMO when the DPoP feature is enabled, we can still allow clients without enforcing DPoP (so with the switch above OFF) to issue DPoP refresh tokens and access tokens. In that case, when DPoP tokens were used, it can be ideal if we also enforce DPoP at token verification. We can take a look at the claims in the refresh token (or access token) and if DPoP claims are present, we should verify DPoP. This will allow clients to migrate/test DPoP without enforcing it, which is possibly aligned with your suggestion? It can be also good to doublecheck the specification in this regards. I am just not 100% sure if we can reliably detect DPoP used by claims in the tokens as standard claims like "cnf" are not DPoP specific. For access tokens, we probably can due the token type "dpop", but not sure about refresh tokens. Maybe if needed, we can add some custom claim into tokens to detect that it is DPoP refresh token, not sure....

Comment from me:

  • For the access tokens, we already have have in the tokens "typ" set to "DPoP". I didn't find that in the standard
  • The refresh tokens are AFAIK opaque, so it might be ok to use the "cnf" if we don't use it in other places.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0