1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
//! ![GitHub CI](https://github.com/jedisct1/rust-jwt-simple/workflows/Rust/badge.svg)
//! [![Docs.rs](https://docs.rs/jwt-simple/badge.svg)](https://docs.rs/jwt-simple/)
//! [![crates.io](https://img.shields.io/crates/v/jwt-simple.svg)](https://crates.io/crates/jwt-simple)
//!
//! # JWT-Simple
//!
//! A new JWT implementation for Rust that focuses on simplicity, while avoiding
//! common JWT security pitfalls.
//!
//! `jwt-simple` is unopinionated and supports all commonly deployed
//! authentication and signature algorithms:
//!
//! * HMAC-SHA2:
//!   * `HS256`
//!   * `HS384`
//!   * `HS512`
//! * `BLAKE2B`
//! * RSA
//!   * `RS256`
//!   * `RS384`
//!   * `RS512`
//!   * `PS256`
//!   * `PS384`
//!   * `PS512`
//! * p256
//!   * `ES256`
//! * p384
//!   * `ES384`
//! * secp256k1
//!   * `ES256K`
//! * Ed25519
//!   * `EdDSA`
//!
//! `jwt-simple` can be compiled out of the box to WebAssembly/WASI.
//! It is fully compatible with Fastly _Compute_ service.
//!
//! Important: JWT's purpose is to verify that data has been created by a party
//! knowing a secret key. It does not provide any kind of confidentiality: JWT
//! data is simply encoded as BASE64, and is not encrypted.
//!
//! ## Usage
//!
//! `cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! jwt-simple = "0.12"
//! ```
//!
//! Rust:
//!
//! ```rust
//! use jwt_simple::prelude::*;
//! ```
//!
//! ## Authentication (symmetric, `HS*` JWT algorithms) example
//!
//! Authentication schemes use the same key for creating and verifying tokens.
//! In other words, both parties need to ultimately trust each other, or else
//! the verifier could also create arbitrary tokens.
//!
//! ### Keys and tokens creation
//!
//! Key creation:
//!
//! ```rust
//! use jwt_simple::prelude::*;
//!
//! // create a new key for the `HS256` JWT algorithm
//! let key = HS256Key::generate();
//! ```
//!
//! A key can be exported as bytes with `key.to_bytes()`, and restored with
//! `HS256Key::from_bytes()`.
//!
//! Token creation:
//!
//! ```rust
//! # use jwt_simple::prelude::*;
//! # fn main() -> Result<(), jwt_simple::Error> {
//! # let key = HS256Key::generate();
//! /// create claims valid for 2 hours
//! let claims = Claims::create(Duration::from_hours(2));
//! let token = key.authenticate(claims)?;
//! # Ok(()) }
//! ```
//!
//! -> Done!
//!
//! ### Token verification
//!
//! ```rust
//! # use jwt_simple::prelude::*;
//! # fn main() -> Result<(), jwt_simple::Error> {
//! # let key = HS256Key::generate();
//! # let token = key.authenticate(Claims::create(Duration::from_secs(10)))?;
//! let claims = key.verify_token::<NoCustomClaims>(&token, None)?;
//! # Ok(()) }
//! ```
//!
//! -> Done! No additional steps required.
//!
//! Key expiration, start time, authentication tags, etc. are automatically
//! verified. The function fails with `JWTError::InvalidAuthenticationTag` if
//! the authentication tag is invalid for the given key.
//!
//! The full set of claims can be inspected in the `claims` object if necessary.
//! `NoCustomClaims` means that only the standard set of claims is used by the
//! application, but application-defined claims can also be supported.
//!
//! Extra verification steps can optionally be enabled via the
//! `ValidationOptions` structure:
//!
//! ```rust
//! # use jwt_simple::prelude::*;
//! # fn main() -> Result<(), jwt_simple::Error> {
//! # let key = HS256Key::generate();
//! # let token = key.authenticate(Claims::create(Duration::from_secs(10)).with_issuer("example app"))?;
//! let mut options = VerificationOptions::default();
//! // Accept tokens that will only be valid in the future
//! options.accept_future = true;
//! // Accept tokens even if they have expired up to 15 minutes after the deadline
//! // and/or they will be valid within 15 minutes.
//! options.time_tolerance = Some(Duration::from_mins(15));
//! // Reject tokens if they were issued more than 1 hour ago
//! options.max_validity = Some(Duration::from_hours(1));
//! // Reject tokens if they don't include an issuer from that list
//! options.allowed_issuers = Some(HashSet::from_strings(&["example app"]));
//! // See the documentation for the full list of available options
//!
//! let claims = key.verify_token::<NoCustomClaims>(&token, Some(options))?;
//! # Ok(()) }
//! ```
//!
//! Note that `allowed_issuers` and `allowed_audiences` are not strings, but
//! sets of strings (using the `HashSet` type from the Rust standard library),
//! as the application can allow multiple return values.
//!
//! ## Signatures (asymmetric, `RS*`, `PS*`, `ES*` and `EdDSA` algorithms) example
//!
//! A signature requires a key pair: a secret key used to create tokens, and a
//! public key, that can only verify them.
//!
//! Always use a signature scheme if both parties do not ultimately trust each
//! other, such as tokens exchanged between clients and API providers.
//!
//! ### Key pairs and tokens creation
//!
//! Key creation:
//!
//! ```rust
//! use jwt_simple::prelude::*;
//!
//! // create a new key pair for the `ES256` JWT algorithm
//! let key_pair = ES256KeyPair::generate();
//!
//! // Or the `ES384` JWT algorithm
//! let key_pair = ES384KeyPair::generate();
//!
//! // a public key can be extracted from a key pair:
//! let public_key = key_pair.public_key();
//! ```
//!
//! Keys can be exported as bytes for later reuse, and imported from bytes or,
//! for RSA, from individual parameters, DER-encoded data or PEM-encoded data.
//!
//! RSA key pair creation, using OpenSSL and PEM importation of the secret key:
//!
//! ```sh
//! openssl genrsa -out private.pem 2048
//! openssl rsa -in private.pem -outform PEM -pubout -out public.pem
//! ```
//!
//! ```no_run
//! # use jwt_simple::prelude::*;
//! # fn main() -> Result<(), jwt_simple::Error> {
//! # let private_pem_file_content = "";
//! # let public_pem_file_content = "";
//! let key_pair = RS384KeyPair::from_pem(private_pem_file_content)?;
//! let public_key = RS384PublicKey::from_pem(public_pem_file_content)?;
//! # Ok(()) }
//! ```
//!
//! Token creation and verification work the same way as with `HS*` algorithms,
//! except that tokens are created with a key pair, and verified using the
//! corresponding public key.
//!
//! Token creation:
//!
//! ```rust
//! # use jwt_simple::prelude::*;
//! # fn main() -> Result<(), jwt_simple::Error> {
//! # let key_pair = Ed25519KeyPair::generate();
//! /// create claims valid for 2 hours
//! let claims = Claims::create(Duration::from_hours(2));
//! let token = key_pair.sign(claims)?;
//! # Ok(()) }
//! ```
//!
//! Token verification:
//!
//! ```rust
//! # use jwt_simple::prelude::*;
//! # fn main() -> Result<(), jwt_simple::Error> {
//! # let key_pair = Ed25519KeyPair::generate();
//! # let public_key = key_pair.public_key();
//! # let token = key_pair.sign(Claims::create(Duration::from_secs(10)))?;
//! let claims = public_key.verify_token::<NoCustomClaims>(&token, None)?;
//! # Ok(()) }
//! ```
//!
//! Available verification options are identical to the ones used with symmetric
//! algorithms.
//!
//! ## Advanced usage
//!
//! ### Custom claims
//!
//! Claim objects support all the standard claims by default, and they can be
//! set directly or via convenient helpers:
//!
//! ```rust
//! # use jwt_simple::prelude::*;
//! let claims = Claims::create(Duration::from_hours(2))
//!     .with_issuer("Example issuer")
//!     .with_subject("Example subject");
//! ```
//!
//! But application-defined claims can also be defined. These simply have to be
//! present in a serializable type (this requires the `serde` crate):
//!
//! ```rust
//! # use jwt_simple::prelude::*;
//! # fn main() -> Result<(), jwt_simple::Error> {
//! #[derive(Serialize, Deserialize)]
//! struct MyAdditionalData {
//!     user_is_admin: bool,
//!     user_country: String,
//! }
//! let my_additional_data = MyAdditionalData {
//!     user_is_admin: false,
//!     user_country: "FR".to_string(),
//! };
//!
//! // Claim creation with custom data:
//!
//! # use jwt_simple::prelude::*;
//! let claims = Claims::with_custom_claims(my_additional_data, Duration::from_secs(30));
//!
//! // Claim verification with custom data. Note the presence of the custom data type:
//!
//! # let key_pair = Ed25519KeyPair::generate();
//! # let public_key = key_pair.public_key();
//! # let token = key_pair.sign(claims)?;
//! let claims = public_key.verify_token::<MyAdditionalData>(&token, None)?;
//! let user_is_admin = claims.custom.user_is_admin;
//! # Ok(()) }
//! ```
//!
//! ### Peeking at metadata before verification
//!
//! Properties such as the key identifier can be useful prior to tag or
//! signature verification in order to pick the right key out of a set.
//!
//! ```rust
//! # use jwt_simple::prelude::*;
//! # fn main() -> Result<(), jwt_simple::Error> {
//! # let token = Ed25519KeyPair::generate().sign(Claims::create(Duration::from_hours(2)))?;
//! let metadata = Token::decode_metadata(&token)?;
//! let key_id = metadata.key_id();
//! let algorithm = metadata.algorithm();
//! // all other standard properties are also accessible
//! # Ok(()) }
//! ```
//!
//! ### Creating and attaching key identifiers
//!
//! Key identifiers indicate to verifiers what public key (or shared key) should
//! be used for verification. They can be attached at any time to existing
//! shared keys, key pairs and public keys:
//!
//! ```rust
//! # use jwt_simple::prelude::*;
//! # let public_key = Ed25519KeyPair::generate().public_key();
//! let public_key_with_id = public_key.with_key_id(&"unique key identifier");
//! ```
//!
//! Instead of delegating this to applications, `jwt-simple` can also create
//! such an identifier for an existing key:
//!
//! ```rust
//! # use jwt_simple::prelude::*;
//! # let mut public_key = Ed25519KeyPair::generate().public_key();
//! let key_id = public_key.create_key_id();
//! ```
//!
//! This creates an text-encoded identifier for the key, attaches it, and
//! returns it.
//!
//! If an identifier has been attached to a shared key or a key pair, tokens
//! created with them will include it.

