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