Skip to main content

oauth2_test_server/
error.rs

1use axum::{
2    http::StatusCode,
3    response::{IntoResponse, Response},
4    Json,
5};
6use serde_json::json;
7use thiserror::Error;
8
9/// Centralized error type for OAuth2 endpoints that return JSON errors.
10#[derive(Debug, Error)]
11pub enum OauthError {
12    #[error("invalid_request")]
13    InvalidRequest(Option<String>),
14
15    #[error("invalid_client")]
16    InvalidClient,
17
18    #[error("invalid_grant")]
19    InvalidGrant,
20
21    #[error("unauthorized_client")]
22    UnauthorizedClient(Option<String>),
23
24    #[error("unsupported_grant_type")]
25    UnsupportedGrantType,
26
27    #[error("invalid_scope")]
28    InvalidScope(String),
29
30    #[error("server_error")]
31    ServerError,
32
33    #[error("invalid_token")]
34    InvalidToken(Option<String>),
35
36    #[error("authorization_pending")]
37    AuthorizationPending,
38
39    #[error("slow_down")]
40    SlowDown,
41
42    #[error("expired_token")]
43    ExpiredToken,
44
45    #[error("{error}")]
46    Custom {
47        status: StatusCode,
48        error: String,
49        description: Option<String>,
50    },
51}
52
53impl IntoResponse for OauthError {
54    fn into_response(self) -> Response {
55        let (status, error, description) = match &self {
56            OauthError::InvalidRequest(desc) => {
57                (StatusCode::BAD_REQUEST, "invalid_request", desc.clone())
58            }
59            OauthError::InvalidClient => (StatusCode::BAD_REQUEST, "invalid_client", None),
60            OauthError::InvalidGrant => (StatusCode::BAD_REQUEST, "invalid_grant", None),
61            OauthError::UnauthorizedClient(desc) => {
62                (StatusCode::BAD_REQUEST, "unauthorized_client", desc.clone())
63            }
64            OauthError::UnsupportedGrantType => {
65                (StatusCode::BAD_REQUEST, "unsupported_grant_type", None)
66            }
67            OauthError::InvalidScope(desc) => {
68                (StatusCode::BAD_REQUEST, "invalid_scope", Some(desc.clone()))
69            }
70            OauthError::ServerError => (StatusCode::INTERNAL_SERVER_ERROR, "server_error", None),
71            OauthError::InvalidToken(desc) => {
72                (StatusCode::UNAUTHORIZED, "invalid_token", desc.clone())
73            }
74            OauthError::AuthorizationPending => {
75                (StatusCode::BAD_REQUEST, "authorization_pending", None)
76            }
77            OauthError::SlowDown => (StatusCode::BAD_REQUEST, "slow_down", None),
78            OauthError::ExpiredToken => (StatusCode::BAD_REQUEST, "expired_token", None),
79            OauthError::Custom {
80                status,
81                error,
82                description,
83            } => (*status, error.as_str(), description.clone()),
84        };
85
86        let mut body = serde_json::Map::new();
87        body.insert("error".to_string(), json!(error));
88        if let Some(desc) = description {
89            body.insert("error_description".to_string(), json!(desc));
90        }
91
92        (status, Json(body)).into_response()
93    }
94}