1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use crate::common::{
frontend::{FrontendResponse, FrontendResponseExt, OAuthError},
model::{Client, Grant},
};
use async_trait::async_trait;
/// Authorization provider trait
/// This is one of the traits that has to be implemented by the end user, for the oauth manager to work.
///
/// This trait is used to authorize a grant proven by a authorization code and exchange a code for a grant.
#[async_trait]
pub trait AuthorizationProvider: 'static + Send + Sync {
/// This is the type of the owner id that is used to identify the resource owner.
/// This type will need to match the OwnerId used in [TokenProvider](crate::token::TokenProvider).
type OwnerId;
/// This is the type of the extras that can be passed down from the top-level authorization functions.
/// This can contain things like request information or owner id to [authorize_grant](AuthorizationProvider::authorize_grant).
type Extras;
/// This is the error type that can be returned by the authorization provider implementing this trait.
/// This type will need to match the Error used in [TokenProvider](crate::token::TokenProvider) and [ClientProvider](crate::common::ClientProvider).
type Error;
/// Authorize a grant.
///
/// # Implementation notes
/// This function should return an [GrantAuthorizationResult] that describes the result of the authorization.
/// - If the result is [Authorized](GrantAuthorizationResult::Authorized), the authorization flow will continue and a code will be generated and returned.
/// - If the result is [RequireAuthentication](GrantAuthorizationResult::RequireAuthentication), the client should be prompted to ask the resource owner to authenticate.
/// - If the result is [RequireScopeConsent](GrantAuthorizationResult::RequireScopeConsent), the client should be prompted to ask the resource owner for consent.
/// - If the result is [Unauthorized](GrantAuthorizationResult::Unauthorized), the authorization flow will be stopped and an error will be returned to the client.
///
/// # Arguments
/// * `client` - The client that is requesting the grant.
/// * `scopes` - The scopes that the client is requesting.
/// * `extras` - An optional parameter that can be passed down from the top-level authorize function, this can contain things like request information or owner id. This is useful to add context like session info to the authorization provider.
///
/// # Returns
/// An [GrantAuthorizationResult] that describes the result of the authorization.
///
/// # Errors
/// If the grant is invalid or the authorization provider fails to authorize the grant, through whatever error.
async fn authorize_grant(
&self,
client: &Client,
scopes: &[String],
extras: &mut Option<Self::Extras>,
) -> Result<GrantAuthorizationResult<Self::OwnerId>, Self::Error>;
/// Generate an authorization code for a grant.
///
/// # Implementation notes
/// This function should return a fully random authorization code that can later be reversed
/// to a grant through [exchange_code_for_grant](AuthorizationProvider::exchange_code_for_grant)
/// which is part of this same trait.
/// You should not use any readable or predictable values for the authorization code, such as JWT.
/// The authorization code MUST expire shortly after it is issued to mitigate the risk of leaks.
/// A maximum authorization code lifetime of 10 minutes is RECOMMENDED.
///
/// # Arguments
/// * `grant` - The grant to authorize.
/// * `extras` - An optional parameter that can be passed down from the top-level functions. This can contain things like request information.
///
/// # Returns
/// A string that represents the authorization code.
///
/// # Errors
/// If the grant is invalid or the authorization provider fails to authorize the grant, through whatever error.
/// This error will later be returned through [OAuthError::ProviderImplementationError].
async fn generate_code_for_grant(
&self,
grant: Grant<Self::OwnerId>,
) -> Result<String, Self::Error>;
/// Exchange an authorization code for a grant.
///
/// # Implementation notes
/// This function should return the grant that was previously authorized by [authorize_grant](AuthorizationProvider::generate_code_for_grant).
///
/// # Arguments
/// * `code` - The authorization code to exchange for a grant.
/// * `extras` - An optional parameter that can be passed down from the top-level functions. This can contain things like request information.
///
/// # Returns
/// An optional grant that was previously authorized by [authorize_grant](AuthorizationProvider::generate_code_for_grant).
/// Or None if the code is invalid or expired.
///
/// # Errors
/// If the code is invalid or expired, or the authorization provider fails to exchange the code for a grant, through whatever error.
/// This error will later be returned through [OAuthError::ProviderImplementationError].
async fn exchange_code_for_grant(
&self,
code: String,
) -> Result<Option<Grant<Self::OwnerId>>, Self::Error>;
/// Handle a required authentication.
/// This function should return a response that can be sent to the client to prompt the resource owner to authenticate.
/// This is used when the resource owner needs to authenticate before the grant can be authorized.
///
/// # Arguments
/// * `extras` - An optional parameter that can be passed down from the top-level functions. This can contain things like request information.
///
/// # Returns
/// A [FrontendResponse] that can be used to build a response to the client.
///
/// # Errors
/// If the authorization provider fails to handle the required authentication, through whatever error.
/// This error will later be returned through [OAuthError::ProviderImplementationError].
///
/// # Default implementation
/// The default implementation of this function will return an [OAuthError::AccessDenied] error.
async fn handle_required_authentication(
&self,
_extras: &mut Option<Self::Extras>,
) -> Result<FrontendResponse, Self::Error> {
Ok(OAuthError::<()>::AccessDenied.into_frontend_response())
}
/// Handle a required scope consent.
/// This function should return a response that can be sent to the client to prompt the resource owner to consent to the requested scopes.
/// This is used when the resource owner needs to consent to the requested scopes before the grant can be authorized.
///
/// # Arguments
/// * `scopes` - The scopes that the resource owner needs to consent to.
/// * `extras` - An optional parameter that can be passed down from the top-level functions. This can contain things like request information.
///
/// # Returns
/// A [FrontendResponse] that can be used to build a response to the client.
///
/// # Errors
/// If the authorization provider fails to handle the required scope consent, through whatever error.
/// This error will later be returned through [OAuthError::ProviderImplementationError].
///
/// # Default implementation
/// The default implementation of this function will return an [OAuthError::AccessDenied] error.
async fn handle_missing_scope_consent(
&self,
_scopes: Vec<String>,
_extras: &mut Option<Self::Extras>,
) -> Result<FrontendResponse, Self::Error> {
Ok(OAuthError::<()>::AccessDenied.into_frontend_response())
}
}
/// The result of an authorization request.
pub enum GrantAuthorizationResult<U> {
/// The grant was authorized, the flow will continue to return an authorization code.
Authorized(U),
/// The resource owner needs to authenticate before the grant can be authorized.
RequireAuthentication,
/// The resource owner needs to consent to the requested scopes before the grant can be authorized.
RequireScopeConsent(Vec<String>),
/// The grant was unauthorized, the flow will stop and return an error to the client.
Unauthorized,
}