Skip to main content

auths_infra_http/
npm_auth.rs

1//! npm access token verification.
2//!
3//! Verifies an npm access token via the `/-/whoami` endpoint and returns
4//! the authenticated username.
5
6use auths_core::ports::platform::{PlatformError, PlatformUserProfile};
7
8use crate::default_http_client;
9
10const NPM_REGISTRY: &str = "https://registry.npmjs.org";
11
12/// HTTP client that verifies npm access tokens.
13///
14/// Usage:
15/// ```ignore
16/// let provider = HttpNpmAuthProvider::new();
17/// let profile = provider.verify_token("npm_abc123").await?;
18/// println!("Authenticated as: {}", profile.login);
19/// ```
20pub struct HttpNpmAuthProvider {
21    client: reqwest::Client,
22}
23
24impl Default for HttpNpmAuthProvider {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30impl HttpNpmAuthProvider {
31    pub fn new() -> Self {
32        Self {
33            client: default_http_client(),
34        }
35    }
36
37    /// Verifies an npm access token and returns the username.
38    ///
39    /// Args:
40    /// * `token`: npm access token (created at https://www.npmjs.com/settings/~/tokens)
41    pub async fn verify_token(&self, token: &str) -> Result<PlatformUserProfile, PlatformError> {
42        let url = format!("{NPM_REGISTRY}/-/whoami");
43        let resp = self
44            .client
45            .get(&url)
46            .bearer_auth(token)
47            .send()
48            .await
49            .map_err(|e| PlatformError::Platform {
50                message: format!("npm whoami request failed: {e}"),
51            })?;
52
53        if !resp.status().is_success() {
54            return Err(PlatformError::Platform {
55                message: format!(
56                    "npm token verification failed (HTTP {}). \
57                     Make sure your token is valid and has read access.",
58                    resp.status()
59                ),
60            });
61        }
62
63        #[derive(serde::Deserialize)]
64        struct WhoamiResponse {
65            username: String,
66        }
67
68        let whoami: WhoamiResponse = resp.json().await.map_err(|e| PlatformError::Platform {
69            message: format!("Failed to parse npm whoami response: {e}"),
70        })?;
71
72        Ok(PlatformUserProfile {
73            login: whoami.username,
74            name: None,
75        })
76    }
77}