1use crate::{types::{Jwt, Algorithm}, jwk::{Key, Jwks}, time::{Leeway, validate_claim_times}, Error, Result};
2
3#[derive(Debug, Clone)]
5pub struct VerifyOptions {
6 pub validate_times: bool,
8 pub leeway: Leeway,
10 pub expected_iss: Option<String>,
12 pub expected_aud: Option<String>,
14 pub expected_alg: Option<Algorithm>,
16 pub now_ts: Option<i64>,
18}
19
20impl Default for VerifyOptions {
21 fn default() -> Self {
22 Self {
23 validate_times: true,
24 leeway: Leeway { seconds: 0 },
25 expected_iss: None,
26 expected_aud: None,
27 expected_alg: None,
28 now_ts: None,
29 }
30 }
31}
32impl VerifyOptions {
33 pub fn validate_times(mut self, v: bool) -> Self { self.validate_times = v; self }
35 pub fn leeway(mut self, s: i64) -> Self { self.leeway = Leeway { seconds: s }; self }
37 pub fn expect_iss(mut self, iss: impl Into<String>) -> Self { self.expected_iss = Some(iss.into()); self }
39 pub fn expect_aud(mut self, aud: impl Into<String>) -> Self { self.expected_aud = Some(aud.into()); self }
41 pub fn expect_alg(mut self, alg: Algorithm) -> Self { self.expected_alg = Some(alg); self }
43 pub fn now_ts(mut self, ts: i64) -> Self { self.now_ts = Some(ts); self }
45}
46
47fn to_jalg(a: Algorithm) -> jsonwebtoken::Algorithm {
49 use Algorithm::*;
50 match a {
51 HS256 => jsonwebtoken::Algorithm::HS256,
52 HS384 => jsonwebtoken::Algorithm::HS384,
53 HS512 => jsonwebtoken::Algorithm::HS512,
54 RS256 => jsonwebtoken::Algorithm::RS256,
55 RS384 => jsonwebtoken::Algorithm::RS384,
56 RS512 => jsonwebtoken::Algorithm::RS512,
57 ES256 => jsonwebtoken::Algorithm::ES256,
58 ES384 => jsonwebtoken::Algorithm::ES384,
59 ES512 => jsonwebtoken::Algorithm::ES384,
60 EdDSA => jsonwebtoken::Algorithm::EdDSA,
61 }
62}
63
64pub fn verify_with_key(jwt: &Jwt, key: &Key, opts: &VerifyOptions) -> Result<()> {
83 use jsonwebtoken::{Validation, DecodingKey, decode};
84
85 if let Some(expected_alg) = opts.expected_alg {
86 if jwt.header.alg != expected_alg {
87 return Err(Error::Claims(format!("algorithm mismatch: expected {:?}, got {:?}", expected_alg, jwt.header.alg)));
88 }
89 }
90
91 match jwt.header.alg {
92 Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => { #[cfg(not(feature="hs"))] return Err(Error::DisabledAlg("HS")); }
93 Algorithm::RS256 | Algorithm::RS384 | Algorithm::RS512 => { #[cfg(not(feature="rs"))] return Err(Error::DisabledAlg("RS")); }
94 Algorithm::ES256 | Algorithm::ES384 | Algorithm::ES512 => { #[cfg(not(feature="es"))] return Err(Error::DisabledAlg("ES")); }
95 Algorithm::EdDSA => { #[cfg(not(feature="eddsa"))] return Err(Error::DisabledAlg("EdDSA")); }
96 }
97
98 let mut v = Validation::new(to_jalg(jwt.header.alg));
99 v.validate_exp = false;
100 v.insecure_disable_signature_validation();
101 if let Some(ref iss) = opts.expected_iss { v.set_issuer(&[iss.clone()]); }
102 if let Some(ref aud) = opts.expected_aud { v.set_audience(&[aud.clone()]); }
103
104 let dkey = match key {
105 Key::Hs(s) => DecodingKey::from_secret(s),
106 Key::RsaPublicPem(p) => DecodingKey::from_rsa_pem(p).map_err(|e| Error::Key(e.to_string()))?,
107 Key::EcPublicPem(p) => DecodingKey::from_ec_pem(p).map_err(|e| Error::Key(e.to_string()))?,
108 Key::EdPublicPem(p) => DecodingKey::from_ed_pem(p).map_err(|e| Error::Key(e.to_string()))?,
109 _ => return Err(Error::Key("public or shared secret required to verify".into())),
110 };
111
112 let token_str = format!("{}.{}.{}", jwt.raw_header_b64, jwt.raw_payload_b64, jwt.signature_b64);
113 let data = decode::<serde_json::Value>(&token_str, &dkey, &v).map_err(|e| Error::Signature(e.to_string()))?;
114
115 if opts.validate_times {
116 let now = opts.now_ts.unwrap_or_else(|| time::OffsetDateTime::now_utc().unix_timestamp());
117 let map = data.claims.as_object().cloned().unwrap_or_default();
118 validate_claim_times(&map, true, opts.leeway, now)?;
119 }
120 Ok(())
121}
122
123impl Jwt {
124 pub fn verify(&self, key: &Key, opts: VerifyOptions) -> Result<()> {
135 verify_with_key(self, key, &opts)
136 }
137 pub fn verify_with_jwks(&self, jwks: &Jwks, opts: VerifyOptions) -> Result<()> {
153 let kid = self.header.kid.clone().ok_or(crate::Error::MissingKid)?;
154 let key = jwks.select_for(&kid, self.header.alg)?;
155 verify_with_key(self, &key, &opts)
156 }
157}