1use jsonwebtoken::{Algorithm, DecodingKey, Validation, decode};
2use serde::Deserialize;
3
4use crate::{AccessTokenVerifier, Claims, Result, error::Error};
5
6#[derive(Debug, Deserialize)]
7pub struct VerifyJwtCfg {
8 pub public_key_pem: String,
9 pub issuer: String,
10 pub audience: String,
11}
12
13pub struct VerifyJwt {
17 decoding_key: DecodingKey,
18 validation: Validation,
19}
20
21impl VerifyJwt {
22 pub fn new(cfg: VerifyJwtCfg) -> Result<Self> {
24 let VerifyJwtCfg {
25 public_key_pem,
26 issuer,
27 audience,
28 } = cfg;
29
30 let decoding_key = DecodingKey::from_ed_pem(public_key_pem.as_bytes())?;
31 let mut validation = Validation::new(Algorithm::EdDSA);
32 if issuer.is_empty() {
33 return Err(Error::ErrorMessage("issuer must not be empty".into()));
34 }
35 if audience.is_empty() {
36 return Err(Error::ErrorMessage("audience must not be empty".into()));
37 }
38 validation.set_issuer(&[issuer]);
39 validation.set_audience(&[audience]);
40 validation.validate_aud = true;
41 Ok(Self {
42 decoding_key,
43 validation,
44 })
45 }
46
47 pub fn validate_token(&self, token: &str) -> Result<Claims> {
49 decode::<Claims>(token, &self.decoding_key, &self.validation)
50 .map(|data| data.claims)
51 .map_err(|e| Error::AuthError(e.to_string().into()))
52 }
53}
54
55impl AccessTokenVerifier for VerifyJwt {
56 fn validate_access_token(&self, token: &str) -> Result<Claims> {
57 self.validate_token(token)
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use jsonwebtoken::{EncodingKey, Header, encode};
64
65 use super::*;
66
67 const PRIVATE_KEY_PEM: &str = "-----BEGIN PRIVATE KEY-----
68MC4CAQAwBQYDK2VwBCIEIGrD/e7uKYqSY4twDEsRfMMuLSrODf14dpTiTK6K1YI0
69-----END PRIVATE KEY-----";
70 const PUBLIC_KEY_PEM: &str = "-----BEGIN PUBLIC KEY-----
71MCowBQYDK2VwAyEA2+Jj2UvNCvQiUPNYRgSi0cJSPiJI6Rs6D0UTeEpQVj8=
72-----END PUBLIC KEY-----";
73
74 #[test]
75 fn test_verify_with_public_key_only() {
76 let claims = Claims::new(
77 "test_issuer".to_string(),
78 "test_audience".to_string(),
79 "test_sub".to_string(),
80 (chrono::Utc::now().timestamp() as usize) + 3600,
81 chrono::Utc::now().timestamp() as usize,
82 );
83 let token = encode(
84 &Header::new(Algorithm::EdDSA),
85 &claims,
86 &EncodingKey::from_ed_pem(PRIVATE_KEY_PEM.as_bytes()).unwrap(),
87 )
88 .unwrap();
89
90 let verifier = VerifyJwt::new(VerifyJwtCfg {
91 public_key_pem: PUBLIC_KEY_PEM.to_string(),
92 issuer: "test_issuer".to_string(),
93 audience: "test_audience".to_string(),
94 })
95 .unwrap();
96 let decoded = verifier.validate_token(&token).unwrap();
97 assert_eq!(decoded.sub, "test_sub");
98 }
99}