Skip to content

UI/fix renew token button#31807

Closed
lklivingstone wants to merge 7 commits into
hashicorp:mainfrom
lklivingstone:ui/fix-renew-token-button
Closed

UI/fix renew token button#31807
lklivingstone wants to merge 7 commits into
hashicorp:mainfrom
lklivingstone:ui/fix-renew-token-button

Conversation

@lklivingstone
Copy link
Copy Markdown
Contributor

Description

What does this PR do?

Fixes: #31315

Vault UI currently renders the “Renew token” button based solely on the token’s renewable property. However, this does not account for policy-level restrictions on auth/token/renew-self.

If a policy explicitly denies renew-self, the button is still displayed.

Root Cause

The UI checked only the token’s renewable flag and did not verify whether the token had update capability on auth/token/renew-self.

Fix

The UI now:

  • Calls /v1/sys/capabilities-self to evaluate permissions on auth/token/renew-self
  • Stores the evaluated capability in the auth service
  • Renders the Renew button only if:
    • The token is structurally renewable
    • The token has update capability on auth/token/renew-self

Additionally included tests for them

Screenshot:
Screenshot from 2026-02-26 22-11-43

Do let me know if this is not the desired UI behaviour.

TODO only if you're a HashiCorp employee

  • Backport Labels: If this fix needs to be backported, use the appropriate backport/ label that matches the desired release branch.
    • LTS: If this fixes a critical security vulnerability or severity 1 bug, it will also need to be backported to the current LTS versions of Vault. To ensure this, use all available enterprise labels.
  • Jira: If this change has an associated Jira, it's referenced either in the PR description, commit message, or branch name.
  • RFC: If this change has an associated RFC, please link it in the description.

PCI review checklist

  • I have documented a clear reason for, and description of, the change I am making.
  • If applicable, I've documented a plan to revert these changes if they require more than reverting the pull request.
  • If applicable, I've documented the impact of any changes to security controls.

Examples of changes to security controls include using new access control methods, adding or removing logging pipelines, etc.

@lklivingstone lklivingstone requested a review from a team as a code owner February 26, 2026 20:18
@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 26, 2026

@lklivingstone is attempting to deploy a commit to the HashiCorp Team on Vercel.

A member of the Team first needs to authorize it.

@dosubot dosubot Bot added the devex Developer Experience label Feb 26, 2026
Comment thread ui/app/services/auth.js Outdated
} catch (e) {
this.set('canRenewSelf', false);
}
},
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.

Thanks for opening this PR! We actually have a capabilities service to use for these sorts of requests, if we could use that instead. Here's an example. One reason is if the capabilities request fails we actually want to default to true rather than potentially gate an action a user can perform because of a failed capability check.

Can this request also be moved to the TokenExpireWarning component? If canRenewSelf is only set once upon login via this auth service, it will not get the updated value if policy changes are made upstream during this session. Requesting the data on demand ensures the latest state.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestion! I’ve updated the implementation to use the capabilities service and moved the check into the TokenExpireWarning component. The capability is now fetched on initialization via fetchRenewCapability() so it’s evaluated on demand rather than being set at login. It also defaults to true on failure (fail-open) to avoid unintentionally gating the action.

Let me know if you’d prefer the capability check to be triggered differently.

Comment on lines +24 to +31
async fetchRenewCapability() {
try {
const { canUpdate } = await this.capabilities.fetchPathCapabilities('auth/token/renew-self');
this.canRenewSelf = canUpdate;
} catch {
this.canRenewSelf = true;
}
}
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.

The service actually has a try...catch that handles this for you! So this can be simplified to

Suggested change
async fetchRenewCapability() {
try {
const { canUpdate } = await this.capabilities.fetchPathCapabilities('auth/token/renew-self');
this.canRenewSelf = canUpdate;
} catch {
this.canRenewSelf = true;
}
}
async fetchRenewCapability() {
const { canUpdate } = await this.capabilities.fetchPathCapabilities('auth/token/renew-self');
this.canRenewSelf = canUpdate;
}

assert.dom('[data-test-renew-token-button]').doesNotExist();
});

test('it shows Renew button if capability check fails (fail-open behavior)', async function (assert) {
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.

We can actually remove this test case since fetchPathCapabilities() will never return an error.

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.

Great test coverage! Thank you for adding 🎉

}

get canShowRenew() {
return this.auth?.authData?.renewable === true && this.canRenewSelf === true;
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.

Since these are both boolean types this could be

Suggested change
return this.auth?.authData?.renewable === true && this.canRenewSelf === true;
return this.auth?.authData?.renewable && this.canRenewSelf

Copy link
Copy Markdown
Contributor

@hellobontempo hellobontempo left a comment

Choose a reason for hiding this comment

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

Excellent work! Thanks for quick turnaround addressing the refactor requests. Just one more small cleanup item to remove the try...catch in the fetchRenewCapability request and then this is good to go. In the mean time, I will hand this off to my teammate who is on the sustaining rotation to assist with getting this merged.

@lklivingstone
Copy link
Copy Markdown
Contributor Author

Thanks @hellobontempo
Please let me know if this fixes everything.

@lklivingstone lklivingstone requested a review from a team as a code owner February 27, 2026 17:34
Copy link
Copy Markdown
Contributor

@hellobontempo hellobontempo left a comment

Choose a reason for hiding this comment

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

Looks great, thank you! This will have to be copied and merged into our private repo first and then ported over to the public Vault repo. The git history will be preserved and still credit you for this change 😄

Edit: I've just approved the workflows to run on this PR to confirm tests pass and that this doesn't introduce failures.

@hc-github-team-secure-vault-core
Copy link
Copy Markdown
Collaborator

Copy workflow completed!

From To Skipped Merge Commits Error
hashicorp/vault#31807 hashicorp/vault-enterprise#12637 0

@hc-github-team-secure-vault-core
Copy link
Copy Markdown
Collaborator

Copy pull request failed!

Origin Pull Request Copied Pull Request Commit SHA Error
#31807 https://github.com/hashicorp/vault-enterprise/pull/12637 https://github.com/hashicorp/vault-enterprise/commit/fe21d9acc13eceb24cd883ce90f91413c743cd80 PATCH https://api.github.com/repos/hashicorp/vault/issues/31315: 403 Resource not accessible by personal access token []
Closed Issues #31315
Error: PATCH https://api.github.com/repos/hashicorp/vault/issues/31315: 403 Resource not accessible by personal access token []

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

Labels

devex Developer Experience

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Vault UI shows "Renew token" button and warning even when renew-self is denied

4 participants