1#![warn(missing_docs)]
7
8use async_trait::async_trait;
9use serde::{Deserialize, Serialize};
10
11pub mod pkce;
13
14pub mod strategy;
16
17pub mod error;
19use crate::error::AuthError;
20
21pub mod state;
23use crate::state::{Identity, OAuthToken};
24
25pub mod discovery;
27
28#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
30pub enum SameSite {
31 Lax,
33 Strict,
35 None,
37}
38
39#[async_trait]
41pub trait OAuthProvider: Send + Sync {
42 fn provider_id(&self) -> &str;
44
45 fn get_authorization_url(
47 &self,
48 state: &str,
49 scopes: &[&str],
50 code_challenge: Option<&str>,
51 ) -> String;
52
53 async fn exchange_code_for_identity(
55 &self,
56 code: &str,
57 code_verifier: Option<&str>,
58 ) -> Result<(Identity, OAuthToken), AuthError>;
59
60 async fn refresh_token(&self, _refresh_token: &str) -> Result<OAuthToken, AuthError> {
62 Err(AuthError::Provider(
63 "Token refresh not supported by this provider".into(),
64 ))
65 }
66
67 async fn revoke_token(&self, _token: &str) -> Result<(), AuthError> {
69 Err(AuthError::Provider(
70 "Token revocation not supported by this provider".into(),
71 ))
72 }
73}
74
75#[async_trait]
77pub trait CredentialsProvider: Send + Sync {
78 type Credentials;
80
81 async fn authenticate(&self, creds: Self::Credentials) -> Result<Identity, AuthError>;
83}
84
85#[async_trait]
87pub trait UserMapper: Send + Sync {
88 type LocalUser: Send + Sync;
90
91 async fn map_user(&self, identity: &Identity) -> Result<Self::LocalUser, AuthError>;
94}
95
96#[async_trait]
98pub trait ErasedOAuthFlow: Send + Sync {
99 fn provider_id(&self) -> String;
101 fn initiate_login(&self, scopes: &[&str], pkce_challenge: Option<&str>) -> (String, String);
103 async fn finalize_login(
105 &self,
106 code: &str,
107 received_state: &str,
108 expected_state: &str,
109 pkce_verifier: Option<&str>,
110 ) -> Result<(Identity, OAuthToken), AuthError>;
111}
112
113#[async_trait]
114impl UserMapper for () {
115 type LocalUser = ();
116 async fn map_user(&self, _identity: &Identity) -> Result<Self::LocalUser, AuthError> {
117 Ok(())
118 }
119}
120
121#[async_trait]
122impl<T: ErasedOAuthFlow + ?Sized> ErasedOAuthFlow for std::sync::Arc<T> {
123 fn provider_id(&self) -> String {
124 (**self).provider_id()
125 }
126
127 fn initiate_login(&self, scopes: &[&str], pkce_challenge: Option<&str>) -> (String, String) {
128 (**self).initiate_login(scopes, pkce_challenge)
129 }
130
131 async fn finalize_login(
132 &self,
133 code: &str,
134 received_state: &str,
135 expected_state: &str,
136 pkce_verifier: Option<&str>,
137 ) -> Result<(Identity, OAuthToken), AuthError> {
138 (**self)
139 .finalize_login(code, received_state, expected_state, pkce_verifier)
140 .await
141 }
142}
143
144#[async_trait]
145impl<T: ErasedOAuthFlow + ?Sized> ErasedOAuthFlow for Box<T> {
146 fn provider_id(&self) -> String {
147 (**self).provider_id()
148 }
149
150 fn initiate_login(&self, scopes: &[&str], pkce_challenge: Option<&str>) -> (String, String) {
151 (**self).initiate_login(scopes, pkce_challenge)
152 }
153
154 async fn finalize_login(
155 &self,
156 code: &str,
157 received_state: &str,
158 expected_state: &str,
159 pkce_verifier: Option<&str>,
160 ) -> Result<(Identity, OAuthToken), AuthError> {
161 (**self)
162 .finalize_login(code, received_state, expected_state, pkce_verifier)
163 .await
164 }
165}