#![forbid(unsafe_code)]

#[cfg(all(feature = "pure-rust", feature = "optimal"))]
compile_error!("jwt-simple: the `optimal` feature is only available when the `pure-rust` feature is disabled - Consider disabling default Cargo features.");

#[cfg(all(not(feature = "pure-rust"), not(feature = "optimal")))]
compile_error!("jwt-simple: the `optimal` feature is required when the `pure-rust` feature is disabled - Consider enabling default Cargo features.");

pub mod algorithms;
pub mod claims;
pub mod common;
#[cfg(feature = "cwt")]
pub mod cwt_token;
pub mod token;

mod jwt_header;
mod serde_additions;

pub mod reexports {
    pub use anyhow;
    pub use coarsetime;
    pub use ct_codecs;
    pub use rand;
    pub use serde;
    pub use serde_json;
    pub use thiserror;
    pub use zeroize;
}

mod error;
pub use error::{Error, JWTError};

pub mod prelude {
    pub use std::collections::HashSet;

    pub use coarsetime::{self, Clock, Duration, UnixTimeStamp};
    pub use ct_codecs::{
        Base64, Base64NoPadding, Base64UrlSafe, Base64UrlSafeNoPadding, Decoder as _, Encoder as _,
    };
    pub use serde::{Deserialize, Serialize};

