Skip to content

[PM-31877] Migrate LoginMethod+Tokens to Setting#973

Merged
Hinton merged 5 commits into
mainfrom
rehydration/login-tokens
Apr 27, 2026
Merged

[PM-31877] Migrate LoginMethod+Tokens to Setting#973
Hinton merged 5 commits into
mainfrom
rehydration/login-tokens

Conversation

@Hinton
Copy link
Copy Markdown
Member

@Hinton Hinton commented Apr 20, 2026

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-31877

📔 Objective

Removes the in-memory login_method: Arc<RwLock<Option<Arc<LoginMethod>>>> field from InternalClient and the duplicated token fields (access_token, expires_on, refresh_token) from PasswordManagerTokenHandlerInner, replacing both with the Setting<T> surface already registered in persisted_state.rs (USER_LOGIN_METHOD, AUTHENTICATION_TOKENS). The state registry is now the single source of truth for PM user login method and tokens, which also makes them persist across process restarts once a durable database is wired up.

Key changes:

  • Setting<T> now derives Clone (setting.rs) so token handlers can cache their handles cheaply.
  • TokenHandler::initialize_middleware now takes &StateRegistry instead of the old Arc<RwLock<Option<Arc<LoginMethod>>>>. A new default async fn set_sm_login_method(&self, _: ServiceAccountLoginMethod) hook is added for Secrets Manager (auth_tokens.rs).
  • InternalClient::get_login_method / set_login_method now dispatch through the state registry for PM user logins and through the token handler for SM logins. get_kdf routes through get_login_method. The secret-leaking debug!(?login_method, …) log was dropped (internal.rs).
  • ClientBuilder::build() drops the local login_method RwLock and passes the hoisted state_registry into initialize_middleware (builder.rs).
  • PasswordManagerTokenHandler inner struct now holds Option<Setting<AuthenticationTokens>> and Option<Setting<UserLoginMethod>> plus identity_config; set_tokens / get_token read & write through the settings (password_manager_token_handler.rs).
  • SecretsManagerTokenHandler keeps its login method in memory as Option<Arc<ServiceAccountLoginMethod>> (SM key material deliberately doesn't Clone), populated via set_sm_login_method (secrets_manager_token_handler.rs).
  • bitwarden-auth gains a direct bitwarden-state dependency.

🚨 Breaking Changes

TokenHandler::initialize_middleware changed signature:

// before
fn initialize_middleware(
    &self,
    login_method: Arc<RwLock<Option<Arc<LoginMethod>>>>,
    identity_config: bitwarden_api_base::Configuration,
    key_store: KeyStore<KeySlotIds>,
) -> Arc<dyn reqwest_middleware::Middleware>;

// after
fn initialize_middleware(
    &self,
    state_registry: &StateRegistry,
    identity_config: bitwarden_api_base::Configuration,
    key_store: KeyStore<KeySlotIds>,
) -> Arc<dyn reqwest_middleware::Middleware>;

Any out-of-tree TokenHandler implementers must update their signature. Migration path: replace the Arc<RwLock<Option<Arc<LoginMethod>>>> parameter with &StateRegistry and, if the handler previously read the user login method through the lock, read it via state_registry.setting(USER_LOGIN_METHOD). SM-style handlers that need a ServiceAccountLoginMethod should override the new set_sm_login_method default and store it in-memory. All in-tree callers (the built-in NoopTokenHandler, ClientManagedTokenHandler, PasswordManagerTokenHandler, SecretsManagerTokenHandler, and ClientBuilder::build()) are updated in this PR.

Replace InternalClient.login_method with state registry settings

Removes the in-memory login_method Arc<RwLock> field from InternalClient
and the duplicated token fields from PasswordManagerTokenHandler, routing
both through the USER_LOGIN_METHOD and AUTHENTICATION_TOKENS settings
already registered in persisted_state.

TokenHandler::initialize_middleware now takes &StateRegistry instead of
the shared login_method lock, and gains a set_sm_login_method hook so
SecretsManagerTokenHandler can keep its login method in memory (SM key
material deliberately does not implement Clone).
@Hinton Hinton requested review from a team as code owners April 20, 2026 10:09
@Hinton Hinton requested review from coroiu and ike-kottlowski April 20, 2026 10:09
login_method: Option<Arc<RwLock<Option<Arc<LoginMethod>>>>>,
// These are defined as optional as they are filled in when instantiating the middleware.
tokens: Option<Setting<AuthenticationTokens>>,
login_method: Option<Setting<UserLoginMethod>>,
Copy link
Copy Markdown
Member Author

@Hinton Hinton Apr 20, 2026

Choose a reason for hiding this comment

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

@dani-garcia Would it be more appropriate to make these required? Since they are Settings Keys, the absent indicates we have no state which feels like a fatal error for a token handler.

We would have to change how the middleware is wired up though which might be tricky.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Hinton Yeah the reason we had to do it like that is that the token handler needed access to some of the client internals, which means we had to do this two-step initialization.

With the rehydration work we're moving towards letting the Client receive the StateRegistry directly rather than creating it internally, so my thinking is that once we're done with rehydration we can change the API to be something like this:

let registry = StateRegistry::new(...);
let handler = PMTokenHandler::new(registry); // the handler can now have all the fields initialized straight away
let client = Client::new(registry, handler); // Client now doesn't need to pass the registry to initialize_middleware, as it's already constructed.

I didn't want to include these changes on this ticket as it's a bigger lift.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 20, 2026

Logo
Checkmarx One – Scan Summary & Details639c4943-5293-47a8-b5b0-19f383d27e46

Great job! No new security vulnerabilities introduced in this pull request

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 20, 2026

🔍 SDK Breaking Change Detection Results

SDK Version: rehydration/login-tokens (2ffb938)
Completed: 2026-04-20 14:11:36 UTC
Total Time: 278s

Client Status Details
typescript ✅ No breaking changes detected TypeScript compilation passed with new SDK version - View Details

Breaking change detection completed. View SDK workflow

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 20, 2026

Codecov Report

❌ Patch coverage is 91.86047% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.21%. Comparing base (96753ee) to head (d2c1636).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
.../token_management/secrets_manager_token_handler.rs 82.60% 4 Missing ⚠️
crates/bitwarden-core/src/client/internal.rs 88.88% 2 Missing ⚠️
crates/bitwarden-core/src/auth/auth_tokens.rs 66.66% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #973   +/-   ##
=======================================
  Coverage   84.20%   84.21%           
=======================================
  Files         390      390           
  Lines       47882    47904   +22     
=======================================
+ Hits        40319    40342   +23     
+ Misses       7563     7562    -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sonarqubecloud
Copy link
Copy Markdown

coroiu
coroiu previously approved these changes Apr 21, 2026
…tion/login-tokens

# Conflicts:
#	crates/bitwarden-core/src/client/builder.rs
#	crates/bitwarden-core/src/client/internal.rs
@Hinton Hinton requested a review from coroiu April 24, 2026 09:53
@Hinton Hinton changed the title Migrate LoginMethod+Tokens to Setting [PM-31877] Migrate LoginMethod+Tokens to Setting Apr 24, 2026
@Hinton Hinton merged commit b203fec into main Apr 27, 2026
58 of 62 checks passed
@Hinton Hinton deleted the rehydration/login-tokens branch April 27, 2026 11:15
eliykat pushed a commit that referenced this pull request Apr 28, 2026
Removes the in-memory `login_method:
Arc<RwLock<Option<Arc<LoginMethod>>>>` field from `InternalClient` and
the duplicated token fields (`access_token`, `expires_on`,
`refresh_token`) from `PasswordManagerTokenHandlerInner`, replacing both
with the `Setting<T>` surface already registered in
[persisted_state.rs](crates/bitwarden-core/src/client/persisted_state.rs)
(`USER_LOGIN_METHOD`, `AUTHENTICATION_TOKENS`). The state registry is
now the single source of truth for PM user login method and tokens,
which also makes them persist across process restarts once a durable
database is wired up.

Key changes:

- `Setting<T>` now derives `Clone`
([setting.rs](crates/bitwarden-state/src/settings/setting.rs)) so token
handlers can cache their handles cheaply.
- `TokenHandler::initialize_middleware` now takes `&StateRegistry`
instead of the old `Arc<RwLock<Option<Arc<LoginMethod>>>>`. A new
default `async fn set_sm_login_method(&self, _:
ServiceAccountLoginMethod)` hook is added for Secrets Manager
([auth_tokens.rs](crates/bitwarden-core/src/auth/auth_tokens.rs)).
- `InternalClient::get_login_method` / `set_login_method` now dispatch
through the state registry for PM user logins and through the token
handler for SM logins. `get_kdf` routes through `get_login_method`. The
secret-leaking `debug!(?login_method, …)` log was dropped
([internal.rs](crates/bitwarden-core/src/client/internal.rs)).
- `ClientBuilder::build()` drops the local `login_method` `RwLock` and
passes the hoisted `state_registry` into `initialize_middleware`
([builder.rs](crates/bitwarden-core/src/client/builder.rs)).
- `PasswordManagerTokenHandler` inner struct now holds
`Option<Setting<AuthenticationTokens>>` and
`Option<Setting<UserLoginMethod>>` plus `identity_config`; `set_tokens`
/ `get_token` read & write through the settings
([password_manager_token_handler.rs](crates/bitwarden-auth/src/token_management/password_manager_token_handler.rs)).
- `SecretsManagerTokenHandler` keeps its login method in memory as
`Option<Arc<ServiceAccountLoginMethod>>` (SM key material deliberately
doesn't `Clone`), populated via `set_sm_login_method`
([secrets_manager_token_handler.rs](crates/bitwarden-auth/src/token_management/secrets_manager_token_handler.rs)).
- `bitwarden-auth` gains a direct `bitwarden-state` dependency.

## 🚨 Breaking Changes

`TokenHandler::initialize_middleware` changed signature:

```rust
// before
fn initialize_middleware(
    &self,
    login_method: Arc<RwLock<Option<Arc<LoginMethod>>>>,
    identity_config: bitwarden_api_base::Configuration,
    key_store: KeyStore<KeySlotIds>,
) -> Arc<dyn reqwest_middleware::Middleware>;

// after
fn initialize_middleware(
    &self,
    state_registry: &StateRegistry,
    identity_config: bitwarden_api_base::Configuration,
    key_store: KeyStore<KeySlotIds>,
) -> Arc<dyn reqwest_middleware::Middleware>;
```

Any out-of-tree `TokenHandler` implementers must update their signature.
Migration path: replace the `Arc<RwLock<Option<Arc<LoginMethod>>>>`
parameter with `&StateRegistry` and, if the handler previously read the
user login method through the lock, read it via
`state_registry.setting(USER_LOGIN_METHOD)`. SM-style handlers that need
a `ServiceAccountLoginMethod` should override the new
`set_sm_login_method` default and store it in-memory. All in-tree
callers (the built-in `NoopTokenHandler`, `ClientManagedTokenHandler`,
`PasswordManagerTokenHandler`, `SecretsManagerTokenHandler`, and
`ClientBuilder::build()`) are updated in this PR.
addisonbeck added a commit that referenced this pull request May 15, 2026
## 🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-31879

## 📔 Objective

Adds `save_to_state` and `load_from_state` to `Client` in
`bitwarden-core`, enabling the CLI to reconstruct a locked client from a
persistent `StateRegistry` without re-authenticating.

`PasswordManagerClient` exposes thin delegation wrappers for
`load_from_state` and `save_to_state` for callers working at the PM
layer.

Some supporting types were added in
`crates/bitwarden-core/src/client/rehydration.rs`: `RehydrationError`
and `SaveStateData`.

All foundation (`StateRegistry`, setting keys,
`ClientBuilder::with_state`, crypto persistence) was committed to main
in prior PRs (#871, #917, #906, #912, #957, #965, #983, #973). This PR
adds the rehydration entry points on top of that infrastructure.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants