1use authly_core::{
2 AuthError, CredentialsProvider, Identity, OAuthProvider, OAuthToken, UserMapper,
3};
4
5pub mod client_credentials_flow;
6pub mod device_flow;
7
8pub use client_credentials_flow::ClientCredentialsFlow;
9pub use device_flow::{DeviceAuthorizationResponse, DeviceFlow};
10
11pub struct OAuth2Flow<P: OAuthProvider, M: UserMapper = ()> {
13 provider: P,
14 mapper: Option<M>,
15}
16
17impl<P: OAuthProvider> OAuth2Flow<P, ()> {
18 pub fn new(provider: P) -> Self {
19 Self {
20 provider,
21 mapper: None,
22 }
23 }
24}
25
26impl<P: OAuthProvider, M: UserMapper> OAuth2Flow<P, M> {
27 pub fn with_mapper(provider: P, mapper: M) -> Self {
28 Self {
29 provider,
30 mapper: Some(mapper),
31 }
32 }
33
34 pub fn initiate_login(
36 &self,
37 scopes: &[&str],
38 pkce_challenge: Option<&str>,
39 ) -> (String, String) {
40 let state = uuid::Uuid::new_v4().to_string();
41 let url = self
42 .provider
43 .get_authorization_url(&state, scopes, pkce_challenge);
44 (url, state)
45 }
46
47 pub async fn finalize_login(
50 &self,
51 code: &str,
52 received_state: &str,
53 expected_state: &str,
54 pkce_verifier: Option<&str>,
55 ) -> Result<(Identity, OAuthToken, Option<M::LocalUser>), AuthError> {
56 if received_state != expected_state {
57 return Err(AuthError::CsrfMismatch);
58 }
59 let (identity, token) = self
60 .provider
61 .exchange_code_for_identity(code, pkce_verifier)
62 .await?;
63
64 let local_user = if let Some(mapper) = &self.mapper {
65 Some(mapper.map_user(&identity).await?)
66 } else {
67 None
68 };
69
70 Ok((identity, token, local_user))
71 }
72
73 pub async fn refresh_access_token(&self, refresh_token: &str) -> Result<OAuthToken, AuthError> {
75 self.provider.refresh_token(refresh_token).await
76 }
77
78 pub async fn revoke_token(&self, token: &str) -> Result<(), AuthError> {
80 self.provider.revoke_token(token).await
81 }
82}
83
84pub struct CredentialsFlow<P: CredentialsProvider, M: UserMapper = ()> {
86 provider: P,
87 mapper: Option<M>,
88}
89
90impl<P: CredentialsProvider> CredentialsFlow<P, ()> {
91 pub fn new(provider: P) -> Self {
92 Self {
93 provider,
94 mapper: None,
95 }
96 }
97}
98
99impl<P: CredentialsProvider, M: UserMapper> CredentialsFlow<P, M> {
100 pub fn with_mapper(provider: P, mapper: M) -> Self {
101 Self {
102 provider,
103 mapper: Some(mapper),
104 }
105 }
106
107 pub async fn authenticate(
108 &self,
109 creds: P::Credentials,
110 ) -> Result<(Identity, Option<M::LocalUser>), AuthError> {
111 let identity = self.provider.authenticate(creds).await?;
112
113 let local_user = if let Some(mapper) = &self.mapper {
114 Some(mapper.map_user(&identity).await?)
115 } else {
116 None
117 };
118
119 Ok((identity, local_user))
120 }
121}