8000 Allow configuring "Revoke Refresh Token" per client (#16422) by thomasdarimont · Pull Request #51798 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content

Allow configuring "Revoke Refresh Token" per client (#16422) - #51798

Open
thomasdarimont wants to merge 16 commits into
keycloak:mainfrom
thomasdarimont:issue/gh-16422-oidc-allow-revoke-refresh-token-client-level
Open

thomasdarimont wants to merge 16 commits into
keycloak:mainfrom
thomasdarimont:issue/gh-16422-oidc-allow-revoke-refresh-token-client-level

Conversation

@thomasdarimont
@thomasdarimont thomasdarimont commented Aug 18, 2026 •
Copy link
Copy Markdown
Contributor

Add client-level overrides for the realm settings "Revoke Refresh Token" and "Refresh Token Max Reuse" via the client attributes revoke.refresh.token and refresh.token.max.reuse. When unset, the realm setting is used. The overrides are exposed in the client's Advanced settings in the admin console and validated on client update.

This also adapts the VCIRefreshTokenProvider to honor the client level setting.

Fixes #16422

Copilot AI balanced review requested due to automatic review settings August 18, 2026 14:18
@thomasdarimont
thomasdarimont requested review from a team as code owners August 18, 2026 14:19
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds per-client overrides for refresh-token rotation and maximum reuse while preserving realm defaults.

Changes:

  • Implements client-level token revocation behavior and validation.
  • Adds Admin UI controls and integration coverage.
  • Documents the settings and release impact.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
themes/.../messages_en.properties Adds validation message.
tests/.../RefreshTokenRevokeClientOverrideTest.java Tests override behavior.
DefaultClientValidationProvider.java Validates maximum reuse.
Messages.java Defines validation key.
TokenManager.java Resolves effective client settings.
RefreshTokenIntrospectionProvider.java Applies override during introspection.
AbstractRefreshTokenProvider.java Applies override during refresh.
OIDCAdvancedConfigWrapper.java Exposes override accessors.
OIDCConfigAttributes.java Defines client attributes.
AdvancedTab.tsx Includes fields in reset handling.
RefreshTokenRevocation.tsx Adds configuration controls.
AdvancedSettings.tsx Integrates the controls.
keycloak.v2/.../messages_en.properties Adds UI labels and help.
timeouts.adoc Documents realm/client relationship.
con-advanced-settings.adoc Documents client options.
26_8_0.adoc Adds release note.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@thomasdarimont
thomasdarimont commented Aug 18, 2026 •
Copy link
Copy Markdown
Contributor Author

Revoke refresh token Disabled in Realm

Edit: revised the UI according to Eriks suggestions: #51798 (comment)

Client level Advanced Setting defaults to Realm setting
image

Tooltip:
image

image

Explicitly disabled:
image

Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings August 19, 2026 12:25
@thomasdarimont
thomasdarimont force-pushed the issue/gh-16422-oidc-allow-revoke-refresh-token-client-level branch from 9932d04 to 4322164 Compare August 19, 2026 12:25
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.

Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.

Suppressed comments (4)

services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java:222

  • Boolean.parseBoolean turns every malformed value into false, so a pre-existing client attribute (attributes were previously unrestricted) can silently disable refresh-token rotation even when the realm enables it. Parse only the two accepted literals and treat any other value as no override.
        return StringUtil.isBlank(value) ? null : Boolean.parseBoolean(value.trim());

services/src/main/java/org/keycloak/validation/DefaultClientValidationProvider.java:247

  • This validation is applied to every client protocol, although these attributes are OIDC-only. Consequently, a SAML client that already uses either arbitrary attribute name with another value can no longer be updated; gate this validator on OIDCLoginProtocol.LOGIN_PROTOCOL, as the nearby OIDC-only ACR validation does.
    private void validateRefreshTokenRevocation(ValidationContext<ClientModel> context) {
        ClientModel client = context.getObjectToValidate();
        if (client == null) return;

docs/documentation/server_admin/topics/clients/oidc/con-advanced-settings.adoc:133

  • This states that enabling the override always revokes a refresh token when used, but a positive Refresh Token Max Reuse explicitly permits reuse. Describe rotation as subject to the effective max-reuse setting so administrators are not misled about the resulting policy.
|The value overrides the realm option <<_revoke-refresh-token,Revoke Refresh Token>> for this client. When set to *Enabled*, refresh tokens issued to this client are revoked when used, regardless of the realm setting. When set to *Disabled*, refresh tokens issued to this client can be reused, even if revocation is enabled for the realm. When not set, the realm setting is used.

services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java:245

  • A negative integer is returned as an effective override even though the new contract requires a non-negative value. A pre-existing attribute with such a value makes currentCount > -1 reject even the first refresh; invalid negative values should fall back to the realm setting just like non-integers.
            return Integer.parseInt(value.trim());
        } catch (NumberFormatException e) {
            return null;

@remcojansen remcojansen left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Tested and works as documented:

  • When realm setting is disabled, enabling revocation on a client takes precedence
  • When realm setting is enabled, disabling revocation on a client takes precedence
  • Max number of re-use takes precedence over realm configuration

Code looks good to me.

Copilot AI review requested due to automatic review settings August 24, 2026 14:50
@thomasdarimont
thomasdarimont force-pushed the issue/gh-16422-oidc-allow-revoke-refresh-token-client-level branch from 1a5b736 to ad09076 Compare August 24, 2026 14:50
@thomasdarimont
Copy link
Copy Markdown
Contributor Author

Rebased on current main to retrigger ci

Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.

Copilot AI review requested due to automatic review settings August 24, 2026 16:00
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 6 comments.

Add client-level overrides for the realm settings "Revoke Refresh Token"
and "Refresh Token Max Reuse" via the client attributes
revoke.refresh.token and refresh.token.max.reuse. When unset, the realm
setting is used. The overrides are exposed in the client's Advanced
settings in the admin console and validated on client update.

Fixes keycloak#16422

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
Also reject malformed revoke.refresh.token values in client validation.

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
Reverting the Advanced settings section wrote the raw JSON string of the
acr.loa.map attribute back into the form, while the form edits it as
key/value pairs. Once a client had been saved through this section
(which persists acr.loa.map as "{}"), clicking Revert and then Save
failed with "acr.loa.map.filter is not a function" and no request was
sent. Convert the attribute to key/value pairs when resetting, matching
how the client details form loads it.

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
- parse revoke.refresh.token strictly; malformed values inherit the realm setting
- add dedicated message key for the revoke.refresh.token validation error
- docs: grammar fix

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
…n revocation

- admin UI: only explicit "true"/"false" override the realm setting, matching the server
- treat negative refresh.token.max.reuse values as "inherit" at runtime

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
… revocation

- Normalize the revoke.refresh.token attribute to its canonical form when
loading it into the client form, so case/whitespace variants accepted by
the server are shown as the matching select option
- Cover an API-created non-canonical value in the advanced tab test
- Clarify in the docs that enabling the override rotates refresh tokens
and limits reuse according to Refresh Token Max Reuse

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
…n layout

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
…etup

A malformed or negative refresh.token.max.reuse attribute (e.g. from an
import) stayed in the form state and was resubmitted on every save of the
Advanced tab, which the server validation now rejects while the field
itself may be hidden. Normalize such values to "inherit" when the form is
set up, in line with revoke.refresh.token, and make both normalizers
tolerate the numeric form values stored by the NumberInput.

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
…lient form normalizer

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
- Canonicalize refresh token max reuse in the admin UI the way the server
parses it (Integer.parseInt), so accepted spellings such as "+1" or "007"
are not turned into inheritance when the client is opened and saved.
- Remove the UI test block that seeded a malformed max reuse through the
admin API, which the server validation rejects; the fallback is covered
by the normalizer unit test.
- Fix the docs: with "Revoke Refresh Token" disabled for a client the
realm max reuse value is not used, reuse is unlimited.

Related to keycloak#1642

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
…oken provider

OID4VCIRefreshTokenProvider kept reading the realm-level "revoke refresh
token" and "max reuse" settings, while the base class already applied the
client-level overrides for the refresh lock. Use the effective settings via
TokenManager in the OID4VCI rotation check as well, and add a test that
rotates and replays an OID4VCI refresh token with the override enabled for
the client and disabled for the realm.

Related to keycloak#16422

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
Copilot AI balanced review requested due to automatic review settings November 3, 2026 21:26
@thomasdarimont
thomasdarimont force-pushed the issue/gh-16422-oidc-allow-revoke-refresh-token-client-level branch from fd2d628 to 89867c4 Compare November 3, 2026 21:26
@thomasdarimont
Copy link
Copy Markdown
Contributor Author

Rebased on current main.

…t to 27

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
@thomasdarimont
Copy link
Copy Markdown
Contributor Author

I moved the release note to 27_0_0.adoc

Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

With realm revocation disabled, the client override leaves /revoke unsynchronized with refresh rotation, while the admin UI test uses the wrong realm, causing assertion and update failures.

2 open issues

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings November 3, 2026 21:33
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

When only the client override enables revocation, revocation bypasses the refresh lock and can race on session state, while the persistence test queries the wrong realm and fails its first assertion.

2 open issues

Review effort: Balanced

…nt lock

The serialization lock taken by /revoke only consulted the realm setting,
so a client that enables revocation through its override could have its
client session read and removed concurrently with a rotating refresh.
Resolve the effective setting via the authenticated client instead.

Also pass the test realm to the admin client helpers in the advanced tab
Playwright test, which otherwise looked the client up in master.

Fixes keycloak#16422

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
Copilot AI balanced review requested due to automatic review settings November 3, 2026 23:46
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Human assessment is needed because client-side normalization differs from server parsing rules and can silently change revocation or max-reuse settings when imported clients are opened and saved.

No open issues 🎉

2 resolved since last review

Review effort: Balanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow configuring "Revoke refresh token" (refresh token rotation) per client (in addition to per realm)

5 participants

0