[PR #6433] Make JWT token refresh optional #3781

Open
opened 2026-03-03 10:21:30 +03:00 by kerem · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/dani-garcia/vaultwarden/pull/6433
Author: @Momi-V
Created: 11/3/2025
Status: 🔄 Open

Base: mainHead: auth-renew


📝 Commits (10+)

  • 1f2c2cf Add option to disable refresh token renewal
  • 830d395 Add logic to make token renew optional
  • bd06258 Add Clone trait to TokenWrapper enum
  • cc90430 Reuse original claims struct for refresh token renewal
  • 19cce48 pass original refresh_claim into renewal function
  • b4f5581 Pass correct type
  • 5a90dbc Add optional parameter existing_refresh_claims to AuthTokens
  • 2515d46 Add optional parameter existing_refresh_claims to AuthTokens
  • 99f061d Add Clone trait to RefreshJwtClaims struct
  • 78bd39e Clone refresh_claims.sub

📊 Changes

4 files changed (+28 additions, -10 deletions)

View changed files

📝 src/api/identity.rs (+1 -1)
📝 src/auth.rs (+21 -7)
📝 src/config.rs (+4 -0)
📝 src/sso.rs (+2 -2)

📄 Description

This implements a config option disable_refresh_token_renewal, that doesn't do refresh token renewal unless a full auth is performed.

Goal:
Only renew the JWT token that allows PIN unlock, bypassing 2FA, etc. if a "full authentication" is performed. This makes things like "require 2FA once every 30/90 days" possible

Rationale:
Currently it's only possible to require periodic reauthentication by setting clients to log-out instead of lock. This is inconvenient since it breaks PIN, offline functionality and requires full reauthentication for every unlock. The current lock behavior on the other hand only requires reauth if a client hasn't connected in 30/90 days, since the token is renewed even on a reduced login that used that same token. This means it effectively never expires, if the client just uses it's existing token more than once a month.

Logic:
If the new option is false the old logic is used (always renew the token). If a normal Password/SSO login is performed the old logic is used.
If the option is true the JWT isn't renewed in the _refresh_login code path, leaving it to expire and force a full auth after 30/90 days

Code:
Having refresh_claims.sub.clone() and Some(&refresh_claims) in the same call isn't amazing, but seems like the simplest way to implement this logic without a refactor to overload AuthToken::new into 2 separate, yet almost identical functions.

Progress:
Compiled and running, but not yet tested to actually behave as expected (currently ongoing).

Feedback welcome


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/dani-garcia/vaultwarden/pull/6433 **Author:** [@Momi-V](https://github.com/Momi-V) **Created:** 11/3/2025 **Status:** 🔄 Open **Base:** `main` ← **Head:** `auth-renew` --- ### 📝 Commits (10+) - [`1f2c2cf`](https://github.com/dani-garcia/vaultwarden/commit/1f2c2cf63d26b4503ab9ba81a1c82e56a1a1cdca) Add option to disable refresh token renewal - [`830d395`](https://github.com/dani-garcia/vaultwarden/commit/830d395c5d76d81db7084baf7f73b02979f662b9) Add logic to make token renew optional - [`bd06258`](https://github.com/dani-garcia/vaultwarden/commit/bd06258240b4ad79910b8139abd7c6fed2c013d2) Add Clone trait to TokenWrapper enum - [`cc90430`](https://github.com/dani-garcia/vaultwarden/commit/cc9043005746413728a94602b853479c95f37126) Reuse original claims struct for refresh token renewal - [`19cce48`](https://github.com/dani-garcia/vaultwarden/commit/19cce482bcb5e9d780936f3f5c46c39c93409341) pass original refresh_claim into renewal function - [`b4f5581`](https://github.com/dani-garcia/vaultwarden/commit/b4f5581b5fe8b207682d95917ff4538be573033b) Pass correct type - [`5a90dbc`](https://github.com/dani-garcia/vaultwarden/commit/5a90dbc369d70b9a6da637fc58b4c43a529ff1ed) Add optional parameter existing_refresh_claims to AuthTokens - [`2515d46`](https://github.com/dani-garcia/vaultwarden/commit/2515d46a7fcc49cbb0114ecba6195a5a0ede13e9) Add optional parameter existing_refresh_claims to AuthTokens - [`99f061d`](https://github.com/dani-garcia/vaultwarden/commit/99f061d5f76aac1d7651f4ea7ac1d22605a89cb6) Add Clone trait to RefreshJwtClaims struct - [`78bd39e`](https://github.com/dani-garcia/vaultwarden/commit/78bd39ef25c02874c791e71f311b22f0c6c49180) Clone refresh_claims.sub ### 📊 Changes **4 files changed** (+28 additions, -10 deletions) <details> <summary>View changed files</summary> 📝 `src/api/identity.rs` (+1 -1) 📝 `src/auth.rs` (+21 -7) 📝 `src/config.rs` (+4 -0) 📝 `src/sso.rs` (+2 -2) </details> ### 📄 Description This implements a config option `disable_refresh_token_renewal`, that doesn't do refresh token renewal unless a full auth is performed. **Goal:** Only renew the JWT token that allows PIN unlock, bypassing 2FA, etc. if a "full authentication" is performed. This makes things like "require 2FA once every 30/90 days" possible **Rationale:** Currently it's only possible to require periodic reauthentication by setting clients to log-out instead of lock. This is inconvenient since it breaks PIN, offline functionality and requires full reauthentication for _every_ unlock. The current lock behavior on the other hand _only_ requires reauth if a client hasn't connected in 30/90 days, since the token is renewed even on a reduced login that used that same token. This means it effectively never expires, if the client just uses it's existing token more than once a month. **Logic:** If the new option is `false` the old logic is used (always renew the token). If a normal Password/SSO login is performed the old logic is used. If the option is `true` the JWT isn't renewed in the `_refresh_login` code path, leaving it to expire and force a full auth after 30/90 days **Code:** Having `refresh_claims.sub.clone()` and `Some(&refresh_claims)` in the same call isn't amazing, but seems like the simplest way to implement this logic without a refactor to overload `AuthToken::new` into 2 separate, yet almost identical functions. **Progress:** Compiled and running, but not yet tested to actually behave as expected (currently ongoing). Feedback welcome --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vaultwarden#3781
No description provided.