mirror of
https://tangled.org/tranquil.farm/tranquil-pds
synced 2026-09-27 04:34:14 +00:00
98 lines
3.4 KiB
Rust
98 lines
3.4 KiB
Rust
use axum::{
|
|
Json,
|
|
http::StatusCode,
|
|
response::{IntoResponse, Response},
|
|
};
|
|
use serde::Serialize;
|
|
|
|
#[derive(Debug)]
|
|
pub enum OAuthError {
|
|
InvalidRequest(String),
|
|
InvalidClient(String),
|
|
InvalidGrant(String),
|
|
UnauthorizedClient(String),
|
|
UnsupportedGrantType(String),
|
|
InvalidScope(String),
|
|
AccessDenied(String),
|
|
ServerError(String),
|
|
UseDpopNonce(String),
|
|
InvalidDpopProof(String),
|
|
ExpiredToken(String),
|
|
InvalidToken(String),
|
|
RateLimited,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct OAuthErrorResponse {
|
|
error: String,
|
|
error_description: Option<String>,
|
|
}
|
|
|
|
impl IntoResponse for OAuthError {
|
|
fn into_response(self) -> Response {
|
|
let (status, error, description) = match self {
|
|
OAuthError::InvalidRequest(msg) => {
|
|
(StatusCode::BAD_REQUEST, "invalid_request", Some(msg))
|
|
}
|
|
OAuthError::InvalidClient(msg) => {
|
|
(StatusCode::UNAUTHORIZED, "invalid_client", Some(msg))
|
|
}
|
|
OAuthError::InvalidGrant(msg) => (StatusCode::BAD_REQUEST, "invalid_grant", Some(msg)),
|
|
OAuthError::UnauthorizedClient(msg) => {
|
|
(StatusCode::UNAUTHORIZED, "unauthorized_client", Some(msg))
|
|
}
|
|
OAuthError::UnsupportedGrantType(msg) => {
|
|
(StatusCode::BAD_REQUEST, "unsupported_grant_type", Some(msg))
|
|
}
|
|
OAuthError::InvalidScope(msg) => (StatusCode::BAD_REQUEST, "invalid_scope", Some(msg)),
|
|
OAuthError::AccessDenied(msg) => (StatusCode::FORBIDDEN, "access_denied", Some(msg)),
|
|
OAuthError::ServerError(msg) => {
|
|
(StatusCode::INTERNAL_SERVER_ERROR, "server_error", Some(msg))
|
|
}
|
|
OAuthError::UseDpopNonce(nonce) => {
|
|
return (
|
|
StatusCode::BAD_REQUEST,
|
|
[("DPoP-Nonce", nonce)],
|
|
Json(OAuthErrorResponse {
|
|
error: "use_dpop_nonce".to_string(),
|
|
error_description: Some("A DPoP nonce is required".to_string()),
|
|
}),
|
|
)
|
|
.into_response();
|
|
}
|
|
OAuthError::InvalidDpopProof(msg) => {
|
|
(StatusCode::UNAUTHORIZED, "invalid_dpop_proof", Some(msg))
|
|
}
|
|
OAuthError::ExpiredToken(msg) => (StatusCode::UNAUTHORIZED, "invalid_token", Some(msg)),
|
|
OAuthError::InvalidToken(msg) => (StatusCode::UNAUTHORIZED, "invalid_token", Some(msg)),
|
|
OAuthError::RateLimited => (
|
|
StatusCode::TOO_MANY_REQUESTS,
|
|
"rate_limited",
|
|
Some("Too many requests. Please try again later.".to_string()),
|
|
),
|
|
};
|
|
(
|
|
status,
|
|
Json(OAuthErrorResponse {
|
|
error: error.to_string(),
|
|
error_description: description,
|
|
}),
|
|
)
|
|
.into_response()
|
|
}
|
|
}
|
|
|
|
impl From<anyhow::Error> for OAuthError {
|
|
fn from(err: anyhow::Error) -> Self {
|
|
tracing::error!("Internal error in OAuth flow: {}", err);
|
|
OAuthError::ServerError("An internal error occurred".to_string())
|
|
}
|
|
}
|
|
|
|
impl From<sqlx::Error> for OAuthError {
|
|
fn from(err: sqlx::Error) -> Self {
|
|
tracing::error!("Database error in OAuth flow: {}", err);
|
|
OAuthError::ServerError("An internal error occurred".to_string())
|
|
}
|
|
}
|