Skip to content

Fix refresh token grant failing after client secret rotation (ADD) - #4052

Merged
duanemay merged 1 commit into
developfrom
fix/4047-refresh-token-secret-rotation
Aug 25, 2026
Merged

Fix refresh token grant failing after client secret rotation (ADD)#4052
duanemay merged 1 commit into
developfrom
fix/4047-refresh-token-secret-rotation

Conversation

@duanemay

Copy link
Copy Markdown
Member

Summary

  • Fixes Refresh token grant fails with "revocable signature mismatch" after adding a new client secret #4047: after adding a second client secret via changeMode=ADD (the multi-secret, zero-downtime rotation feature), grant_type=refresh_token calls failed with invalid_token: revocable signature mismatch for any refresh token issued before the rotation — regardless of which secret was used to authenticate.
  • Root cause: UaaTokenServices.refreshAccessToken() ran a second, redundant revocation-signature check (throwIfInvalidRevocationHashSignature) immediately after the correct check (tokenValidationService.validateToken(...), which already loops over every currently valid client secret) had already passed. The redundant check compared against a single, hardcoded "newest secret" only, so it rejected tokens signed against an older still-valid secret.
  • Fix: remove the redundant, single-secret check and its now-unused helper — the multi-secret-aware check performed a few lines earlier already covers this claim correctly.

Test plan

  • Added refreshTokenIssuedBeforeAddClientSecretStillWorksAfterAdd in TokenMvcMockTests.java: issues a password-grant refresh token while the client has one secret, adds a second secret via changeMode=ADD, then confirms the original refresh token still redeems successfully.
  • Confirmed the new test fails against the pre-fix code and passes with the fix applied.
  • Ran the full TokenMvcMockTests suite and the org.cloudfoundry.identity.uaa.oauth.* package in the server module — all passing.
  • Manually reproduced the original bug end-to-end against a local UAA instance using uaa-cli, and confirmed the fix resolves it.

🤖 Generated with Claude Code

refreshAccessToken() ran a second, redundant revocation-signature check
that only compared against a single, hardcoded "newest secret" instead
of every currently valid client secret. The primary check performed a
few lines earlier (tokenValidationService.validateToken) already loops
over all client secrets correctly, so any refresh token issued while a
client had only one secret was wrongly rejected with "revocable
signature mismatch" as soon as a second secret was added via
changeMode=ADD, defeating zero-downtime secret rotation.

Fixes #4047

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 24, 2026 19:27
@duanemay
duanemay requested review from fhanik and strehle August 24, 2026 19:29

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

This pull request fixes a refresh-token validation bug triggered by zero-downtime client secret rotation (changeMode=ADD) by removing a redundant, single-secret revocation-signature check that incorrectly rejected refresh tokens signed with an older (but still valid) client secret.

Changes:

  • Removed the redundant throwIfInvalidRevocationHashSignature(...) check from UaaTokenServices.refreshAccessToken(...) (multi-secret validation is already correctly handled by TokenValidationService.validateToken(...)).
  • Deleted the now-unused helper method.
  • Added a regression test that issues a refresh token pre-rotation, adds a second secret, and verifies the original refresh token can still be redeemed.

Reviewed changes

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

File Description
uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenMvcMockTests.java Adds a regression test covering refresh-token redemption after ADD secret rotation.
server/src/main/java/org/cloudfoundry/identity/uaa/oauth/UaaTokenServices.java Removes the redundant single-secret revocation-signature validation that breaks multi-secret rotation.

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

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 2 out of 2 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 2 out of 2 changed files in this pull request and generated 1 comment.

Comment on lines +3220 to +3228
// the refresh token issued before the rotation must still be redeemable with the original secret
mockMvc.perform(post("/oauth/token")
.accept(MediaType.APPLICATION_JSON_VALUE)
.with(httpBasic(clientId, SECRET))
.param("grant_type", "refresh_token")
.param("client_id", clientId)
.param("client_secret", SECRET)
.param("refresh_token", refreshToken))
.andExpect(status().isOk());
@github-project-automation github-project-automation Bot moved this from Inbox to Pending Merge | Prioritized in Foundational Infrastructure Working Group Aug 25, 2026
@duanemay
duanemay merged commit 71d2397 into develop Aug 25, 2026
30 of 31 checks passed
@duanemay
duanemay deleted the fix/4047-refresh-token-secret-rotation branch August 25, 2026 13:52
@github-project-automation github-project-automation Bot moved this from Pending Merge | Prioritized to Done in Foundational Infrastructure Working Group Aug 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

Refresh token grant fails with "revocable signature mismatch" after adding a new client secret

3 participants