Show organization name after authenticating (#15823)

## Summary

Shows the name of the logged-in organization on success, rather than
repeating the URL.
This commit is contained in:
Charlie Marsh 2025-09-16 09:46:43 -04:00 committed by GitHub
parent 663053b0d1
commit ac52201626
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 32 additions and 17 deletions

View File

@ -10,7 +10,9 @@ pub use credentials::{Credentials, Username};
pub use index::{AuthPolicy, Index, Indexes}; pub use index::{AuthPolicy, Index, Indexes};
pub use keyring::KeyringProvider; pub use keyring::KeyringProvider;
pub use middleware::AuthMiddleware; pub use middleware::AuthMiddleware;
pub use pyx::{DEFAULT_TOLERANCE_SECS, PyxOAuthTokens, PyxTokenStore, PyxTokens, TokenStoreError}; pub use pyx::{
DEFAULT_TOLERANCE_SECS, PyxJwt, PyxOAuthTokens, PyxTokenStore, PyxTokens, TokenStoreError,
};
pub use realm::Realm; pub use realm::Realm;
pub use service::{Service, ServiceParseError}; pub use service::{Service, ServiceParseError};
pub use store::{AuthBackend, AuthScheme, TextCredentialStore, TomlCredentialError}; pub use store::{AuthBackend, AuthScheme, TextCredentialStore, TomlCredentialError};

View File

@ -368,9 +368,9 @@ impl PyxTokenStore {
tolerance_secs: u64, tolerance_secs: u64,
) -> Result<PyxTokens, TokenStoreError> { ) -> Result<PyxTokens, TokenStoreError> {
// Decode the access token. // Decode the access token.
let jwt = Jwt::decode(match &tokens { let jwt = PyxJwt::decode(match &tokens {
PyxTokens::OAuth(PyxOAuthTokens { access_token, .. }) => access_token.as_str(), PyxTokens::OAuth(PyxOAuthTokens { access_token, .. }) => access_token,
PyxTokens::ApiKey(PyxApiKeyTokens { access_token, .. }) => access_token.as_str(), PyxTokens::ApiKey(PyxApiKeyTokens { access_token, .. }) => access_token,
})?; })?;
// If the access token is expired, refresh it. // If the access token is expired, refresh it.
@ -503,14 +503,20 @@ impl TokenStoreError {
/// The payload of the JWT. /// The payload of the JWT.
#[derive(Debug, serde::Deserialize)] #[derive(Debug, serde::Deserialize)]
struct Jwt { pub struct PyxJwt {
exp: Option<i64>, /// The expiration time of the JWT, as a Unix timestamp.
pub exp: Option<i64>,
/// The issuer of the JWT.
pub iss: Option<String>,
/// The name of the organization, if any.
#[serde(rename = "urn:pyx:org_name")]
pub name: Option<String>,
} }
impl Jwt { impl PyxJwt {
/// Decode the JWT from the access token. /// Decode the JWT from the access token.
fn decode(access_token: &str) -> Result<Self, JwtError> { pub fn decode(access_token: &AccessToken) -> Result<Self, JwtError> {
let mut token_segments = access_token.splitn(3, '.'); let mut token_segments = access_token.as_str().splitn(3, '.');
let _header = token_segments.next().ok_or(JwtError::MissingHeader)?; let _header = token_segments.next().ok_or(JwtError::MissingHeader)?;
let payload = token_segments.next().ok_or(JwtError::MissingPayload)?; let payload = token_segments.next().ok_or(JwtError::MissingPayload)?;

View File

@ -7,8 +7,8 @@ use url::Url;
use uuid::Uuid; use uuid::Uuid;
use uv_auth::{ use uv_auth::{
AccessToken, AuthBackend, Credentials, PyxOAuthTokens, PyxTokenStore, PyxTokens, Service, AccessToken, AuthBackend, Credentials, PyxJwt, PyxOAuthTokens, PyxTokenStore, PyxTokens,
TextCredentialStore, Service, TextCredentialStore,
}; };
use uv_client::{AuthIntegration, BaseClient, BaseClientBuilder}; use uv_client::{AuthIntegration, BaseClient, BaseClientBuilder};
use uv_distribution_types::IndexUrl; use uv_distribution_types::IndexUrl;
@ -45,12 +45,19 @@ pub(crate) async fn login(
.auth_integration(AuthIntegration::NoAuthMiddleware) .auth_integration(AuthIntegration::NoAuthMiddleware)
.build(); .build();
pyx_login_with_browser(&pyx_store, &client, &printer).await?; let access_token = pyx_login_with_browser(&pyx_store, &client, &printer).await?;
let jwt = PyxJwt::decode(&access_token)?;
if let Some(name) = jwt.name.as_deref() {
writeln!(printer.stderr(), "Logged in to {}", name.bold().cyan())?;
} else {
writeln!( writeln!(
printer.stderr(), printer.stderr(),
"Logged in to {}", "Logged in to {}",
pyx_store.api().bold().cyan() pyx_store.api().bold().cyan()
)?; )?;
}
return Ok(ExitStatus::Success); return Ok(ExitStatus::Success);
} }