raps_kernel/auth/
token_ops.rs1use anyhow::{Context, Result};
7use colored::Colorize;
8
9use super::AuthClient;
10use super::types::UserInfo;
11use crate::config::Config;
12use crate::storage::{StorageBackend, TokenStorage};
13use crate::types::StoredToken;
14
15impl AuthClient {
16 pub(crate) fn token_storage(&self) -> TokenStorage {
18 let backend = StorageBackend::from_env();
19 TokenStorage::new(backend)
20 }
21
22 pub(crate) fn load_stored_token_static(_config: &Config) -> Option<StoredToken> {
24 let backend = StorageBackend::from_env();
25 let storage = TokenStorage::new(backend);
26 storage.load().ok().flatten()
27 }
28
29 pub(crate) fn save_token(&self, token: &StoredToken) -> Result<()> {
31 let storage = self.token_storage();
32 storage.save(token)
33 }
34
35 #[allow(dead_code)]
37 fn load_stored_token(&self) -> Result<StoredToken> {
38 let storage = self.token_storage();
39 storage
40 .load()?
41 .ok_or_else(|| anyhow::anyhow!("No stored token found"))
42 }
43
44 pub fn delete_stored_token(&self) -> Result<()> {
46 let storage = self.token_storage();
47 storage.delete()
48 }
49
50 pub async fn login_with_token(
52 &self,
53 access_token: String,
54 refresh_token: Option<String>,
55 expires_in: u64,
56 scopes: Vec<String>,
57 ) -> Result<StoredToken> {
58 let user_info = self.get_user_info_with_token(&access_token).await?;
60
61 println!(
62 "{} Token validated for user: {}",
63 "OK".green().bold(),
64 user_info.email.as_deref().unwrap_or("unknown")
65 );
66
67 let stored = StoredToken {
69 access_token: access_token.clone(),
70 refresh_token,
71 expires_at: chrono::Utc::now().timestamp() + expires_in as i64,
72 scopes,
73 };
74
75 self.save_token(&stored)?;
76
77 {
79 let mut cache = self.cached_3leg_token.lock().await;
80 cache.token = Some(stored.clone());
81 }
82
83 Ok(stored)
84 }
85
86 pub(crate) async fn get_user_info_with_token(&self, token: &str) -> Result<UserInfo> {
88 let url = if self.config.base_url != "https://developer.api.autodesk.com" {
89 format!("{}/userinfo", self.config.base_url)
90 } else {
91 "https://api.userprofile.autodesk.com/userinfo".to_string()
92 };
93 let _auth_start = std::time::Instant::now();
94 let response = self
95 .http_client
96 .get(url)
97 .bearer_auth(token)
98 .send()
99 .await
100 .context("Failed to fetch user info")?;
101 crate::profiler::record_http_request(_auth_start.elapsed());
102
103 if !response.status().is_success() {
104 let status = response.status();
105 let error_text = response.text().await.unwrap_or_default();
106 let redacted = crate::logging::redact_secrets(&error_text);
107 anyhow::bail!("Failed to validate token ({status}): {redacted}");
108 }
109
110 let user: UserInfo = response.json().await.context("Failed to parse user info")?;
111
112 Ok(user)
113 }
114}