actix_jwt_auth_middleware/
errors.rs

1use actix_web::body::BoxBody;
2use actix_web::http::StatusCode;
3use actix_web::Error as ActixWebError;
4use actix_web::HttpResponse;
5use actix_web::ResponseError;
6use jwt_compact::CreationError;
7use jwt_compact::ParseError;
8use jwt_compact::ValidationError;
9
10pub type AuthResult<T> = Result<T, AuthError>;
11
12/**
13    Crate wide error type
14
15    if `#[cfg(debug_assertions)]` is true
16    the wrapped errors in (Internal, RefreshAuthorizerDenied, TokenCreation, TokenParse, TokenValidation)
17    are in included in the error message.
18*/
19#[derive(Debug)]
20pub enum AuthError {
21    NoToken,
22    NoTokenSigner,
23    RefreshAuthorizerCall(ActixWebError),
24    RefreshAuthorizerDenied(ActixWebError),
25    TokenCreation(CreationError),
26    TokenParse(ParseError),
27    TokenValidation(ValidationError),
28}
29
30impl PartialEq for AuthError {
31    fn eq(&self, other: &Self) -> bool {
32        match (self, other) {
33            (Self::TokenCreation(_), Self::TokenCreation(_))
34            | (Self::TokenValidation(_), Self::TokenValidation(_))
35            | (Self::TokenParse(_), Self::TokenParse(_))
36            | (Self::RefreshAuthorizerCall(_), Self::RefreshAuthorizerCall(_)) => true,
37            _ => core::mem::discriminant(self) == core::mem::discriminant(other),
38        }
39    }
40}
41
42impl From<CreationError> for AuthError {
43    fn from(val: CreationError) -> Self {
44        AuthError::TokenCreation(val)
45    }
46}
47
48impl From<ParseError> for AuthError {
49    fn from(val: ParseError) -> Self {
50        AuthError::TokenParse(val)
51    }
52}
53
54impl From<ValidationError> for AuthError {
55    fn from(val: ValidationError) -> Self {
56        AuthError::TokenValidation(val)
57    }
58}
59
60impl std::fmt::Display for AuthError {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        const NO_TOKEN_MESSAGE: &str = "An error occurred, no cookie containing a jwt was found in the request. Please first authenticate with this application.";
63
64        #[cfg(not(debug_assertions))]
65        match self {
66            AuthError::NoToken => f.write_str(NO_TOKEN_MESSAGE),
67            AuthError::RefreshAuthorizerDenied(err) => f.write_str(&err.to_string()),
68            AuthError::TokenParse(_) | AuthError::TokenValidation(_) => {
69                f.write_str("An error occurred, the provided jwt could not be processed.")
70            }
71            AuthError::RefreshAuthorizerCall(_)
72            | AuthError::NoTokenSigner
73            | AuthError::TokenCreation(_) => {
74                f.write_str("An internal error occurred. Please try again later.")
75            }
76        }
77        #[cfg(debug_assertions)]
78        match self {
79            AuthError::NoToken => f.write_str(NO_TOKEN_MESSAGE),
80            AuthError::NoTokenSigner => f.write_str(
81                "An error occurred because no CookieSigner was configured on the Authority struct.",
82            ),
83            AuthError::TokenCreation(err) => f.write_fmt(format_args!(
84                "An error occurred creating the jwt.\n\t Error: \"{err}\""
85            )),
86            AuthError::TokenValidation(err) => f.write_fmt(format_args!(
87                "An error occurred validating the jwt.\n\t Error: \"{err}\""
88            )),
89            AuthError::TokenParse(err) => f.write_fmt(format_args!(
90                "An error occurred parsing the jwt.\n\t Error: \"{err}\""
91            )),
92            AuthError::RefreshAuthorizerDenied(err) | AuthError::RefreshAuthorizerCall(err) => {
93                f.write_str(&err.to_string())
94            }
95        }
96    }
97}
98
99impl ResponseError for AuthError {
100    fn status_code(&self) -> StatusCode {
101        match self {
102            AuthError::TokenCreation(_) | AuthError::NoTokenSigner => {
103                StatusCode::INTERNAL_SERVER_ERROR
104            }
105            AuthError::TokenParse(_) => StatusCode::BAD_REQUEST,
106            AuthError::NoToken | AuthError::TokenValidation(_) => StatusCode::UNAUTHORIZED,
107            AuthError::RefreshAuthorizerCall(err) | AuthError::RefreshAuthorizerDenied(err) => {
108                err.as_response_error().status_code()
109            }
110        }
111    }
112    fn error_response(&self) -> HttpResponse<BoxBody> {
113        match self {
114            AuthError::RefreshAuthorizerDenied(err) | AuthError::RefreshAuthorizerCall(err) => {
115                err.error_response()
116            }
117            _ => HttpResponse::build(self.status_code()).body(self.to_string()),
118        }
119    }
120}