    pub use crate::algorithms::*;
    pub use crate::claims::*;
    pub use crate::common::*;
    #[cfg(feature = "cwt")]
    pub use crate::cwt_token::*;
    pub use crate::token::*;

    mod hashset_from_strings {
        use std::collections::HashSet;

        pub trait HashSetFromStringsT {
            /// Create a set from a list of strings
            fn from_strings(strings: &[impl ToString]) -> HashSet<String> {
                strings.iter().map(|x| x.to_string()).collect()
            }
        }

        impl HashSetFromStringsT for HashSet<String> {}
    }

    pub use hashset_from_strings::HashSetFromStringsT as _;
}

#[cfg(test)]
mod tests {
    use crate::prelude::*;

    const RSA_KP_PEM: &str = r"
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAyqq0N5u8Jvl+BLH2VMP/NAv/zY9T8mSq0V2Gk5Ql5H1a+4qi
3viorUXG3AvIEEccpLsW85ps5+I9itp74jllRjA5HG5smbb+Oym0m2Hovfj6qP/1
m1drQg8oth6tNmupNqVzlGGWZLsSCBLuMa3pFaPhoxl9lGU3XJIQ1/evMkOb98I3
hHb4ELn3WGtNlAVkbP20R8sSii/zFjPqrG/NbSPLyAl1ctbG2d8RllQF1uRIqYQj
85yx73hqQCMpYWU3d9QzpkLf/C35/79qNnSKa3t0cyDKinOY7JGIwh8DWAa4pfEz
gg56yLcilYSSohXeaQV0nR8+rm9J8GUYXjPK7wIDAQABAoIBAQCpeRPYyHcPFGTH
4lU9zuQSjtIq/+bP9FRPXWkS8bi6GAVEAUtvLvpGYuoGyidTTVPrgLORo5ncUnjq
KwebRimlBuBLIR/Zboery5VGthoc+h4JwniMnQ6JIAoIOSDZODA5DSPYeb58n15V
uBbNHkOiH/eoHsG/nOAtnctN/cXYPenkCfeLXa3se9EzkcmpNGhqCBL/awtLU17P
Iw7XxsJsRMBOst4Aqiri1GQI8wqjtXWLyfjMpPR8Sqb4UpTDmU1wHhE/w/+2lahC
Tu0/+sCWj7TlafYkT28+4pAMyMqUT6MjqdmGw8lD7/vXv8TF15NU1cUv3QSKpVGe
50vlB1QpAoGBAO1BU1evrNvA91q1bliFjxrH3MzkTQAJRMn9PBX29XwxVG7/HlhX
0tZRSR92ZimT2bAu7tH0Tcl3Bc3NwEQrmqKlIMqiW+1AVYtNjuipIuB7INb/TUM3
smEh+fn3yhMoVxbbh/klR1FapPUFXlpNv3DJHYM+STqLMhl9tEc/I7bLAoGBANqt
zR6Kovf2rh7VK/Qyb2w0rLJE7Zh/WI+r9ubCba46sorqkJclE5cocxWuTy8HWyQp
spxzLP1FQlsI+MESgRLueoH3HtB9lu/pv6/8JlNjU6SzovfUZ0KztVUyUeB4vAcH
pGcf2CkUtoYc8YL22Ybck3s8ThIdnY5zphCF55PtAoGAf46Go3c05XVKx78R05AD
D2/y+0mnSGSzUjHPMzPyadIPxhltlCurlERhnwPGC4aNHFcvWTwS8kUGns6HF1+m
JNnI1okSCW10UI/jTJ1avfwU/OKIBKKWSfi9cDJTt5cRs51V7pKnVEr6sy0uvDhe
u+G091HuhwY9ak0WNtPwfJ8CgYEAuRdoyZQQso7x/Bj0tiHGW7EOB2n+LRiErj6g
odspmNIH8zrtHXF9bnEHT++VCDpSs34ztuZpywnHS2SBoHH4HD0MJlszksbqbbDM
1bk3+1bUIlEF/Hyk1jljn3QTB0tJ4y1dwweaH9NvVn7DENW9cr/aePGnJwA4Lq3G
fq/IPlUCgYAuqgJQ4ztOq0EaB75xgqtErBM57A/+lMWS9eD/euzCEO5UzWVaiIJ+
nNDmx/jvSrxA1Ih8TEHjzv4ezLFYpaJrTst4Mjhtx+csXRJU9a2W6HMXJ4Kdn8rk
PBziuVURslNyLdlFsFlm/kfvX+4Cxrbb+pAGETtRTgmAoCDbvuDGRQ==
-----END RSA PRIVATE KEY-----
    ";

