Skip to main content

pdk_jwt_lib/validator/
es_validator.rs

1// Copyright (c) 2026, Salesforce, Inc.,
2// All rights reserved.
3// For full license text, see the LICENSE.txt file
4
5//! # Elliptic Curve Signature Validator
6//!
7//! This module provides signature validation for elliptic curve algorithms
8//! (ES256, ES384) used in JWT tokens.
9
10use std::time::{SystemTime, UNIX_EPOCH};
11
12use elliptic_curve::pkcs8::LineEnding::CR;
13use elliptic_curve::pkcs8::{AssociatedOid, EncodePublicKey};
14use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint};
15use elliptic_curve::{CurveArithmetic, JwkParameters, PublicKey};
16use jwt_simple::prelude::{
17    Duration, ECDSAP256PublicKeyLike, ECDSAP384PublicKeyLike, ES256PublicKey, ES384PublicKey,
18    VerificationOptions,
19};
20
21use super::signature_validator::SignatureValidation;
22use crate::error::jwt_error::JWTError;
23use crate::model::claims::{CustomClaims, JWTClaims, TryFromTrustedJWTSimpleClaims};
24use crate::model::signing_algorithm::SigningKeyLength;
25use crate::model::untrusted_token::untrusted_jwt::UntrustedJWT;
26use crate::parser::es_pk_parser::parse_es_pk;
27
28// Signature validator for ES algorithm.
29// Supports key lengths 256 and 384.
30pub struct EsSignatureValidator<C: CurveArithmetic> {
31    key_length: SigningKeyLength,
32    key: PublicKey<C>,
33}
34
35impl<C> EsSignatureValidator<C>
36where
37    C: CurveArithmetic + JwkParameters + AssociatedOid,
38    <C as CurveArithmetic>::AffinePoint: FromEncodedPoint<C>,
39    <C as elliptic_curve::Curve>::FieldBytesSize: ModulusSize,
40    <C as CurveArithmetic>::AffinePoint: ToEncodedPoint<C>,
41{
42    pub fn new(key_length: SigningKeyLength, key: String) -> Result<Self, JWTError> {
43        let key = parse_es_pk(key)?;
44        Ok(Self { key_length, key })
45    }
46}
47
48impl<C> SignatureValidation for EsSignatureValidator<C>
49where
50    C: CurveArithmetic + JwkParameters + AssociatedOid,
51    <C as CurveArithmetic>::AffinePoint: FromEncodedPoint<C>,
52    <C as elliptic_curve::Curve>::FieldBytesSize: ModulusSize,
53    <C as CurveArithmetic>::AffinePoint: ToEncodedPoint<C>,
54{
55    fn validate(&self, token: String) -> Result<JWTClaims, JWTError> {
56        UntrustedJWT::new(token.as_str())
57            .and_then(|token| {
58                let str_key = self.key.to_public_key_pem(CR)?;
59                as_es_algorithm(&self.key_length, str_key.as_str())?
60                    .verify_token(token.value().as_str())
61            })
62            .and_then(|claims| JWTClaims::try_from_trusted_jwt_simple_claims(claims, token))
63    }
64}
65
66fn full_tolerance() -> core::time::Duration {
67    core::time::Duration::from_secs(Duration::from_days(365 * 50).as_secs())
68}
69
70enum EsPublicKey {
71    ES256 { pk: ES256PublicKey },
72    ES384 { pk: ES384PublicKey },
73}
74
75impl EsPublicKey {
76    fn verify_token(
77        &self,
78        token: &str,
79    ) -> Result<jwt_simple::claims::JWTClaims<CustomClaims>, JWTError> {
80        let now = SystemTime::now()
81            .duration_since(UNIX_EPOCH)
82            .unwrap_or_else(|_| full_tolerance());
83
84        let options = VerificationOptions {
85            accept_future: true,
86            time_tolerance: Some(Duration::from(now)),
87            ..Default::default()
88        };
89
90        match self {
91            EsPublicKey::ES256 { pk } => pk
92                .verify_token::<CustomClaims>(token, Some(options))
93                .map_err(JWTError::from),
94            EsPublicKey::ES384 { pk } => pk
95                .verify_token::<CustomClaims>(token, Some(options))
96                .map_err(JWTError::from),
97        }
98    }
99}
100
101fn as_es_algorithm(key_length: &SigningKeyLength, key: &str) -> Result<EsPublicKey, JWTError> {
102    match (key_length, key) {
103        (SigningKeyLength::Len256, key) => Ok(EsPublicKey::ES256 {
104            pk: ES256PublicKey::from_pem(key)?,
105        }),
106        (SigningKeyLength::Len384, key) => Ok(EsPublicKey::ES384 {
107            pk: ES384PublicKey::from_pem(key)?,
108        }),
109        _ => Err(JWTError::InvalidKeyLength(format!(
110            "Invalid configuration: Key length {key_length:?} is not valid for algorithm ES"
111        ))),
112    }
113}
114
115impl From<elliptic_curve::pkcs8::spki::Error> for crate::error::jwt_error::JWTError {
116    fn from(e: elliptic_curve::pkcs8::spki::Error) -> Self {
117        JWTError::EsPublicKeyParseFailed(format!("ES Public key parsing error: {e}"))
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::EsSignatureValidator;
124    use crate::model::signing_algorithm::SigningKeyLength;
125    use p256::NistP256;
126    use p384::NistP384;
127
128    const ES_PUBLIC_KEY_PEM: &str = "-----BEGIN PUBLIC KEY-----
129MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERqVXn+o+6zEOpWEsGw5CsB+wd8zO
130jxu0uASGpiGP+wYfcc1unyMxcStbDzUjRuObY8DalaCJ9/J6UrkQkZBtZw==
131-----END PUBLIC KEY-----";
132
133    const ES_384_PUBLIC_KEY_PEM: &str = "-----BEGIN PUBLIC KEY-----
134MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEjjUFluy6cFrvj/UQwTJoEhPLEJSrKkx0
135Rqxc0HEHdFuj0dpj977K9LoYRvZopFk8roS1DW3wghytCEfnW6AWNiesqa4S4iux
136oomerb1S3+mXzX4p5459w9axcam9qgjo
137-----END PUBLIC KEY-----";
138
139    fn es256_validator() -> EsSignatureValidator<NistP256> {
140        EsSignatureValidator::new(SigningKeyLength::Len256, String::from(ES_PUBLIC_KEY_PEM))
141            .unwrap()
142    }
143
144    fn es384_validator() -> EsSignatureValidator<NistP384> {
145        EsSignatureValidator::new(
146            SigningKeyLength::Len384,
147            String::from(ES_384_PUBLIC_KEY_PEM),
148        )
149        .unwrap()
150    }
151
152    mod es_validator_256 {
153        use crate::error::jwt_error::JWTErrorEnumKind;
154        use crate::validator::es_validator::tests::es256_validator;
155        use crate::validator::es_validator::SignatureValidation;
156        use crate::validator::signature_validator::tests::assert_error_kind;
157        use test_case::test_case;
158
159        extern crate test_case;
160
161        #[test]
162        fn validation_ok_and_jwt_parsed() {
163            let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJleHAiOjkyMDA5ODUyNH0.ba5H-gFMcWnu-02y_5ITZVX4FSw2d9zE6BJJCWulWOMMuXaSX4-lBVPCjMpSPBE6fNlnWg4Po6bUf0gRdZCAlg";
164
165            let validation = es256_validator().validate(token.to_string());
166
167            assert!(validation.is_ok());
168
169            let jwt_claims = validation.unwrap();
170
171            // Check token was correctly parsed
172            assert_eq!(jwt_claims.get_header("alg").unwrap(), "ES256");
173            assert_eq!(
174                jwt_claims.expiration().unwrap().to_string(),
175                "1999-02-27 06:55:24 UTC"
176            );
177        }
178
179        #[test]
180        fn validation_fails_when_token_not_sent() {
181            let token = "";
182
183            let validation = es256_validator().validate(token.to_string());
184
185            assert_error_kind(&validation, JWTErrorEnumKind::ValidationFailed);
186        }
187
188        #[test]
189        fn unparseable_token_is_rejected() {
190            let token = "WhatAmI?AnInvalidToken!";
191
192            let validation = es256_validator().validate(token.to_string());
193
194            assert_error_kind(&validation, JWTErrorEnumKind::ValidationFailed);
195        }
196
197        #[test]
198        fn validation_fails_on_invalid_signature() {
199            let token = "eyJraWQiOiI5OWNiY2EzYS1kZmM4LTQ3NjgtODQ4MC0yZmIwZWVjZTkyZjEiLCJhbGciOiJFUzI1NiJ9.ew0KICAic3ViIjogIjEyMzQ1Njc4OTAiLA0KICAibmFtZSI6ICJBbmlzaCBOYXRoIiwNCiAgImlhdCI6IDE1MTYyMzkwMjINCn0.OS4wEFUvkfHG_wOPFBDVq04F7NDUvvwFmTR147hoP6IjqmwkDBeslsN_5YMcqGR8wztvQYmPi785xJshja9uVA";
200
201            let validation = es256_validator().validate(token.to_string());
202
203            assert_error_kind(&validation, JWTErrorEnumKind::ValidationFailed);
204        }
205
206        #[test]
207        fn validation_fails_on_missing_signature() {
208            let token = "eyJraWQiOiI5NDE2YWY5ZS1jMTZlLTRjM2UtYmNkNy1kODFmMTdkZjBhN2YiLCJhbGciOiJFUzI1NiJ9.ew0KfQ.X_HB6PXUBcMlFjPAZYFRpgJLIzZO6ADcrqnSS4Sq2nVdcQtjkknuwxptjyFpNU5iP7PAFjYwRSMubgh4cQHNqA";
209
210            let validation = es256_validator().validate(token.to_string());
211
212            assert_error_kind(&validation, JWTErrorEnumKind::ValidationFailed);
213        }
214
215        #[test_case("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.e30.zWty50iXfn_2RtgdvqJ-A7xhkqSeO2UtAa_W9-RASE7ofEkGArOffQUOtQv76v1tQXDUqlQFf9FOms4FKPaQKA"; "verifyValidToken 256")]
216        #[test_case("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJleHAiOjkyMDA5ODUyNH0.ba5H-gFMcWnu-02y_5ITZVX4FSw2d9zE6BJJCWulWOMMuXaSX4-lBVPCjMpSPBE6fNlnWg4Po6bUf0gRdZCAlg"; "exceptionNotThrownOnExpiredTokenWithNoClaimValidation 256")]
217        #[test_case("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.e30.zWty50iXfn_2RtgdvqJ-A7xhkqSeO2UtAa_W9-RASE7ofEkGArOffQUOtQv76v1tQXDUqlQFf9FOms4FKPaQKA"; "exceptionNotThrownOnMissingClaim 256")]
218        #[test_case("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJleHAiOjMyODAzOTQwOTh9.0rFDoK4mv20SBw2rhNIXcNb4gCIElIzXm9pZYyi0XJ3wvFP9-NmRtOBhBOhEiF4S6tpw2u1Mjvv05yQbqsWfRA"; "verifyNotExpiredToken 256")]
219        #[test_case("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJleHAiOjkyMDA5ODUyNH0.ba5H-gFMcWnu-02y_5ITZVX4FSw2d9zE6BJJCWulWOMMuXaSX4-lBVPCjMpSPBE6fNlnWg4Po6bUf0gRdZCAlg"; "exceptionNotThrownOnExpiredToken 256")]
220        #[test_case("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJuYmYiOjgyMDA5ODUyNH0.jpshS_OqCYjhHlji9vLFlQ4gRFeHXOwx4TzDGpz3lKzgIqGpYgXvuspVrDAZNsbt_WUq4XkynJj7I1SKXdljUg"; "verifyTokenWithNbf 256")]
221        #[test_case("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJuYmYiOjMyODAzOTQwOTh9.BFmaYwAqljy5T7CWwndf_5hwJljasmCNwyM8paOqtBULbyZBrdpT9ZK1co2lD60IdFvAivmEuWEZqpldK3CuJg"; "exceptionNotThrownNotYetActiveToken 256")]
222        #[test_case("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJmb28ifQ.1urtAG-oabmrWjH3OVxu--e0UPa5dpxXtZ7CFJGQxFG0IGzPM4LLyxBenWs-9Ue07dPXISuBa77yMTzmuqcLBQ"; "verifyTokenWithAud 256")]
223        #[test_case("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOlsiZXRjIiwiZm9vIiwiYmxhaCJdfQ.wEQIdgpzCMK4O3f9obSVit7-IJTOvJm8fWY9j0w-9vJxyxU2zCto7oCx5B2Z8OmWS9oD4bvc1KlEpd_-i7Vi2A"; "verifyTokenWithAudArray 256")]
224        #[test_case("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOlsiZXRjIiwiZm9vIGJhciIsImJsYWgiXX0.rtdfw_0B0OVyzRg86IfvXpymK4ukg5vVLxsCKtRj9soxk_4X-xSyDgv9sN_cTfTPOq1upsotUFBoWMhIEUve2Q"; "verifyTokenWithAudiencesWithSpaces 256")]
225        #[test_case("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOlsiZXRjIiwiRm9vIiwiYmxhaCJdfQ.Wk6KIMh858nuaa2caoRNiUahZl9KlJbAZ5AgtSUMH-96hJs7naNfzeux-cZ-tuil6ePTLvjwsranIAvDWznamw"; "verifyTokenWithAudiencesCaseSensitive 256")]
226        #[test_case("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOlsiZXRjIiwiYmxhaCJdfQ.SFdcVoIGlJTDAkao6QfjOQEDPq4lAzVjcWQOBXUZ3_EqIWUCJ6XEohhghuux8QbSDmhj36mVimrBbQ4IcyvYJw"; "exceptionNotThrownWhenInvalidAudToken 256")]
227        #[test_case("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJmb28iLCJuYmYiOjgyMDA5ODUyNCwibmFtZSI6IkpvaG4gRG9lIiwic2NvcGVzIjpbInJlYWQiLCJ3cml0ZSJdLCJleHAiOjMyODAzOTQwOTh9.xfaGYUA1xGgYQjdiWFT8JT8AHdZochXx8VkvP1dnUgV-SmdefElAy3JaXKfpnVFM-7DvcnEeUYycQCNL3qS9lA"; "checkAllValidations 256")]
228        fn verify_valid_token_256(token: &str) {
229            let validation = es256_validator().validate(token.to_string());
230
231            assert!(validation.is_ok());
232        }
233    }
234
235    mod es_validator_384 {
236        use crate::error::jwt_error::JWTErrorEnumKind;
237        use crate::validator::es_validator::tests::es384_validator;
238        use crate::validator::es_validator::SignatureValidation;
239        use crate::validator::signature_validator::tests::assert_error_kind;
240        use test_case::test_case;
241
242        extern crate test_case;
243
244        #[test]
245        fn validation_ok() {
246            let token = "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNjU4NDMwNjg2LCJleHAiOjE2NTg5NDg2MzF9.Bm6E2fuWizA8WObF6tWl80Gyak79H6FaD4Fxn9d0Gr-IGih5PvntcXHHl18p1DYFLsrt9xPfIAAaWsIk6VfrtCNb65Y2nzqDJUCNcYtFBvxY8NPY2dRLC3Gl5HAqVvex";
247
248            let validation = es384_validator().validate(token.to_string());
249
250            assert!(validation.is_ok());
251        }
252
253        #[test]
254        fn validation_fails_when_token_not_sent() {
255            let token = "eyJraWQiOiI5NDE2YWY5ZS1jMTZlLTRjM2UtYmNkNy1kODFmMTdkZjBhN2YiLCJhbGciOiJFUzI1NiJ9.ew0KfQ.X_HB6PXUBcMlFjPAZYFRpgJLIzZO6ADcrqnSS4Sq2nVdcQtjkknuwxptjyFpNU5iP7PAFjYwRSMubgh4cQHNqA";
256
257            let validation = es384_validator().validate(token.to_string());
258
259            assert_error_kind(&validation, JWTErrorEnumKind::ValidationFailed);
260        }
261
262        #[test]
263        fn unparseable_token_is_rejected() {
264            let token = "WhatAmI?AnInvalidToken!";
265
266            let validation = es384_validator().validate(token.to_string());
267
268            assert_error_kind(&validation, JWTErrorEnumKind::ValidationFailed);
269        }
270
271        #[test]
272        fn validation_fails_on_invalid_signature() {
273            let token = "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFuaXNoIE5hdGgiLCJpYXQiOjE1MTYyMzkwMjJ9.6adcW-2ww22MC3n41o5b6wULVolXno4md0glQR1U9hfIpbyyWQS2U-947x4mnc6bx-pxKO9SjnLtv7rsvOjvP300K5WayPIISQ0lc7CDkKH2s3oT1Bw5gHVtKfYT5Gjv";
274
275            let validation = es384_validator().validate(token.to_string());
276
277            assert_error_kind(&validation, JWTErrorEnumKind::ValidationFailed);
278        }
279
280        #[test]
281        fn validation_fails_on_missing_signature() {
282            let token = "";
283
284            let validation = es384_validator().validate(token.to_string());
285
286            assert_error_kind(&validation, JWTErrorEnumKind::ValidationFailed);
287        }
288
289        #[test_case("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.e30.LLv51B6Y7ksfwFNLeMuF_nWNVHjvZwU75MC6uVJCFqYag7RogTHuEMIc5PsE42fwAlsKaY8pWQbzLeMkl7-vC0fkMvj7YDIowWYE15gfHigzbrelwpgFZ8k6SzdIKZJ2"; "verifyValidToken 384")]
290        #[test_case("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJleHAiOjkyMDA5ODUyNH0._IIq-sOy4JExOTJphYrxcogGc7dEc80xNLqz0FmY_6FAgH_W1E6ihitVnMwAg1WUKJZAPIuLCZtdCiWi69aH5Uz_YGKPZjppOqETgHuoQ8C89z2gQ313LgoyBv-ebvpB"; "exceptionNotThrownOnExpiredTokenWithNoClaimValidation 384")]
291        #[test_case("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.e30.6BJi3OGsiXOyRwUfu663r9SL0NzuYkdOQ_MS46WfGSWBXHc8WS_VpKlt4wZXaZMOQKndDCPdKbvXSLnrJ0pNWGiwQ7IufviWxhXkMJL6jll9Jwf1-y8EXQt1NiY8aYvR"; "exceptionNotThrownOnMissingClaim 384")]
292        #[test_case("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJleHAiOjMyODAzOTQwOTh9.LxipZW5nkk-T-2mRxLzmEE44lKy4cc3eHLWI3LfDPHFO_qhZIqaGxhS7SwBk6HNCiJ61EOHq-YjehMa1xxaKupfa6n7MlVm9EqHhPXyONqfiH3BchxhqC1KbDv9TrKyz"; "verifyNotExpiredToken 384")]
293        #[test_case("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJleHAiOjkyMDA5ODUyNC4zMjF9.Xyn-wcsh_SCoBFJZkQUC5jeJYSuXpF1k7UbgQN0jwZJSBCCkxOYjzevuCXtZJsnySmYkyuP-7K6YPtLpiS7Nmqz--1AN6S6u4l3TO-20PjybFhEckZEGVYf98esmcwHm"; "exceptionNotThrownOnExpiredToken 384")]
294        #[test_case("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJuYmYiOjgyMDA5ODUyNC40MzN9.Db2CqHjYHIvB_pb2_p3GfI57KRHGa_MYJ3dF5Or4vM4JQG5E756Lm21_dSqYDJnA6roan7z92uuoqpFRRNmdHjTz8zgP_QBcdSQhUsogA3YlE27o-oveGsjDOWQG_88l"; "verifyTokenWithNbf 384")]
295        #[test_case("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJuYmYiOjMyODAzOTQwOTguMzQyfQ.H3DWycc7O1QY4_V8alWXQf9cuxYmRPkKdmaiQ8yTVj5LaOTDxoVeFYusQWC8NQ0ZbYrEqZNHLcZlTQZ55fsaYPXrRgLaeqCQ_BGeMJZqj8btzoZ8AKGUtWYbUhCD6UfL"; "exceptionNotThrownNotYetActiveToken 384")]
296        #[test_case("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJmb28ifQ.pdejdj6fkVgxQLzW_hj40tbk2Nc2WFcfrzdtIT2ZKbd9UA24nO_eYjz411eR8wN0uYMPlgkGXeMFRCw-TMmmTvhhqLy-3tgFfdMtfD6HkxVhFRSK1q7ZUWOfumNmspgR"; "verifyTokenWithAud 384")]
297        #[test_case("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiZXRjIiwiZm9vIiwiYmxhaCJdfQ.KhcqpcQdiOPy_fiVjDqmETW1uxgKoVlQqF4aMvterke0i6GdD0d5Bst5_wxz4l4Q54Ybw6uLHRwXT7Afc9RTDPBQqRLf2CgidRu72NukcXufYpJyPsyelneETSAC855N"; "verifyTokenWithAudArray 384")]
298        #[test_case("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiZXRjIiwiZm9vIGJhciIsImJsYWgiXX0.v-yysmA64_SJ0w9eZPL3NNQFCpJYweFvy7LJP84N_6NDA1RjAicAi7Gt6DIAdG-cFG0Jn8NJM4DdwRBJUycGrOILCOgmio-bh63S-FwBLk3ExAJzrAr_yiMWLEvekgR6"; "verifyTokenWithAudiencesWithSpaces 384")]
299        #[test_case("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiZXRjIiwiRm9vIiwiYmxhaCJdfQ.irwNz94eGFFXblZSxC4OGAs3pzR07b1VAaEGfzu_2QcTAHqMSLw1c7HmeBDczwNY89X1smiVhFx6R1COJ8CA9c1h9vrYe1ED_LfElVfvTSpYHNcPWgBLFsvQI7k98xL4"; "verifyTokenWithAudiencesCaseSensitive 384")]
300        #[test_case("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiZXRjIiwiYmxhaCJdfQ.9C3CuglaBOiKoJQycEjVg2NOap2RbQVhSdqJk6V3tC3mK3OzxFouPuzb7ZLNlJh73UbD-gHXZxieFTNAc60dcYVt-tuUMYA9Atp-FZTeoZ973a-KI_DHb9BLiLo0hgYi"; "exceptionNotThrownWhenInvalidAudToken 384")]
301        #[test_case("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJmb28iLCJuYmYiOjgyMDA5ODUyNCwibmFtZSI6IkpvaG4gRG9lIiwic2NvcGVzIjpbInJlYWQiLCJ3cml0ZSJdLCJleHAiOjMyODAzOTQwOTh9.4_AS9rscqomVqrAuF3JuV9WT-dahxNik3U5ou-nLmYK8Is-7ddkP1tLfQm5ufcRUXrN9HbyXdNy9Afr8TP0Vd72v45HKEZancXaghzlhmGGROesshVwBRltC1XLYEsIE"; "checkAllValidations 384")]
302        fn verify_valid_token_384(token: &str) {
303            let validation = es384_validator().validate(token.to_string());
304
305            assert!(validation.is_ok());
306        }
307    }
308}