1use async_trait::async_trait;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5pub mod pkce;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct Identity {
10 pub provider_id: String,
12 pub external_id: String,
14 pub email: Option<String>,
16 pub username: Option<String>,
18 pub attributes: HashMap<String, String>,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct OAuthToken {
25 pub access_token: String,
27 pub token_type: String,
29 pub expires_in: Option<u64>,
31 pub refresh_token: Option<String>,
33 pub scope: Option<String>,
35 pub id_token: Option<String>,
37}
38
39#[derive(Debug, thiserror::Error)]
41pub enum AuthError {
42 #[error("Provider error: {0}")]
44 Provider(String),
45 #[error("Invalid credentials")]
47 InvalidCredentials,
48 #[error("Invalid code")]
50 InvalidCode,
51 #[error("Network error")]
53 Network,
54 #[error("Session error: {0}")]
56 Session(String),
57 #[error("Token error: {0}")]
59 Token(String),
60 #[error("CSRF state mismatch")]
62 CsrfMismatch,
63}
64
65#[async_trait]
67pub trait OAuthProvider: Send + Sync {
68 fn get_authorization_url(
70 &self,
71 state: &str,
72 scopes: &[&str],
73 code_challenge: Option<&str>,
74 ) -> String;
75
76 async fn exchange_code_for_identity(
78 &self,
79 code: &str,
80 code_verifier: Option<&str>,
81 ) -> Result<(Identity, OAuthToken), AuthError>;
82
83 async fn refresh_token(&self, _refresh_token: &str) -> Result<OAuthToken, AuthError> {
85 Err(AuthError::Provider(
86 "Token refresh not supported by this provider".into(),
87 ))
88 }
89
90 async fn revoke_token(&self, _token: &str) -> Result<(), AuthError> {
92 Err(AuthError::Provider(
93 "Token revocation not supported by this provider".into(),
94 ))
95 }
96}
97
98#[async_trait]
100pub trait CredentialsProvider: Send + Sync {
101 type Credentials;
102
103 async fn authenticate(&self, creds: Self::Credentials) -> Result<Identity, AuthError>;
105}
106
107#[async_trait]
109pub trait UserMapper: Send + Sync {
110 type LocalUser: Send + Sync;
111
112 async fn map_user(&self, identity: &Identity) -> Result<Self::LocalUser, AuthError>;
115}
116
117#[async_trait]
118impl UserMapper for () {
119 type LocalUser = ();
120 async fn map_user(&self, _identity: &Identity) -> Result<Self::LocalUser, AuthError> {
121 Ok(())
122 }
123}