    const RSA_PK_PEM: &str = r"
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyqq0N5u8Jvl+BLH2VMP/
NAv/zY9T8mSq0V2Gk5Ql5H1a+4qi3viorUXG3AvIEEccpLsW85ps5+I9itp74jll
RjA5HG5smbb+Oym0m2Hovfj6qP/1m1drQg8oth6tNmupNqVzlGGWZLsSCBLuMa3p
FaPhoxl9lGU3XJIQ1/evMkOb98I3hHb4ELn3WGtNlAVkbP20R8sSii/zFjPqrG/N
bSPLyAl1ctbG2d8RllQF1uRIqYQj85yx73hqQCMpYWU3d9QzpkLf/C35/79qNnSK
a3t0cyDKinOY7JGIwh8DWAa4pfEzgg56yLcilYSSohXeaQV0nR8+rm9J8GUYXjPK
7wIDAQAB
-----END PUBLIC KEY-----
    ";

    #[test]
    fn hs384() {
        let key = HS384Key::from_bytes(b"your-256-bit-secret").with_key_id("my-key-id");
        let claims = Claims::create(Duration::from_secs(86400)).with_issuer("test issuer");
        let token = key.authenticate(claims).unwrap();
        let options = VerificationOptions {
            allowed_issuers: Some(HashSet::from_strings(&["test issuer"])),
            ..Default::default()
        };
        let _claims = key
            .verify_token::<NoCustomClaims>(&token, Some(options))
            .unwrap();
    }

