Skip to main content

rig_core/providers/chatgpt/auth/
mod.rs

1//! ChatGPT access-token configuration and native OAuth authentication.
2//!
3//! ```no_run
4//! use rig_core::providers::chatgpt::auth::{AuthSource, Authenticator, DeviceCodeHandler};
5//!
6//! let auth = Authenticator::new(AuthSource::OAuth, None, DeviceCodeHandler::default(), true);
7//! ```
8
9use crate::http_client::HttpClientExt;
10use crate::wire::Secret;
11use futures::lock::Mutex;
12use std::fmt;
13use std::path::PathBuf;
14use std::sync::Arc;
15
16pub use crate::providers::internal::auth::{DeviceCodeHandler, DeviceCodePrompt};
17
18#[cfg(not(target_family = "wasm"))]
19mod native;
20
21#[derive(Clone)]
22pub enum AuthSource {
23    AccessToken {
24        access_token: String,
25        account_id: Option<String>,
26    },
27    OAuth,
28}
29
30impl fmt::Debug for AuthSource {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        match self {
33            Self::AccessToken { .. } => f.write_str("AccessToken(<redacted>)"),
34            Self::OAuth => f.write_str("OAuth"),
35        }
36    }
37}
38
39#[derive(Clone, Debug)]
40#[cfg_attr(target_family = "wasm", allow(dead_code))]
41pub struct Authenticator {
42    source: AuthSource,
43    auth_file: Option<PathBuf>,
44    device_code_handler: DeviceCodeHandler,
45    allow_device_flow: bool,
46    /// Held across a cache refresh to prevent concurrent updates.
47    refresh_lock: Arc<Mutex<()>>,
48}
49
50pub use crate::providers::internal::auth::AuthError;
51
52#[derive(Debug, Clone)]
53pub struct AuthContext {
54    /// Resolved credential. Use [`Secret::expose`] only when raw bytes are required.
55    pub access_token: Secret,
56    pub account_id: Option<String>,
57}
58
59impl Authenticator {
60    pub fn new(
61        source: AuthSource,
62        auth_file: Option<PathBuf>,
63        device_code_handler: DeviceCodeHandler,
64        allow_device_flow: bool,
65    ) -> Self {
66        Self {
67            source,
68            auth_file,
69            device_code_handler,
70            allow_device_flow,
71            refresh_lock: Arc::default(),
72        }
73    }
74
75    /// Resolve the access token and account id, refreshing through `http` as needed.
76    /// Return cache, transport, or authorization errors. OAuth is unsupported
77    /// on WASM; explicit access tokens remain available.
78    #[cfg_attr(target_family = "wasm", allow(unused_variables))]
79    pub async fn auth_context<H>(&self, http: &H) -> Result<AuthContext, AuthError>
80    where
81        H: HttpClientExt,
82    {
83        match &self.source {
84            AuthSource::AccessToken {
85                access_token,
86                account_id,
87            } => Ok(AuthContext {
88                access_token: access_token.clone().into(),
89                account_id: account_id.clone(),
90            }),
91            #[cfg(not(target_family = "wasm"))]
92            AuthSource::OAuth => self.auth_context_oauth(http).await,
93            #[cfg(target_family = "wasm")]
94            AuthSource::OAuth => Err(AuthError::Message(
95                "ChatGPT OAuth is not supported on wasm targets".into(),
96            )),
97        }
98    }
99}