Skip to main content

rustauth_oauth/oauth2/
provider.rs

1use std::future::Future;
2use std::pin::Pin;
3
4use serde_json::Value;
5use url::Url;
6
7use super::authorization_url::AuthorizationUrlRequest;
8use super::error::OAuthError;
9use super::tokens::{OAuth2Tokens, OAuth2UserInfo, ProviderOptions};
10
11/// Minimal OAuth provider metadata.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct OAuthProviderMetadata {
14    id: String,
15    name: String,
16}
17
18impl OAuthProviderMetadata {
19    pub fn new(id: impl Into<String>, name: impl Into<String>) -> Self {
20        Self {
21            id: id.into(),
22            name: name.into(),
23        }
24    }
25
26    pub fn id(&self) -> &str {
27        &self.id
28    }
29
30    pub fn name(&self) -> &str {
31        &self.name
32    }
33}
34
35pub type SocialProviderFuture<'a, T> =
36    Pin<Box<dyn Future<Output = Result<T, OAuthError>> + Send + 'a>>;
37
38#[derive(Debug, Clone, Default, PartialEq, Eq)]
39pub struct SocialAuthorizationUrlRequest {
40    pub state: String,
41    pub redirect_uri: String,
42    pub code_verifier: Option<String>,
43    pub scopes: Vec<String>,
44    pub login_hint: Option<String>,
45}
46
47impl SocialAuthorizationUrlRequest {
48    pub fn into_authorization_url_request(
49        self,
50        id: impl Into<String>,
51        options: ProviderOptions,
52        authorization_endpoint: impl Into<String>,
53        scopes: Vec<String>,
54    ) -> AuthorizationUrlRequest {
55        AuthorizationUrlRequest {
56            id: id.into(),
57            options,
58            authorization_endpoint: authorization_endpoint.into(),
59            redirect_uri: self.redirect_uri,
60            state: self.state,
61            code_verifier: self.code_verifier,
62            scopes,
63            login_hint: self.login_hint,
64            ..AuthorizationUrlRequest::default()
65        }
66    }
67}
68
69#[derive(Debug, Clone, Default, PartialEq, Eq)]
70pub struct SocialAuthorizationCodeRequest {
71    pub code: String,
72    pub code_verifier: Option<String>,
73    pub redirect_uri: String,
74    pub device_id: Option<String>,
75}
76
77#[derive(Debug, Clone, Default, PartialEq)]
78pub struct SocialIdTokenRequest {
79    pub token: String,
80    pub nonce: Option<String>,
81    pub access_token: Option<String>,
82    pub refresh_token: Option<String>,
83    pub scopes: Vec<String>,
84    pub provider_user: Option<Value>,
85}
86
87pub trait SocialOAuthProvider: Send + Sync + 'static {
88    fn id(&self) -> &str;
89    fn name(&self) -> &str;
90    fn provider_options(&self) -> ProviderOptions;
91
92    fn create_authorization_url(
93        &self,
94        input: SocialAuthorizationUrlRequest,
95    ) -> Result<Url, OAuthError>;
96
97    fn validate_authorization_code(
98        &self,
99        input: SocialAuthorizationCodeRequest,
100    ) -> SocialProviderFuture<'_, OAuth2Tokens>;
101
102    fn get_user_info(
103        &self,
104        tokens: OAuth2Tokens,
105        provider_user: Option<Value>,
106    ) -> SocialProviderFuture<'_, Option<OAuth2UserInfo>>;
107
108    fn verify_id_token(&self, _input: SocialIdTokenRequest) -> SocialProviderFuture<'_, bool> {
109        Box::pin(async { Ok(false) })
110    }
111
112    fn refresh_access_token(
113        &self,
114        _refresh_token: String,
115    ) -> SocialProviderFuture<'_, OAuth2Tokens> {
116        Box::pin(async move {
117            Err(OAuthError::InvalidResponse(
118                "provider does not support refresh tokens".to_owned(),
119            ))
120        })
121    }
122
123    fn revoke_token(&self, _token: String) -> SocialProviderFuture<'_, ()> {
124        Box::pin(async move {
125            Err(OAuthError::InvalidResponse(
126                "provider does not support token revocation".to_owned(),
127            ))
128        })
129    }
130}