    #[test]
    fn blake2b() {
        let key = Blake2bKey::from_bytes(b"your-256-bit-secret").with_key_id("my-key-id");
        let claims = Claims::create(Duration::from_secs(86400)).with_issuer("test issuer");
        let token = key.authenticate(claims).unwrap();
        let options = VerificationOptions {
            allowed_issuers: Some(HashSet::from_strings(&["test issuer"])),
            ..Default::default()
        };
        let _claims = key
            .verify_token::<NoCustomClaims>(&token, Some(options))
            .unwrap();
    }

    #[test]
    fn rs256() {
        let key_pair = RS256KeyPair::from_pem(RSA_KP_PEM).unwrap();
        let claims = Claims::create(Duration::from_secs(86400));
        let token = key_pair.sign(claims).unwrap();
        let pk = RS256PublicKey::from_pem(RSA_PK_PEM).unwrap();
        let _claims = pk.verify_token::<NoCustomClaims>(&token, None).unwrap();
        let components = pk.to_components();
        let hex_e = Base64::encode_to_string(components.e).unwrap();
        let _e = Base64::decode_to_vec(hex_e, None).unwrap();
    }

    #[test]
    fn ps384() {
        let key_pair = PS384KeyPair::generate(2048).unwrap();
        let claims = Claims::create(Duration::from_secs(86400));
        let token = key_pair.sign(claims).unwrap();
        let _claims = key_pair
            .public_key()
            .verify_token::<NoCustomClaims>(&token, None)
            .unwrap();
    }

    #[test]
    fn es256() {
        let key_pair = ES256KeyPair::generate();
        let claims = Claims::create(Duration::from_secs(86400));
        let token = key_pair.sign(claims).unwrap();
        let _claims = key_pair
            .public_key()
            .verify_token::<NoCustomClaims>(&token, None)
            .unwrap();
    }

    #[test]
    fn es384() {
        let key_pair = ES384KeyPair::generate();
        let claims = Claims::create(Duration::from_secs(86400));
        let token = key_pair.sign(claims).unwrap();
        let _claims = key_pair
            .public_key()
            .verify_token::<NoCustomClaims>(&token, None)
            .unwrap();
    }

