actix_jwt_validator_middleware/
lib.rs

1pub 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}