Skip to main content

axum_security/oauth2/
handler.rs

1use std::time::Duration;
2
3use axum::{http::StatusCode, response::IntoResponse};
4
5pub use crate::after_login::AfterLoginCookies;
6
7/// Tokens received after a successful OAuth 2.0 authorization code exchange.
8pub struct TokenResponse {
9    /// The access token issued by the provider.
10    pub access_token: String,
11    /// The refresh token, if the provider issued one.
12    pub refresh_token: Option<String>,
13    /// The lifetime of the access token, if the provider sent `expires_in`.
14    pub expires_in: Option<Duration>,
15}
16
17/// An error the provider returned on the callback redirect
18/// (RFC 6749 §4.1.2.1) instead of an authorization code — for example when
19/// the user denies consent (`access_denied`).
20#[derive(Debug, Clone)]
21pub struct AuthorizationErrorResponse {
22    /// The `error` code, e.g. `access_denied` or `invalid_scope`.
23    pub error: String,
24    /// The optional human-readable `error_description`.
25    pub error_description: Option<String>,
26    /// The optional `error_uri` pointing at documentation.
27    pub error_uri: Option<String>,
28}
29
30/// Implement this trait to handle the outcome of an OAuth 2.0 login.
31///
32/// After the authorization code exchange succeeds, [`after_login`](OAuth2Handler::after_login)
33/// is called with the tokens and an [`AfterLoginCookies`] helper for setting response cookies.
34///
35/// If the provider redirects back with an error instead (RFC 6749 §4.1.2.1),
36/// [`on_error`](OAuth2Handler::on_error) is called; override it to render your
37/// own page or redirect. The default returns `401 Unauthorized`.
38pub trait OAuth2Handler: Send + Sync + 'static {
39    fn after_login(
40        &self,
41        token_res: TokenResponse,
42        _context: &mut AfterLoginCookies<'_>,
43    ) -> impl Future<Output = impl IntoResponse> + Send;
44
45    /// Called when the provider returns an authorization error on the
46    /// callback (e.g. the user cancelled). The state cookie has already been
47    /// cleared. The default renders `401 Unauthorized`.
48    fn on_error(
49        &self,
50        error: AuthorizationErrorResponse,
51    ) -> impl Future<Output = impl IntoResponse> + Send {
52        async move {
53            let _ = error;
54            StatusCode::UNAUTHORIZED
55        }
56    }
57}