Skip to main content

framework_cqrs_lib/cqrs/infra/token/services/
jwt_rsa.rs

1use std::fmt::Debug;
2use std::sync::Arc;
3
4use async_trait::async_trait;
5use jsonwebtoken::{Algorithm, decode, decode_header, DecodingKey, Validation};
6use reqwest::Client;
7use serde::{Deserialize, Serialize};
8use serde::de::DeserializeOwned;
9
10use crate::cqrs::infra::cache::CacheAsync;
11use crate::cqrs::core::token::TokenService;
12use crate::cqrs::models::errors::{Error, ResultErr};
13
14pub struct JwtRSATokenService {
15    pub cache: Arc<CacheAsync>,
16    pub http_client: Arc<Client>,
17    pub auth_back_url: String,
18}
19
20impl JwtRSATokenService {
21    pub fn new(cache: Arc<CacheAsync>, http_client: Arc<Client>, auth_back_url: String) -> Self {
22        Self {
23            cache,
24            http_client,
25            auth_back_url,
26        }
27    }
28}
29
30#[async_trait]
31impl TokenService for JwtRSATokenService {
32    async fn decode<CLAIMS: Debug + Serialize + DeserializeOwned>(&self, token: &str) -> ResultErr<CLAIMS> {
33        let header = decode_header(token).map_err(|err| {
34            let message = err.to_string();
35            Error::Simple(format!("decode header token : {message}"))
36        })?;
37
38        let kid = header.kid.ok_or(Error::Simple("jwt invalid, pas de kid dans l'entete".to_string()))?;
39        let maybe_data = self.cache.get(&kid).await;
40
41        let jwk = match maybe_data {
42            Some(data) => {
43                let jwk = serde_json::from_str::<JWK>(data.as_str())
44                    .map_err(|err| Error::Simple(err.to_string()))?;
45                Ok(jwk)
46            }
47            None => {
48                let url = format!("{}/v1/jwks/{kid}/public", self.auth_back_url);
49                let response = self.http_client
50                    .get(url)
51                    .send()
52                    .await.map_err(|err| Error::Simple(err.to_string()))?;
53                if response.status() == 200 {
54                    let jwk = response.json::<JWK>().await.map_err(|err| Error::Simple(err.to_string()))?;
55                    let stringify = serde_json::to_string(&jwk)
56                        .map_err(|err| Error::Simple(err.to_string()))?;
57                    self.cache.upsert(kid, stringify).await;
58                    Ok(jwk)
59                } else {
60                    Err(Error::Simple("erreur lors du call authbacku".to_string()))
61                }
62            }
63        }?;
64
65        let decoding_key = DecodingKey::from_rsa_components(
66            jwk.n.as_str(),
67            jwk.e.as_str(),
68        ).map_err(|err| Error::Simple({
69            let error_message = err.to_string();
70            format!("decoding key : {error_message}")
71        }))?;
72
73
74        decode::<CLAIMS>(token, &decoding_key, &Validation::new(Algorithm::RS256))
75            .map(|token_data| token_data.claims)
76            .map_err(|err| {
77                let message = err.to_string();
78                Error::Simple(format!("decode token : {message}"))
79            })
80    }
81}
82
83#[derive(Serialize, Deserialize, Clone, Debug)]
84pub struct JWK {
85    n: String,
86    e: String,
87}