Skip to main content

kontext_dev_sdk/
oauth.rs

1use url::Url;
2
3use crate::KontextAuthSession;
4use crate::KontextDevClient;
5use crate::KontextDevConfig;
6use crate::KontextDevError;
7use crate::TokenExchangeToken;
8
9#[derive(Clone, Debug)]
10pub struct KontextOAuthProviderConfig {
11    pub config: KontextDevConfig,
12}
13
14#[derive(Clone, Debug)]
15pub struct ParsedOAuthCallback {
16    pub code: Option<String>,
17    pub state: Option<String>,
18    pub error: Option<String>,
19    pub error_description: Option<String>,
20}
21
22#[derive(Clone, Debug)]
23pub struct TokenExchangeConfig {
24    pub config: KontextDevConfig,
25    pub subject_token: String,
26    pub resource: String,
27}
28
29#[derive(Clone, Debug)]
30pub struct KontextOAuthProvider {
31    client: KontextDevClient,
32}
33
34impl KontextOAuthProvider {
35    pub fn new(config: KontextOAuthProviderConfig) -> Self {
36        Self {
37            client: KontextDevClient::new(config.config),
38        }
39    }
40
41    pub fn client(&self) -> &KontextDevClient {
42        &self.client
43    }
44
45    pub async fn authenticate(&self) -> Result<KontextAuthSession, KontextDevError> {
46        self.client.authenticate_mcp().await
47    }
48
49    pub async fn create_connect_session(
50        &self,
51        gateway_access_token: &str,
52    ) -> Result<crate::ConnectSession, KontextDevError> {
53        self.client
54            .create_connect_session(gateway_access_token)
55            .await
56    }
57
58    pub async fn create_integration_connect_url(
59        &self,
60        gateway_access_token: &str,
61    ) -> Result<String, KontextDevError> {
62        self.client
63            .create_integration_connect_url(gateway_access_token)
64            .await
65    }
66}
67
68pub fn parse_oauth_callback(url: &str) -> Result<ParsedOAuthCallback, KontextDevError> {
69    let parsed = Url::parse(url).map_err(|source| KontextDevError::InvalidUrl {
70        url: url.to_string(),
71        source,
72    })?;
73
74    let mut callback = ParsedOAuthCallback {
75        code: None,
76        state: None,
77        error: None,
78        error_description: None,
79    };
80
81    for (key, value) in parsed.query_pairs() {
82        match key.as_ref() {
83            "code" => callback.code = Some(value.to_string()),
84            "state" => callback.state = Some(value.to_string()),
85            "error" => callback.error = Some(value.to_string()),
86            "error_description" => callback.error_description = Some(value.to_string()),
87            _ => {}
88        }
89    }
90
91    Ok(callback)
92}
93
94pub async fn exchange_token(
95    config: TokenExchangeConfig,
96) -> Result<TokenExchangeToken, KontextDevError> {
97    let client = KontextDevClient::new(config.config);
98    client
99        .exchange_for_resource(&config.subject_token, &config.resource, None)
100        .await
101}