Skip to main content

raps_kernel/auth/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2024-2025 Dmytro Yemelianov
3
4//! Authentication module for APS OAuth 2.0
5//!
6//! Implements both 2-legged (client credentials) and 3-legged (authorization code) OAuth flows.
7
8mod device_code;
9mod three_leg;
10mod token_ops;
11mod two_leg;
12pub mod types;
13
14#[cfg(test)]
15mod tests;
16
17pub use types::*;
18
19use std::sync::Arc;
20use tokio::sync::RwLock;
21
22use crate::config::Config;
23use crate::http::HttpClientConfig;
24use types::{CachedToken, TokenCache};
25
26/// Authentication client for APS
27///
28/// Handles OAuth 2.0 token acquisition for both 2-legged and 3-legged flows.
29#[derive(Clone)]
30pub struct AuthClient {
31    pub(crate) config: Config,
32    pub(crate) http_client: reqwest::Client,
33    pub(crate) cached_2leg_token: Arc<RwLock<Option<CachedToken>>>,
34    pub(crate) cached_3leg_token: Arc<tokio::sync::Mutex<TokenCache>>,
35}
36
37impl AuthClient {
38    /// Create a new authentication client
39    pub fn new(config: Config) -> Self {
40        Self::new_with_http_config(config, HttpClientConfig::default())
41    }
42
43    /// Create a new authentication client with custom HTTP config
44    pub fn new_with_http_config(config: Config, http_config: HttpClientConfig) -> Self {
45        // Try to load stored 3-legged token synchronously
46        let stored_token = Self::load_stored_token_static(&config);
47
48        // Create HTTP client with configured timeouts
49        let http_client = http_config
50            .create_client()
51            .unwrap_or_else(|_| reqwest::Client::new()); // Fallback to default if config fails
52
53        Self {
54            config,
55            http_client,
56            cached_2leg_token: Arc::new(RwLock::new(None)),
57            cached_3leg_token: Arc::new(tokio::sync::Mutex::new(TokenCache {
58                token: stored_token,
59                refreshing: false,
60            })),
61        }
62    }
63
64    /// Get config reference
65    pub fn config(&self) -> &Config {
66        &self.config
67    }
68
69    /// Set a 3-legged token for testing purposes
70    /// This allows integration tests to simulate a logged-in state
71    #[cfg(any(test, feature = "test-utils"))]
72    pub async fn set_3leg_token_for_testing(&self, token: crate::types::StoredToken) {
73        let mut cache = self.cached_3leg_token.lock().await;
74        cache.token = Some(token);
75    }
76
77    /// Set a 2-legged token for testing purposes
78    /// This allows integration tests to simulate having a valid cached token
79    #[cfg(any(test, feature = "test-utils"))]
80    pub async fn set_2leg_token_for_testing(&self, access_token: String, expires_in_secs: u64) {
81        use std::time::{Duration, Instant};
82        let mut cache = self.cached_2leg_token.write().await;
83        *cache = Some(CachedToken {
84            access_token,
85            expires_at: Instant::now() + Duration::from_secs(expires_in_secs),
86        });
87    }
88}