this repo has no description
1use axum::{
2 Json,
3 http::StatusCode,
4 response::{IntoResponse, Response},
5};
6use serde::Serialize;
7
8#[derive(Debug)]
9pub enum OAuthError {
10 InvalidRequest(String),
11 InvalidClient(String),
12 InvalidGrant(String),
13 UnauthorizedClient(String),
14 UnsupportedGrantType(String),
15 InvalidScope(String),
16 AccessDenied(String),
17 ServerError(String),
18 UseDpopNonce(String),
19 InvalidDpopProof(String),
20 ExpiredToken(String),
21 InvalidToken(String),
22 RateLimited,
23}
24
25#[derive(Serialize)]
26struct OAuthErrorResponse {
27 error: String,
28 error_description: Option<String>,
29}
30
31impl IntoResponse for OAuthError {
32 fn into_response(self) -> Response {
33 let (status, error, description) = match self {
34 OAuthError::InvalidRequest(msg) => {
35 (StatusCode::BAD_REQUEST, "invalid_request", Some(msg))
36 }
37 OAuthError::InvalidClient(msg) => {
38 (StatusCode::UNAUTHORIZED, "invalid_client", Some(msg))
39 }
40 OAuthError::InvalidGrant(msg) => (StatusCode::BAD_REQUEST, "invalid_grant", Some(msg)),
41 OAuthError::UnauthorizedClient(msg) => {
42 (StatusCode::UNAUTHORIZED, "unauthorized_client", Some(msg))
43 }
44 OAuthError::UnsupportedGrantType(msg) => {
45 (StatusCode::BAD_REQUEST, "unsupported_grant_type", Some(msg))
46 }
47 OAuthError::InvalidScope(msg) => (StatusCode::BAD_REQUEST, "invalid_scope", Some(msg)),
48 OAuthError::AccessDenied(msg) => (StatusCode::FORBIDDEN, "access_denied", Some(msg)),
49 OAuthError::ServerError(msg) => {
50 (StatusCode::INTERNAL_SERVER_ERROR, "server_error", Some(msg))
51 }
52 OAuthError::UseDpopNonce(nonce) => {
53 return (
54 StatusCode::BAD_REQUEST,
55 [("DPoP-Nonce", nonce)],
56 Json(OAuthErrorResponse {
57 error: "use_dpop_nonce".to_string(),
58 error_description: Some("A DPoP nonce is required".to_string()),
59 }),
60 )
61 .into_response();
62 }
63 OAuthError::InvalidDpopProof(msg) => {
64 (StatusCode::UNAUTHORIZED, "invalid_dpop_proof", Some(msg))
65 }
66 OAuthError::ExpiredToken(msg) => (StatusCode::UNAUTHORIZED, "invalid_token", Some(msg)),
67 OAuthError::InvalidToken(msg) => (StatusCode::UNAUTHORIZED, "invalid_token", Some(msg)),
68 OAuthError::RateLimited => (
69 StatusCode::TOO_MANY_REQUESTS,
70 "rate_limited",
71 Some("Too many requests. Please try again later.".to_string()),
72 ),
73 };
74 (
75 status,
76 Json(OAuthErrorResponse {
77 error: error.to_string(),
78 error_description: description,
79 }),
80 )
81 .into_response()
82 }
83}
84
85impl From<sqlx::Error> for OAuthError {
86 fn from(err: sqlx::Error) -> Self {
87 tracing::error!("Database error in OAuth flow: {}", err);
88 OAuthError::ServerError("An internal error occurred".to_string())
89 }
90}
91
92impl From<anyhow::Error> for OAuthError {
93 fn from(err: anyhow::Error) -> Self {
94 tracing::error!("Internal error in OAuth flow: {}", err);
95 OAuthError::ServerError("An internal error occurred".to_string())
96 }
97}