1use axum::{
2 body::Body,
3 http::StatusCode,
4 response::{IntoResponse, Response},
5};
6use http::header;
7use jsonwebtoken::Algorithm;
8use thiserror::Error;
9
10use tracing::debug;
11
12#[derive(Debug, Error)]
13pub enum InitError {
14 #[error("Builder Error {0}")]
15 BuilderError(String),
16
17 #[error(transparent)]
18 KeyFileError(#[from] std::io::Error),
19
20 #[error(transparent)]
21 KeyDecodingError(#[from] jsonwebtoken::errors::Error),
22
23 #[error("Builder Error {0}")]
24 DiscoveryError(String),
25
26 #[error("Builder Error {0}")]
27 JwksUrlError(String),
28
29 #[error("Jwks Parsing Error {0}")]
30 JwksParsingError(#[from] serde_json::Error),
31}
32
33#[derive(Debug, Error)]
34pub enum AuthError {
35 #[error(transparent)]
36 JwksSerialisationError(#[from] serde_json::Error),
37
38 #[error("JwksRefreshError {0}")]
39 JwksRefreshError(String),
40
41 #[error("InvalidKey {0}")]
42 InvalidKey(String),
43
44 #[error("Invalid Kid {0}")]
45 InvalidKid(String),
46
47 #[error("Invalid Key Algorithm {0:?}")]
48 InvalidKeyAlg(Algorithm),
49
50 #[error("Missing Token")]
51 MissingToken(),
52
53 #[error(transparent)]
54 InvalidToken(#[from] jsonwebtoken::errors::Error),
55
56 #[error("Invalid Claim")]
57 InvalidClaims(),
58
59 #[error("No Authorizer")]
60 NoAuthorizer(),
61
62 #[error("No Authorizer Layer")]
64 NoAuthorizerLayer(),
65}
66
67fn response_wwwauth(status: StatusCode, bearer: &str) -> Response<Body> {
68 let mut res = Response::new(Body::empty());
69 *res.status_mut() = status;
70 let h = if bearer.is_empty() {
71 "Bearer".to_owned()
72 } else {
73 format!("Bearer {bearer}")
74 };
75 res.headers_mut().insert(header::WWW_AUTHENTICATE, h.parse().unwrap());
76
77 res
78}
79
80fn response_500() -> Response<Body> {
81 let mut res = Response::new(Body::empty());
82 *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
83
84 res
85}
86
87#[cfg(feature = "tonic")]
88impl From<AuthError> for Response<tonic::body::BoxBody> {
89 fn from(e: AuthError) -> Self {
90 match e {
91 AuthError::JwksRefreshError(err) => {
92 tracing::error!("AuthErrors::JwksRefreshError: {}", err);
93 tonic::Status::internal("")
94 }
95 AuthError::InvalidKey(err) => {
96 tracing::error!("AuthErrors::InvalidKey: {}", err);
97 tonic::Status::internal("")
98 }
99 AuthError::JwksSerialisationError(err) => {
100 tracing::error!("AuthErrors::JwksSerialisationError: {}", err);
101 tonic::Status::internal("")
102 }
103 AuthError::InvalidKeyAlg(err) => {
104 debug!("AuthErrors::InvalidKeyAlg: {:?}", err);
105 tonic::Status::unauthenticated("error=\"invalid_token\", error_description=\"invalid key algorithm\"")
106 }
107 AuthError::InvalidKid(err) => {
108 debug!("AuthErrors::InvalidKid: {}", err);
109 tonic::Status::unauthenticated("error=\"invalid_token\", error_description=\"invalid kid\"")
110 }
111 AuthError::InvalidToken(err) => {
112 debug!("AuthErrors::InvalidToken: {}", err);
113 tonic::Status::unauthenticated("error=\"invalid_token\"")
114 }
115 AuthError::MissingToken() => {
116 debug!("AuthErrors::MissingToken");
117 tonic::Status::unauthenticated("")
118 }
119 AuthError::InvalidClaims() => {
120 debug!("AuthErrors::InvalidClaims");
121 tonic::Status::unauthenticated("error=\"insufficient_scope\"")
122 }
123 AuthError::NoAuthorizer() => {
124 debug!("AuthErrors::NoAuthorizer");
125 tonic::Status::unauthenticated("error=\"invalid_token\"")
126 }
127 AuthError::NoAuthorizerLayer() => {
128 debug!("AuthErrors::NoAuthorizerLayer");
129 tonic::Status::unauthenticated("error=\"no_authorizer_layer\"")
130 }
131 }
132 .into_http()
133 }
134}
135
136impl From<AuthError> for Response {
137 fn from(e: AuthError) -> Self {
138 e.into_response()
139 }
140}
141
142impl IntoResponse for AuthError {
144 fn into_response(self) -> Response {
145 match self {
146 AuthError::JwksRefreshError(err) => {
147 tracing::error!("AuthErrors::JwksRefreshError: {}", err);
148 response_500()
149 }
150 AuthError::InvalidKey(err) => {
151 tracing::error!("AuthErrors::InvalidKey: {}", err);
152 response_500()
153 }
154 AuthError::JwksSerialisationError(err) => {
155 tracing::error!("AuthErrors::JwksSerialisationError: {}", err);
156 response_500()
157 }
158 AuthError::InvalidKeyAlg(err) => {
159 debug!("AuthErrors::InvalidKeyAlg: {:?}", err);
160 response_wwwauth(
161 StatusCode::UNAUTHORIZED,
162 "error=\"invalid_token\", error_description=\"invalid key algorithm\"",
163 )
164 }
165 AuthError::InvalidKid(err) => {
166 debug!("AuthErrors::InvalidKid: {}", err);
167 response_wwwauth(
168 StatusCode::UNAUTHORIZED,
169 "error=\"invalid_token\", error_description=\"invalid kid\"",
170 )
171 }
172 AuthError::InvalidToken(err) => {
173 debug!("AuthErrors::InvalidToken: {}", err);
174 response_wwwauth(StatusCode::UNAUTHORIZED, "error=\"invalid_token\"")
175 }
176 AuthError::MissingToken() => {
177 debug!("AuthErrors::MissingToken");
178 response_wwwauth(StatusCode::UNAUTHORIZED, "")
179 }
180 AuthError::InvalidClaims() => {
181 debug!("AuthErrors::InvalidClaims");
182 response_wwwauth(StatusCode::FORBIDDEN, "error=\"insufficient_scope\"")
183 }
184 AuthError::NoAuthorizer() => {
185 debug!("AuthErrors::NoAuthorizer");
186 response_wwwauth(StatusCode::FORBIDDEN, "error=\"invalid_token\"")
187 }
188 AuthError::NoAuthorizerLayer() => {
189 debug!("AuthErrors::NoAuthorizerLayer");
190 response_wwwauth(StatusCode::UNAUTHORIZED, "error=\"no_authorizer_layer\"")
192 }
193 }
194 }
195}