actix_jwt_validator_middleware/
lib.rs1pub use jwks_client;
2
3use actix_web::dev::{self, HttpResponseBuilder, ServiceRequest};
4use actix_web::http::StatusCode;
5use actix_web::Error as ActixError;
6use actix_web::{web, FromRequest, HttpRequest, HttpResponse};
7
8use actix_web_httpauth::extractors::bearer::BearerAuth;
9use actix_web_httpauth::extractors::bearer::Config as BearerConfig;
10use actix_web_httpauth::extractors::AuthenticationError;
11use actix_web_httpauth::headers::www_authenticate::bearer::Bearer;
12use actix_web_httpauth::middleware::HttpAuthentication;
13
14use jwks_client::error::Error as JwksError;
15use jwks_client::keyset::KeyStore;
16
17use jonases_tracing_util::tracing::{event, Level};
18use jonases_tracing_util::{log_simple_err, log_simple_err_callback};
19
20use futures::future::{ready, Ready};
21
22use serde::{Deserialize, Serialize};
23
24use display_json::DisplayAsJson;
25
26use std::sync::Arc;
27
28pub async fn init_key_set(
29 certs_endpoint: &str,
30) -> Result<Arc<KeyStore>, JwksError> {
31 Ok(Arc::new(KeyStore::new_from(&certs_endpoint).await?))
32}
33
34pub fn jwt_validator() -> HttpAuthentication<
35 BearerAuth,
36 fn(
37 ServiceRequest,
38 BearerAuth,
39 ) -> Ready<Result<ServiceRequest, ActixError>>,
40> {
41 HttpAuthentication::bearer(auth_wrapper)
42}
43
44fn auth_wrapper(
45 req: ServiceRequest,
46 bearer: BearerAuth,
47) -> Ready<Result<ServiceRequest, ActixError>> {
48 ready(auth(req, bearer))
49}
50
51fn auth(
52 req: ServiceRequest,
53 bearer: BearerAuth,
54) -> Result<ServiceRequest, ActixError> {
55 let config = req
56 .app_data::<BearerConfig>()
57 .map(|data| data.clone())
58 .unwrap_or_else(Default::default);
59
60 let key_set = req
61 .app_data::<web::Data<Arc<KeyStore>>>()
62 .ok_or(AuthenticationError::from(config.clone()))
63 .map_err(log_simple_err_callback("could not retrieve key_set"))?;
64
65 match key_set.verify(bearer.token()) {
66 Ok(_jwt) => match User::decode(bearer.token(), &key_set) {
67 Ok(user) => {
68 event!(Level::INFO, %user);
69 Ok(req)
70 }
71 Err(e) => {
72 log_simple_err("could not decode user from access token", &e);
73 Err(AuthenticationError::from(config).into())
74 }
75 },
76 Err(e) => {
77 log_simple_err("could not verify user access token", &e);
78 Err(AuthenticationError::from(config).into())
79 }
80 }
81}
82
83#[derive(Serialize, Deserialize, DisplayAsJson)]
84pub struct User {
85 pub name: String,
86 #[serde(alias = "preferred_username")]
87 pub username: String,
88 pub email: String,
89}
90
91impl User {
92 fn init(
93 req: &HttpRequest,
94 payload: &mut dev::Payload,
95 ) -> Result<User, Error> {
96 let bearer = BearerAuth::from_request(req, payload)
97 .into_inner()
98 .map_err(log_simple_err_callback(
99 "could not retrieve BearerAuth from request",
100 ))?;
101
102 let key_set = req
103 .app_data::<web::Data<Arc<KeyStore>>>()
104 .ok_or(Error::KeyStoreNotFound)
105 .map_err(log_simple_err_callback(
106 "could not retrieve key_set",
107 ))?;
108
109 Self::decode(bearer.token(), &key_set)
110 }
111
112 pub fn try_from_token(token: &str) -> Result<User, Error> {
113 let key_set = KeyStore::new();
114 Self::decode(token, &key_set)
115 }
116
117 fn decode(token: &str, key_set: &KeyStore) -> Result<User, Error> {
118 let jwt = key_set.decode(token).map_err(
119 log_simple_err_callback("could not decode user access token"),
120 )?;
121
122 let user =
123 jwt.payload().into().map_err(log_simple_err_callback(
124 "could not parse user access token into user object",
125 ))?;
126
127 Ok(user)
128 }
129}
130
131impl FromRequest for User {
132 type Config = ();
133 type Future = Ready<Result<Self, Self::Error>>;
134 type Error = Error;
135
136 fn from_request(
137 req: &HttpRequest,
138 payload: &mut dev::Payload,
139 ) -> Self::Future {
140 ready(User::init(req, payload))
141 }
142}
143
144#[derive(Debug, Serialize, DisplayAsJson)]
145pub enum Error {
146 HeaderNotFound,
147 KeyStoreNotFound,
148 JwksError,
149}
150
151impl From<AuthenticationError<Bearer>> for Error {
152 fn from(_: AuthenticationError<Bearer>) -> Self {
153 Self::HeaderNotFound
154 }
155}
156
157impl From<JwksError> for Error {
158 fn from(_: JwksError) -> Self {
159 Self::JwksError
160 }
161}
162
163impl actix_web::error::ResponseError for Error {
164 fn error_response(&self) -> HttpResponse {
165 let mut res = HttpResponseBuilder::new(self.status_code());
166 res.json(self)
167 }
168
169 fn status_code(&self) -> StatusCode {
170 StatusCode::INTERNAL_SERVER_ERROR
171 }
172}