diff options
| author | Michelle Tilley <michelle@michelletilley.net> | 2026-03-23 09:33:04 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-03-23 09:33:04 -0700 |
| commit | 7f06ba0ee93eebf4482a7eb5d5d25e9d8a072f9d (patch) | |
| tree | 20f214ce5d0ac08dc6eee0beb2c3c70128050a8e /crates/atuin-client/src/auth.rs | |
| parent | feat: hex init nu (#3330) (diff) | |
| download | atuin-7f06ba0ee93eebf4482a7eb5d5d25e9d8a072f9d.zip | |
chore: Refactor CLI auth flows and token storage (#3317)
This PR eplaces the binary `is_hub_sync()` auth routing with an explicit
`SyncAuth` enum that classifies the client's authentication state at
runtime. This fixes a class of bugs where CLI session tokens were
silently mis-stored or used with the wrong auth scheme during Hub
migration.
Diffstat (limited to 'crates/atuin-client/src/auth.rs')
| -rw-r--r-- | crates/atuin-client/src/auth.rs | 46 |
1 files changed, 37 insertions, 9 deletions
diff --git a/crates/atuin-client/src/auth.rs b/crates/atuin-client/src/auth.rs index 1e638c21..8ea4b8ab 100644 --- a/crates/atuin-client/src/auth.rs +++ b/crates/atuin-client/src/auth.rs @@ -18,7 +18,13 @@ static APP_USER_AGENT: &str = concat!("atuin/", env!("CARGO_PKG_VERSION")); /// Result of an auth operation that may require 2FA. pub enum AuthResponse { /// Operation succeeded; for login/register, contains the session token. - Success { session: String }, + /// `auth_type` indicates the kind of token: `Some("hub")` for Hub API + /// tokens (prefixed `atapi_`), `Some("cli")` for legacy CLI session + /// tokens. `None` when the server didn't include the field (old servers). + Success { + session: String, + auth_type: Option<String>, + }, /// Two-factor authentication is required; the caller should prompt for a /// TOTP code and retry with it. TwoFactorRequired, @@ -153,6 +159,7 @@ impl AuthClient for LegacyAuthClient { Ok(AuthResponse::Success { session: resp.session, + auth_type: resp.auth.or(Some("cli".into())), }) } @@ -160,6 +167,7 @@ impl AuthClient for LegacyAuthClient { let resp = crate::api_client::register(&self.address, username, email, password).await?; Ok(AuthResponse::Success { session: resp.session, + auth_type: resp.auth.or(Some("cli".into())), }) } @@ -273,6 +281,7 @@ impl AuthClient for HubAuthClient { let login: LoginResponse = resp.json().await?; return Ok(AuthResponse::Success { session: login.session, + auth_type: login.auth, }); } @@ -316,6 +325,7 @@ impl AuthClient for HubAuthClient { let reg: RegisterResponse = resp.json().await?; return Ok(AuthResponse::Success { session: reg.session, + auth_type: reg.auth, }); } @@ -332,10 +342,19 @@ impl AuthClient for HubAuthClient { new_password: &str, totp_code: Option<&str>, ) -> Result<MutateResponse> { - let hub_token = self - .hub_token - .as_deref() - .ok_or_else(|| eyre::eyre!("Not logged in to Hub"))?; + let hub_token = self.hub_token.as_deref().ok_or_else(|| { + eyre::eyre!( + "Not logged in to Atuin Hub. \ + Please run 'atuin login' to authenticate." + ) + })?; + + if !hub_token.starts_with("atapi_") { + bail!( + "Your Hub session token is invalid. \ + Please run 'atuin login' to re-authenticate with Atuin Hub." + ); + } ensure_crypto_provider(); let url = make_url(&self.address, "/api/v0/account/password")?; @@ -385,10 +404,19 @@ impl AuthClient for HubAuthClient { password: &str, totp_code: Option<&str>, ) -> Result<MutateResponse> { - let hub_token = self - .hub_token - .as_deref() - .ok_or_else(|| eyre::eyre!("Not logged in to Hub"))?; + let hub_token = self.hub_token.as_deref().ok_or_else(|| { + eyre::eyre!( + "Not logged in to Atuin Hub. \ + Please run 'atuin login' to authenticate." + ) + })?; + + if !hub_token.starts_with("atapi_") { + bail!( + "Your Hub session token is invalid. \ + Please run 'atuin login' to re-authenticate with Atuin Hub." + ); + } ensure_crypto_provider(); let url = make_url(&self.address, "/api/v0/account")?; |
