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
use axum::{
    extract::rejection::TypedHeaderRejection,
    http::StatusCode,
    response::{IntoResponse, Response},
};
use jsonwebtoken::Algorithm;
use thiserror::Error;

use tracing::log::warn;

#[derive(Debug, Error)]
pub enum AuthError {
    #[error(transparent)]
    JwksSerialisationError(#[from] serde_json::Error),

    #[error(transparent)]
    JwksRefreshError(#[from] reqwest::Error),

    #[error(transparent)]
    KeyFileError(#[from] std::io::Error),

    #[error("InvalidKey {0}")]
    InvalidKey(String),

    #[error("Invalid Kid {0}")]
    InvalidKid(String),

    #[error("Invalid Key Algorithm {0:?}")]
    InvalidKeyAlg(Algorithm),

    #[error(transparent)]
    InvalidTokenHeader(#[from] TypedHeaderRejection),

    #[error(transparent)]
    InvalidToken(#[from] jsonwebtoken::errors::Error),

    #[error("Invalid Claim")]
    InvalidClaims(),
}

impl IntoResponse for AuthError {
    fn into_response(self) -> Response {
        warn!("AuthError: {}", &self);
        let (status, error_message) = match self {
            AuthError::JwksRefreshError(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
            AuthError::KeyFileError(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
            AuthError::InvalidKid(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg),
            AuthError::InvalidTokenHeader(_) => (StatusCode::BAD_REQUEST, self.to_string()),
            AuthError::InvalidToken(_) => (StatusCode::BAD_REQUEST, self.to_string()),
            AuthError::InvalidKey(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg),
            AuthError::JwksSerialisationError(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
            AuthError::InvalidKeyAlg(_) => (StatusCode::BAD_REQUEST, self.to_string()),
            AuthError::InvalidClaims() => (StatusCode::FORBIDDEN, self.to_string()),
        };
        let body = axum::Json(serde_json::json!({
            "error": error_message,
        }));
        (status, body).into_response()
    }
}