    #[test]
    fn es256k() {
        let key_pair = ES256kKeyPair::generate();
        let claims = Claims::create(Duration::from_secs(86400));
        let token = key_pair.sign(claims).unwrap();
        let _claims = key_pair
            .public_key()
            .verify_token::<NoCustomClaims>(&token, None)
            .unwrap();
    }

    #[test]
    fn ed25519() {
        #[derive(Serialize, Deserialize)]
        struct CustomClaims {
            is_custom: bool,
        }

        let key_pair = Ed25519KeyPair::generate();
        let mut pk = key_pair.public_key();
        let key_id = pk.create_key_id();
        let key_pair = key_pair.with_key_id(key_id);
        let custom_claims = CustomClaims { is_custom: true };
        let claims = Claims::with_custom_claims(custom_claims, Duration::from_secs(86400));
        let token = key_pair.sign(claims).unwrap();
        let options = VerificationOptions {
            required_key_id: Some(key_id.to_string()),
            ..Default::default()
        };
        let claims: JWTClaims<CustomClaims> = key_pair
            .public_key()
            .verify_token::<CustomClaims>(&token, Some(options))
            .unwrap();
        assert!(claims.custom.is_custom);
    }

    #[test]
    fn ed25519_der() {
        let key_pair = Ed25519KeyPair::generate();
        let der = key_pair.to_der();
        let key_pair2 = Ed25519KeyPair::from_der(&der).unwrap();
        assert_eq!(key_pair.to_bytes(), key_pair2.to_bytes());
    }

    #[test]
    fn require_nonce() {
        let key = HS256Key::generate();
        let mut claims = Claims::create(Duration::from_hours(1));
        let nonce = claims.create_nonce();
        let token = key.authenticate(claims).unwrap();

        let options = VerificationOptions {
            required_nonce: Some(nonce),
            ..Default::default()
        };
        key.verify_token::<NoCustomClaims>(&token, Some(options))
            .unwrap();
    }

    #[test]
    fn eddsa_pem() {
        let sk_pem = "-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIMXY1NUbUe/3dW2YUoKW5evsnCJPMfj60/q0RzGne3gg
-----END PRIVATE KEY-----\n";
        let pk_pem = "-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAyrRjJfTnhMcW5igzYvPirFW5eUgMdKeClGzQhd4qw+Y=
-----END PUBLIC KEY-----\n";
        let kp = Ed25519KeyPair::from_pem(sk_pem).unwrap();
        assert_eq!(kp.public_key().to_pem(), pk_pem);
    }

    #[test]
    fn key_metadata() {
        let mut key_pair = Ed25519KeyPair::generate();
        let thumbprint = key_pair.public_key().sha1_thumbprint();
        let key_metadata = KeyMetadata::default()
            .with_certificate_sha1_thumbprint(&thumbprint)
            .unwrap();
        key_pair.attach_metadata(key_metadata).unwrap();

        let claims = Claims::create(Duration::from_secs(86400));
        let token = key_pair.sign(claims).unwrap();

        let decoded_metadata = Token::decode_metadata(&token).unwrap();
        assert_eq!(
            decoded_metadata.certificate_sha1_thumbprint(),
            Some(thumbprint.as_ref())
        );
        let _ = key_pair
            .public_key()
            .verify_token::<NoCustomClaims>(&token, None)
            .unwrap();
    }

    #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
    #[test]
    fn expired_token() {
        let key = HS256Key::generate();
        let claims = Claims::create(Duration::from_secs(1));
        let token = key.authenticate(claims).unwrap();
        std::thread::sleep(std::time::Duration::from_secs(2));
        let options = VerificationOptions {
            time_tolerance: None,
            ..Default::default()
        };
        let claims = key.verify_token::<NoCustomClaims>(&token, None);
        assert!(claims.is_ok());
        let claims = key.verify_token::<NoCustomClaims>(&token, Some(options));
        assert!(claims.is_err());
    }
}