jwt_simple/
lib.rs

1//! [![GitHub CI](https://github.com/jedisct1/rust-jwt-simple/workflows/Rust/badge.svg)](https://github.com/jedisct1/rust-jwt-simple/actions)
2//! [![Docs.rs](https://docs.rs/jwt-simple/badge.svg)](https://docs.rs/jwt-simple/)
3//! [![crates.io](https://img.shields.io/crates/v/jwt-simple.svg)](https://crates.io/crates/jwt-simple)
4//!
5//! <!-- @import "[TOC]" {cmd="toc" depthFrom=1 depthTo=6 orderedList=false} -->
6//!
7//! <!-- code_chunk_output -->
8//!
9//! - [JWT-Simple](#jwt-simple)
10//! - [Usage](#usage)
11//! - [Authentication (symmetric, `HS*` JWT algorithms) example](#authentication-symmetric-hs-jwt-algorithms-example)
12//! - [Keys and tokens creation](#keys-and-tokens-creation)
13//! - [Token verification](#token-verification)
14//! - [Signatures (asymmetric, `RS*`, `PS*`, `ES*` and `EdDSA` algorithms) example](#signatures-asymmetric-rs-ps-es-and-eddsa-algorithms-example)
15//! - [Key pairs and tokens creation](#key-pairs-and-tokens-creation)
16//! - [ES256](#es256)
17//! - [ES384](#es384)
18//! - [Advanced usage](#advanced-usage)
19//! - [Custom claims](#custom-claims)
20//! - [Peeking at metadata before verification](#peeking-at-metadata-before-verification)
21//! - [Creating and attaching key identifiers](#creating-and-attaching-key-identifiers)
22//! - [Mitigations against replay attacks](#mitigations-against-replay-attacks)
23//! - [CWT (CBOR) support](#cwt-cbor-support)
24//! - [Working around compilation issues with the `boring` crate](#working-around-compilation-issues-with-the-boring-crate)
25//! - [Usage in Web browsers](#usage-in-web-browsers)
26//! - [Why yet another JWT crate](#why-yet-another-jwt-crate)
27//!
28//! <!-- /code_chunk_output -->
29//!
30//! # JWT-Simple
31//!
32//! A new JWT (JSON Web Tokens) implementation for Rust that focuses on simplicity, while avoiding common JWT security pitfalls.
33//!
34//! `jwt-simple` is unopinionated and supports all commonly deployed authentication and signature algorithms:
35//!
36//! | JWT algorithm name | Description                           |
37//! | ------------------ | ------------------------------------- |
38//! | `HS256`            | HMAC-SHA-256                          |
39//! | `HS384`            | HMAC-SHA-384                          |
40//! | `HS512`            | HMAC-SHA-512                          |
41//! | `BLAKE2B`          | BLAKE2B-256                           |
42//! | `RS256`            | RSA with PKCS#1v1.5 padding / SHA-256 |
43//! | `RS384`            | RSA with PKCS#1v1.5 padding / SHA-384 |
44//! | `RS512`            | RSA with PKCS#1v1.5 padding / SHA-512 |
45//! | `PS256`            | RSA with PSS padding / SHA-256        |
46//! | `PS384`            | RSA with PSS padding / SHA-384        |
47//! | `PS512`            | RSA with PSS padding / SHA-512        |
48//! | `ES256`            | ECDSA over p256 / SHA-256             |
49//! | `ES384`            | ECDSA over p384 / SHA-384             |
50//! | `ES256K`           | ECDSA over secp256k1 / SHA-256        |
51//! | `EdDSA`            | Ed25519                               |
52//!
53//! `jwt-simple` can be compiled out of the box to WebAssembly/WASI. It is fully compatible with Fastly _Compute_ service.
54//!
55//! 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.
56//!
57//! ## Usage
58//!
59//! `cargo.toml`:
60//!
61//! ```toml
62//! [dependencies]
63//! jwt-simple = "0.12"
64//! ```
65//!
66//! Rust:
67//!
68//! ```rust
69//! use jwt_simple::prelude::*;
70//! ```
71//!
72//! Errors are returned as `jwt_simple::Error` values (alias for the `Error` type of the `thiserror` crate).
73//!
74//! ## Authentication (symmetric, `HS*` JWT algorithms) example
75//!
76//! 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.
77//!
78//! ### Keys and tokens creation
79//!
80//! Key creation:
81//!
82//! ```rust
83//! use jwt_simple::prelude::*;
84//!
85//! // create a new key for the `HS256` JWT algorithm
86//! let key = HS256Key::generate();
87//! ```
88//!
89//! A key can be exported as bytes with `key.to_bytes()`, and restored with `HS256Key::from_bytes()`.
90//!
91//! Token creation:
92//!
93//! ```rust
94//! # use jwt_simple::prelude::*;
95//! # fn main() -> Result<(), jwt_simple::Error> {
96//! # let key = HS256Key::generate();
97//! /// create claims valid for 2 hours
98//! let claims = Claims::create(Duration::from_hours(2));
99//! let token = key.authenticate(claims)?;
100//! # Ok(())
101//! # }
102//! ```
103//!
104//! -> Done!
105//!
106//! ### Token verification
107//!
108//! ```rust
109//! # use jwt_simple::prelude::*;
110//! # fn main() -> Result<(), jwt_simple::Error> {
111//! # let key = HS256Key::generate();
112//! # let claims = Claims::create(Duration::from_hours(2));
113//! # let token = key.authenticate(claims)?;
114//! let claims = key.verify_token::<NoCustomClaims>(&token, None)?;
115//! # Ok(())
116//! # }
117//! ```
118//!
119//! -> Done! No additional steps required.
120//!
121//! 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.
122//!
123//! 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.
124//!
125//! Extra verification steps can optionally be enabled via the `ValidationOptions` structure:
126//!
127//! ```rust
128//! # use jwt_simple::prelude::*;
129//! # fn xmain() -> Result<(), jwt_simple::Error> {
130//! # let key = HS256Key::generate();
131//! # let claims = Claims::create(Duration::from_hours(2));
132//! # let token = key.authenticate(claims)?;
133//! let mut options = VerificationOptions::default();
134//! // Accept tokens that will only be valid in the future
135//! options.accept_future = true;
136//! // Accept tokens even if they have expired up to 15 minutes after the deadline,
137//! // and/or they will be valid within 15 minutes.
138//! // Note that 15 minutes is the default, since it is very common for clocks to be slightly off.
139//! options.time_tolerance = Some(Duration::from_mins(15));
140//! // Reject tokens if they were issued more than 1 hour ago
141//! options.max_validity = Some(Duration::from_hours(1));
142//! // Reject tokens if they don't include an issuer from that set
143//! options.allowed_issuers = Some(HashSet::from_strings(&["example app"]));
144//!
145//! // see the documentation for the full list of available options
146//!
147//! let claims = key.verify_token::<NoCustomClaims>(&token, Some(options))?;
148//! # Ok(())
149//! # }
150//! # fn main() { xmain().ok(); }
151//! ```
152//!
153//! 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.
154//!
155//! ## Signatures (asymmetric, `RS*`, `PS*`, `ES*` and `EdDSA` algorithms) example
156//!
157//! A signature requires a key pair: a secret key used to create tokens, and a public key, that can only verify them.
158//!
159//! Always use a signature scheme if both parties do not ultimately trust each other, such as tokens exchanged between clients and API providers.
160//!
161//! ### Key pairs and tokens creation
162//!
163//! Key creation:
164//!
165//! #### ES256
166//!
167//! ```rust
168//! use jwt_simple::prelude::*;
169//!
170//! // create a new key pair for the `ES256` JWT algorithm
171//! let key_pair = ES256KeyPair::generate();
172//!
173//! // a public key can be extracted from a key pair:
174//! let public_key = key_pair.public_key();
175//! ```
176//!
177//! #### ES384
178//!
179//! ```rust
180//! use jwt_simple::prelude::*;
181//!
182//! // create a new key pair for the `ES384` JWT algorithm
183//! let key_pair = ES384KeyPair::generate();
184//!
185//! // a public key can be extracted from a key pair:
186//! let public_key = key_pair.public_key();
187//! ```
188//!
189//! 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.
190//!
191//! RSA key pair creation, using OpenSSL and PEM importation of the secret key:
192//!
193//! ```sh
194//! openssl genrsa -out private.pem 2048
195//! openssl rsa -in private.pem -outform PEM -pubout -out public.pem
196//! ```
197//!
198//! ```rust
199//! # use jwt_simple::prelude::*;
200//! # fn xmain() -> Result<(), jwt_simple::Error> {
201//! # let private_pem_file_content = "test";
202//! # let public_pem_file_content = "test";
203//! let key_pair = RS384KeyPair::from_pem(private_pem_file_content)?;
204//! let public_key = RS384PublicKey::from_pem(public_pem_file_content)?;
205//! # Ok(())
206//! # }
207//! # fn main() { xmain().ok(); }
208//! ```
209//!
210//! 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.
211//!
212//! Token creation:
213//!
214//! ```rust
215//! # use jwt_simple::prelude::*;
216//! # fn xmain() -> Result<(), jwt_simple::Error> {
217//! # let private_pem_file_content = "test";
218//! # let key_pair = RS384KeyPair::from_pem(private_pem_file_content)?;
219//! /// create claims valid for 2 hours
220//! let claims = Claims::create(Duration::from_hours(2));
221//! let token = key_pair.sign(claims)?;
222//! # Ok(())
223//! # }
224//! # fn main() { xmain().ok(); }
225//! ```
226//!
227//! Token verification:
228//!
229//! ```rust
230//! # use jwt_simple::prelude::*;
231//! # fn xmain() -> Result<(), jwt_simple::Error> {
232//! # let private_pem_file_content = "test";
233//! # let public_pem_file_content = "test";
234//! # let key_pair = RS384KeyPair::from_pem(private_pem_file_content)?;
235//! # let public_key = RS384PublicKey::from_pem(public_pem_file_content)?;
236//! # let claims = Claims::create(Duration::from_hours(2));
237//! # let token = key_pair.sign(claims)?;
238//! let claims = public_key.verify_token::<NoCustomClaims>(&token, None)?;
239//! # Ok(())
240//! # }
241//! # fn main() { xmain().ok(); }
242//! ```
243//!
244//! Available verification options are identical to the ones used with symmetric algorithms.
245//!
246//! ## Advanced usage
247//!
248//! ### Custom claims
249//!
250//! Claim objects support all the standard claims by default, and they can be set directly or via convenient helpers:
251//!
252//! ```rust
253//! # use jwt_simple::prelude::*;
254//! let claims = Claims::create(Duration::from_hours(2)).
255//! with_issuer("Example issuer").with_subject("Example subject");
256//! ```
257//!
258//! But application-defined claims can also be defined. These simply have to be present in a serializable type (this requires the `serde` crate):
259//!
260//! ```rust
261//! # use jwt_simple::prelude::*;
262//! # use serde::{de::DeserializeOwned, Serialize};
263//! #[derive(Serialize, Deserialize)]
264//! struct MyAdditionalData {
265//! user_is_admin: bool,
266//! user_country: String,
267//! }
268//! let my_additional_data = MyAdditionalData {
269//! user_is_admin: false,
270//! user_country: "FR".to_string(),
271//! };
272//! ```
273//!
274//! Claim creation with custom data:
275//!
276//! ```rust
277//! # use jwt_simple::prelude::*;
278//! # use serde::{de::DeserializeOwned, Serialize};
279//! # #[derive(Serialize, Deserialize)]
280//! # struct MyAdditionalData {user_is_admin: bool}
281//! # fn main() -> Result<(), jwt_simple::Error> {
282//! # let my_additional_data = MyAdditionalData {user_is_admin: false};
283//! let claims = Claims::with_custom_claims(my_additional_data, Duration::from_secs(30));
284//! # Ok(())
285//! # }
286//! ```
287//!
288//! Claim verification with custom data. Note the presence of the custom data type:
289//!
290//! ```rust
291//! # use jwt_simple::prelude::*;
292//! # use serde::{de::DeserializeOwned, Serialize};
293//! # #[derive(Serialize, Deserialize)]
294//! # struct MyAdditionalData {user_is_admin: bool}
295//! # fn xmain() -> Result<(), jwt_simple::Error> {
296//! # let kp = Ed25519KeyPair::generate();
297//! # let claims = Claims::create(Duration::from_secs(86400));
298//! # let token = kp.sign(claims)?;
299//! # let public_key = kp.public_key();
300//! let claims = public_key.verify_token::<MyAdditionalData>(&token, None)?;
301//! let user_is_admin = claims.custom.user_is_admin;
302//! # Ok(())
303//! # }
304//! # fn main() { xmain().ok(); }
305//! ```
306//!
307//! ### Peeking at metadata before verification
308//!
309//! 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.
310//!
311//! ```rust
312//! # use jwt_simple::prelude::*;
313//! # fn main() -> Result<(), jwt_simple::Error> {
314//! # let key = RS384KeyPair::generate(3072)?;
315//! # let claims = Claims::create(Duration::from_secs(86400));
316//! # let token = key.sign(claims)?;
317//! let metadata = Token::decode_metadata(&token)?;
318//! let key_id = metadata.key_id();
319//! let algorithm = metadata.algorithm();
320//! // all other standard properties are also accessible
321//! # Ok(())
322//! # }
323//! ```
324//!
325//! **IMPORTANT:** neither the key ID nor the algorithm can be trusted. This is an unfixable design flaw of the JWT standard.
326//!
327//! As a result, `algorithm` should be used only for debugging purposes, and never to select a key type.
328//! Similarly, `key_id` should be used only to select a key in a set of keys made for the same algorithm.
329//!
330//! At the bare minimum, verification using `HS*` must be prohibited if a signature scheme was originally used to create the token.
331//!
332//! ### Creating and attaching key identifiers
333//!
334//! Key identifiers indicate to verifiers what public key (or shared key) should be used for verification.
335//! They can be attached at any time to existing shared keys, key pairs and public keys:
336//!
337//! ```rust
338//! # use jwt_simple::prelude::*;
339//! # let public_key = Ed25519KeyPair::generate().public_key();
340//! let public_key_with_id = public_key.with_key_id(&"unique key identifier");
341//! ```
342//!
343//! Instead of delegating this to applications, `jwt-simple` can also create such an identifier for an existing key:
344//!
345//! ```rust
346//! # use jwt_simple::prelude::*;
347//! # let mut public_key = Ed25519KeyPair::generate().public_key();
348//! let key_id = public_key.create_key_id();
349//! ```
350//!
351//! This creates a text-encoded identifier for the key, attaches it, and returns it.
352//!
353//! If an identifier has been attached to a shared key or a key pair, tokens created with them will include it.
354//!
355//! ### Mitigations against replay attacks
356//!
357//! `jwt-simple` includes mechanisms to mitigate replay attacks:
358//!
359//! - Nonces can be created and attached to new tokens using the `create_nonce()` claim function. The verification procedure can later reject any token that doesn't include the expected nonce (`required_nonce` verification option).
360//! - The verification procedure can reject tokens created too long ago, no matter what their expiration date is. This prevents tokens from malicious (or compromised) signers from being used for too long.
361//! - The verification procedure can reject tokens created before a date. For a given user, the date of the last successful authentication can be stored in a database, and used later along with this option to reject older (replayed) tokens.
362//!
363//! ### Salted keys
364//!
365//! Symmetric keys, such as the ones used with the `HS256`, `HS384`, `HS512` and `BLAKE2B` algorithms, are simple and fast, but have a major downside: signature and verification use the exact same key. Therefore, an adversary having access to the verifier key can forge arbitrary, valid tokens.
366//!
367//! Salted keys mitigate this issue in the following way:
368//!
369//! - A random signer salt is created and attached to the shared key. This salt is meant to be known only by the signer.
370//! - Another salt is computed from the signer salt and is meant to be used for verification.
371//! - The verifier salt is used to verify the signer salt, which is included in tokens in the `salt` JWT header.
372//!
373//! If the verifier has access to tokens, it can forge arbitrary tokens. But given only the verification code and keys, this is impossible. This greatly improves the security of symmetric keys used for verification on 3rd party servers, such as CDNs.
374//!
375//! A salt binds to a key, and can be of any length. The `generate_with_salt()` function generates both a random symmetric key, and a 32-byte salt.
376//!
377//! Example usage:
378//!
379//! ```rust
380//! /// Create a random key and a signer salt
381//! # use jwt_simple::prelude::*;
382//! # fn main() -> Result<(), jwt_simple::Error> {
383//! let key = HS256Key::generate_with_salt();
384//! let claims = Claims::create(Duration::from_secs(86400));
385//! let token = key.authenticate(claims).unwrap();
386//! # Ok(())
387//! # }
388//! ```
389//!
390//! A salt is a `Salt` enum, because it can be either a salt for signing, or a salt for verification.
391//! It can be saved and restored:
392//!
393//! ```rust
394//! # use jwt_simple::prelude::*;
395//! # fn main() -> Result<(), jwt_simple::Error> {
396//! let mut key = HS256Key::generate_with_salt();
397//! /// Get the salt
398//! let salt = key.salt();
399//! /// Attach an existing salt to a key
400//! key.attach_salt(salt)?;
401//! # Ok(())
402//! # }
403//! ```
404//!
405//! Given a signer salt, the corresponding verifier salt can be computed:
406//!
407//! ```rust
408//! # use jwt_simple::prelude::*;
409//! # fn main() -> Result<(), jwt_simple::Error> {
410//! # let key = HS256Key::generate_with_salt();
411//! /// Compute the verifier salt, given a signer salt
412//! let verifier_salt = key.verifier_salt()?;
413//! # Ok(())
414//! # }
415//! ```
416//!
417//! The verifier salt doesn't have to be secret, and can even be hard-coded in the verification code.
418//!
419//! Verification:
420//!
421//! ```rust
422//! # use jwt_simple::prelude::*;
423//! # fn xmain() -> Result<(), jwt_simple::Error> {
424//! # let verifier_salt_bytes = b"verifier salt".to_vec();
425//! # let mut key = HS256Key::generate_with_salt();
426//! # let claims = Claims::create(Duration::from_secs(86400));
427//! # let token = key.authenticate(claims)?;
428//! let verifier_salt = Salt::Verifier(verifier_salt_bytes);
429//! key.attach_salt(verifier_salt)?;
430//! let claims = key.verify_token::<NoCustomClaims>(&token, None)?;
431//! # Ok(())
432//! # }
433//! # fn main() { xmain().ok(); }
434//! ```
435//!
436//! ### CWT (CBOR) support
437//!
438//! The development code includes a `cwt` cargo feature that enables experimental parsing and validation of CWT tokens.
439//!
440//! Please note that CWT doesn't support custom claims. The required identifiers [haven't been standardized yet](https://www.iana.org/assignments/cwt/cwt.xhtml).
441//!
442//! Also, the existing Rust crates for JSON and CBOR deserialization are not safe. An untrusted party can send a serialized object that requires a lot of memory and CPU to deserialize. Band-aids have been added for JSON, but with the current Rust tooling, it would be tricky to do for CBOR.
443//!
444//! As a mitigation, we highly recommend rejecting tokens that would be too large in the context of your application. That can be done by with the `max_token_length` verification option.
445//!
446//!
447//! ### Specifying header options
448//!
449//! It is possible to change the content type (`cty`) and signature type (`typ`) fields of a signed JWT by using the `sign_with_options`/`authenticate_with_options` functions, passing in a `HeaderOptions` struct:
450//!
451//! ```rust
452//! # use jwt_simple::prelude::*;
453//! # let mut key_pair = Ed25519KeyPair::generate();
454//! # let claims = Claims::create(Duration::from_secs(86400));
455//! let options = HeaderOptions {
456//!    content_type: Some("foo".into()),
457//!    signature_type: Some("foo+JWT".into()),
458//!    ..Default::default()
459//! };
460//! key_pair.sign_with_options(claims, &options).unwrap();
461//! ```
462//! By default, generated JWTs will have a signature type field containing the string "JWT", and the content type field will not be present.
463//!
464//! ### Validating content and signature types
465//!
466//! By default, `jwt_simple` ignores the `content_type` field when doing validation, and checks `signature_type` to ensure it is either exactly `JWT` or ends in `+JWT`, case insensitive, if it is present. Both fields may instead be case-insensitively compared against an expected string:
467//!
468//! ```rust
469//! # use jwt_simple::prelude::*;
470//! # let mut options = VerificationOptions::default();
471//! options.required_signature_type = Some("JWT".into());
472//! options.required_content_type = Some("foo+jwt".into());
473//! ```
474//!
475//! When validating CWTs, note that CWTs do not have a `content_type` field in their header, and therefore attempting to match a specific one by setting `required_content_type` during validation will **always result in an error**.
476//!
477//! ## Working around compilation issues with the `boring` crate
478//!
479//! As a temporary workaround for portability issues with one of the dependencies (the `boring` crate), this library can be compiled to use only Rust implementations.
480//!
481//! In order to do so, import the crate with `default-features=false, features=["pure-rust"]` in your Cargo configuration.
482//!
483//! Do not do it unconditionally. This is only required for very specific setups and targets, and only until issues with the `boring` crate have been solved. The way to configure this in Cargo may also change in future versions.
484//!
485//! Static builds targeting the `musl` library don't require that workaround. Just use [`cargo-zigbuild`](https://github.com/rust-cross/cargo-zigbuild) to build your project.
486//!
487//! ## Usage in Web browsers
488//!
489//! The `wasm32-freestanding` target (still sometimes called `wasm32-unknown-unknown` in Rust) is supported (as in "it compiles").
490//!
491//! However, using a native JavaScript implementation is highly recommended instead. There are high-quality JWT implementations in JavaScript, leveraging the WebCrypto API, that provide better performance and security guarantees than a WebAssembly module.
492//!
493//! ## Why yet another JWT crate
494//!
495//! This crate is not an endorsement of JWT. JWT is [an awful design](https://tools.ietf.org/html/rfc8725), and one of the many examples that "but this is a standard" doesn't necessarily mean that it is good.
496//!
497//! I would highly recommend [PASETO](https://github.com/paragonie/paseto) or [Biscuit](https://github.com/CleverCloud/biscuit) instead if you control both token creation and verification.
498//!
499//! However, JWT is still widely used in the industry, and remains absolutely mandatory to communicate with popular APIs.
500//!
501//! This crate was designed to:
502//!
503//! - Be simple to use, even to people who are new to Rust
504//! - Avoid common JWT API pitfalls
505//! - Support features widely in use. I'd love to limit the algorithm choices to Ed25519, but other methods are required to connect to existing APIs, so just provide them (with the exception of the `None` signature method for obvious reasons).
506//! - Minimize code complexity and external dependencies
507//! - Automatically perform common tasks to prevent misuse. Signature verification and claims validation happen automatically instead of relying on applications.
508//! - Still allow power users to access everything JWT tokens include if they really need to
509//! - Work out of the box in a WebAssembly environment, so that it can be used in function-as-a-service platforms.
510
511#![forbid(unsafe_code)]
512
513#[cfg(all(feature = "pure-rust", feature = "optimal"))]
514compile_error!("jwt-simple: the `optimal` feature is only available when the `pure-rust` feature is disabled - Consider disabling default Cargo features.");
515
516#[cfg(all(not(feature = "pure-rust"), not(feature = "optimal")))]
517compile_error!("jwt-simple: the `optimal` feature is required when the `pure-rust` feature is disabled - Consider enabling default Cargo features.");
518
519pub mod algorithms;
520pub mod claims;
521pub mod common;
522#[cfg(feature = "cwt")]
523pub mod cwt_token;
524pub mod token;
525
526mod jwt_header;
527mod serde_additions;
528
529pub mod reexports {
530    pub use anyhow;
531    pub use coarsetime;
532    pub use ct_codecs;
533    pub use rand;
534    pub use serde;
535    pub use serde_json;
536    pub use thiserror;
537    pub use zeroize;
538}
539
540mod error;
541pub use error::{Error, JWTError};
542
543pub mod prelude {
544    pub use std::collections::HashSet;
545
546    pub use coarsetime::{self, Clock, Duration, UnixTimeStamp};
547    pub use ct_codecs::{
548        Base64, Base64NoPadding, Base64UrlSafe, Base64UrlSafeNoPadding, Decoder as _, Encoder as _,
549    };
550    pub use serde::{Deserialize, Serialize};
551
552    pub use crate::algorithms::*;
553    pub use crate::claims::*;
554    pub use crate::common::*;
555    #[cfg(feature = "cwt")]
556    pub use crate::cwt_token::*;
557    pub use crate::token::*;
558
559    mod hashset_from_strings {
560        use std::collections::HashSet;
561
562        pub trait HashSetFromStringsT {
563            /// Create a set from a list of strings
564            fn from_strings(strings: &[impl ToString]) -> HashSet<String> {
565                strings.iter().map(|x| x.to_string()).collect()
566            }
567        }
568
569        impl HashSetFromStringsT for HashSet<String> {}
570    }
571
572    pub use hashset_from_strings::HashSetFromStringsT as _;
573}
574
575#[cfg(test)]
576mod tests {
577    use crate::prelude::*;
578
579    const RSA_KP_PEM: &str = r"
580-----BEGIN RSA PRIVATE KEY-----
581MIIEpAIBAAKCAQEAyqq0N5u8Jvl+BLH2VMP/NAv/zY9T8mSq0V2Gk5Ql5H1a+4qi
5823viorUXG3AvIEEccpLsW85ps5+I9itp74jllRjA5HG5smbb+Oym0m2Hovfj6qP/1
583m1drQg8oth6tNmupNqVzlGGWZLsSCBLuMa3pFaPhoxl9lGU3XJIQ1/evMkOb98I3
584hHb4ELn3WGtNlAVkbP20R8sSii/zFjPqrG/NbSPLyAl1ctbG2d8RllQF1uRIqYQj
58585yx73hqQCMpYWU3d9QzpkLf/C35/79qNnSKa3t0cyDKinOY7JGIwh8DWAa4pfEz
586gg56yLcilYSSohXeaQV0nR8+rm9J8GUYXjPK7wIDAQABAoIBAQCpeRPYyHcPFGTH
5874lU9zuQSjtIq/+bP9FRPXWkS8bi6GAVEAUtvLvpGYuoGyidTTVPrgLORo5ncUnjq
588KwebRimlBuBLIR/Zboery5VGthoc+h4JwniMnQ6JIAoIOSDZODA5DSPYeb58n15V
589uBbNHkOiH/eoHsG/nOAtnctN/cXYPenkCfeLXa3se9EzkcmpNGhqCBL/awtLU17P
590Iw7XxsJsRMBOst4Aqiri1GQI8wqjtXWLyfjMpPR8Sqb4UpTDmU1wHhE/w/+2lahC
591Tu0/+sCWj7TlafYkT28+4pAMyMqUT6MjqdmGw8lD7/vXv8TF15NU1cUv3QSKpVGe
59250vlB1QpAoGBAO1BU1evrNvA91q1bliFjxrH3MzkTQAJRMn9PBX29XwxVG7/HlhX
5930tZRSR92ZimT2bAu7tH0Tcl3Bc3NwEQrmqKlIMqiW+1AVYtNjuipIuB7INb/TUM3
594smEh+fn3yhMoVxbbh/klR1FapPUFXlpNv3DJHYM+STqLMhl9tEc/I7bLAoGBANqt
595zR6Kovf2rh7VK/Qyb2w0rLJE7Zh/WI+r9ubCba46sorqkJclE5cocxWuTy8HWyQp
596spxzLP1FQlsI+MESgRLueoH3HtB9lu/pv6/8JlNjU6SzovfUZ0KztVUyUeB4vAcH
597pGcf2CkUtoYc8YL22Ybck3s8ThIdnY5zphCF55PtAoGAf46Go3c05XVKx78R05AD
598D2/y+0mnSGSzUjHPMzPyadIPxhltlCurlERhnwPGC4aNHFcvWTwS8kUGns6HF1+m
599JNnI1okSCW10UI/jTJ1avfwU/OKIBKKWSfi9cDJTt5cRs51V7pKnVEr6sy0uvDhe
600u+G091HuhwY9ak0WNtPwfJ8CgYEAuRdoyZQQso7x/Bj0tiHGW7EOB2n+LRiErj6g
601odspmNIH8zrtHXF9bnEHT++VCDpSs34ztuZpywnHS2SBoHH4HD0MJlszksbqbbDM
6021bk3+1bUIlEF/Hyk1jljn3QTB0tJ4y1dwweaH9NvVn7DENW9cr/aePGnJwA4Lq3G
603fq/IPlUCgYAuqgJQ4ztOq0EaB75xgqtErBM57A/+lMWS9eD/euzCEO5UzWVaiIJ+
604nNDmx/jvSrxA1Ih8TEHjzv4ezLFYpaJrTst4Mjhtx+csXRJU9a2W6HMXJ4Kdn8rk
605PBziuVURslNyLdlFsFlm/kfvX+4Cxrbb+pAGETtRTgmAoCDbvuDGRQ==
606-----END RSA PRIVATE KEY-----
607    ";
608
609    const RSA_PK_PEM: &str = r"
610-----BEGIN PUBLIC KEY-----
611MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyqq0N5u8Jvl+BLH2VMP/
612NAv/zY9T8mSq0V2Gk5Ql5H1a+4qi3viorUXG3AvIEEccpLsW85ps5+I9itp74jll
613RjA5HG5smbb+Oym0m2Hovfj6qP/1m1drQg8oth6tNmupNqVzlGGWZLsSCBLuMa3p
614FaPhoxl9lGU3XJIQ1/evMkOb98I3hHb4ELn3WGtNlAVkbP20R8sSii/zFjPqrG/N
615bSPLyAl1ctbG2d8RllQF1uRIqYQj85yx73hqQCMpYWU3d9QzpkLf/C35/79qNnSK
616a3t0cyDKinOY7JGIwh8DWAa4pfEzgg56yLcilYSSohXeaQV0nR8+rm9J8GUYXjPK
6177wIDAQAB
618-----END PUBLIC KEY-----
619    ";
620
621    #[test]
622    fn hs384() {
623        let key = HS384Key::from_bytes(b"your-256-bit-secret").with_key_id("my-key-id");
624        let claims = Claims::create(Duration::from_secs(86400)).with_issuer("test issuer");
625        let token = key.authenticate(claims).unwrap();
626        let options = VerificationOptions {
627            allowed_issuers: Some(HashSet::from_strings(&["test issuer"])),
628            ..Default::default()
629        };
630        let _claims = key
631            .verify_token::<NoCustomClaims>(&token, Some(options))
632            .unwrap();
633    }
634
635    #[test]
636    fn blake2b() {
637        let key = Blake2bKey::from_bytes(b"your-256-bit-secret").with_key_id("my-key-id");
638        let claims = Claims::create(Duration::from_secs(86400)).with_issuer("test issuer");
639        let token = key.authenticate(claims).unwrap();
640        let options = VerificationOptions {
641            allowed_issuers: Some(HashSet::from_strings(&["test issuer"])),
642            ..Default::default()
643        };
644        let _claims = key
645            .verify_token::<NoCustomClaims>(&token, Some(options))
646            .unwrap();
647    }
648
649    #[test]
650    fn rs256() {
651        let key_pair = RS256KeyPair::from_pem(RSA_KP_PEM).unwrap();
652        let claims = Claims::create(Duration::from_secs(86400));
653        let token = key_pair.sign(claims).unwrap();
654        let pk = RS256PublicKey::from_pem(RSA_PK_PEM).unwrap();
655        let _claims = pk.verify_token::<NoCustomClaims>(&token, None).unwrap();
656        let components = pk.to_components();
657        let hex_e = Base64::encode_to_string(components.e).unwrap();
658        let _e = Base64::decode_to_vec(hex_e, None).unwrap();
659    }
660
661    #[test]
662    fn ps384() {
663        let key_pair = PS384KeyPair::generate(2048).unwrap();
664        let claims = Claims::create(Duration::from_secs(86400));
665        let token = key_pair.sign(claims).unwrap();
666        let _claims = key_pair
667            .public_key()
668            .verify_token::<NoCustomClaims>(&token, None)
669            .unwrap();
670    }
671
672    #[test]
673    fn es256() {
674        let key_pair = ES256KeyPair::generate();
675        let claims = Claims::create(Duration::from_secs(86400));
676        let token = key_pair.sign(claims).unwrap();
677        let _claims = key_pair
678            .public_key()
679            .verify_token::<NoCustomClaims>(&token, None)
680            .unwrap();
681    }
682
683    #[test]
684    fn es384() {
685        let key_pair = ES384KeyPair::generate();
686        let claims = Claims::create(Duration::from_secs(86400));
687        let token = key_pair.sign(claims).unwrap();
688        let _claims = key_pair
689            .public_key()
690            .verify_token::<NoCustomClaims>(&token, None)
691            .unwrap();
692    }
693
694    #[test]
695    fn es256k() {
696        let key_pair = ES256kKeyPair::generate();
697        let claims = Claims::create(Duration::from_secs(86400));
698        let token = key_pair.sign(claims).unwrap();
699        let _claims = key_pair
700            .public_key()
701            .verify_token::<NoCustomClaims>(&token, None)
702            .unwrap();
703    }
704
705    #[test]
706    fn ed25519() {
707        #[derive(Serialize, Deserialize)]
708        struct CustomClaims {
709            is_custom: bool,
710        }
711
712        let key_pair = Ed25519KeyPair::generate();
713        let mut pk = key_pair.public_key();
714        let key_id = pk.create_key_id();
715        let key_pair = key_pair.with_key_id(key_id);
716        let public_key = key_pair.public_key(); // Get public key after setting key_id
717        let custom_claims = CustomClaims { is_custom: true };
718        let claims = Claims::with_custom_claims(custom_claims, Duration::from_secs(86400));
719        let token = key_pair.sign(claims).unwrap();
720        let options = VerificationOptions {
721            required_key_id: Some(key_id.to_string()),
722            ..Default::default()
723        };
724        let claims: JWTClaims<CustomClaims> = public_key
725            .verify_token::<CustomClaims>(&token, Some(options))
726            .unwrap();
727        assert!(claims.custom.is_custom);
728    }
729
730    #[test]
731    fn ed25519_der() {
732        let key_pair = Ed25519KeyPair::generate();
733        let der = key_pair.to_der();
734        let key_pair2 = Ed25519KeyPair::from_der(&der).unwrap();
735        assert_eq!(key_pair.to_bytes(), key_pair2.to_bytes());
736    }
737
738    #[test]
739    fn require_nonce() {
740        let key = HS256Key::generate();
741        let mut claims = Claims::create(Duration::from_hours(1));
742        let nonce = claims.create_nonce();
743        let token = key.authenticate(claims).unwrap();
744
745        let options = VerificationOptions {
746            required_nonce: Some(nonce),
747            ..Default::default()
748        };
749        key.verify_token::<NoCustomClaims>(&token, Some(options))
750            .unwrap();
751    }
752
753    #[test]
754    fn eddsa_pem() {
755        let sk_pem = "-----BEGIN PRIVATE KEY-----
756MC4CAQAwBQYDK2VwBCIEIMXY1NUbUe/3dW2YUoKW5evsnCJPMfj60/q0RzGne3gg
757-----END PRIVATE KEY-----\n";
758        let pk_pem = "-----BEGIN PUBLIC KEY-----
759MCowBQYDK2VwAyEAyrRjJfTnhMcW5igzYvPirFW5eUgMdKeClGzQhd4qw+Y=
760-----END PUBLIC KEY-----\n";
761        let kp = Ed25519KeyPair::from_pem(sk_pem).unwrap();
762        assert_eq!(kp.public_key().to_pem(), pk_pem);
763    }
764
765    #[test]
766    fn key_metadata() {
767        let mut key_pair = Ed25519KeyPair::generate();
768        let thumbprint = key_pair.public_key().sha1_thumbprint();
769        let key_metadata = KeyMetadata::default()
770            .with_certificate_sha1_thumbprint(&thumbprint)
771            .unwrap();
772        key_pair.attach_metadata(key_metadata).unwrap();
773
774        let claims = Claims::create(Duration::from_secs(86400));
775        let token = key_pair.sign(claims).unwrap();
776
777        let decoded_metadata = Token::decode_metadata(&token).unwrap();
778        assert_eq!(
779            decoded_metadata.certificate_sha1_thumbprint(),
780            Some(thumbprint.as_ref())
781        );
782        let _ = key_pair
783            .public_key()
784            .verify_token::<NoCustomClaims>(&token, None)
785            .unwrap();
786    }
787
788    #[test]
789    fn set_header_content_type() {
790        let key_pair = Ed25519KeyPair::generate();
791        let claims = Claims::create(Duration::from_secs(86400));
792        let token = key_pair
793            .sign_with_options(
794                claims,
795                &HeaderOptions {
796                    content_type: Some("foo".into()),
797                    ..Default::default()
798                },
799            )
800            .unwrap();
801        let decoded_metadata = Token::decode_metadata(&token).unwrap();
802        assert_eq!(
803            decoded_metadata.jwt_header.content_type.as_deref(),
804            Some("foo")
805        );
806        let _ = key_pair
807            .public_key()
808            .verify_token::<NoCustomClaims>(&token, None)
809            .unwrap();
810    }
811
812    #[test]
813    fn set_header_signature_type() {
814        let key_pair = Ed25519KeyPair::generate();
815        let claims = Claims::create(Duration::from_secs(86400));
816        let token = key_pair
817            .sign_with_options(
818                claims,
819                &HeaderOptions {
820                    signature_type: Some("etc+jwt".into()),
821                    ..Default::default()
822                },
823            )
824            .unwrap();
825        let decoded_metadata = Token::decode_metadata(&token).unwrap();
826        assert_eq!(
827            decoded_metadata.jwt_header.signature_type.as_deref(),
828            Some("etc+jwt")
829        );
830        let _ = key_pair
831            .public_key()
832            .verify_token::<NoCustomClaims>(&token, None)
833            .unwrap();
834    }
835
836    #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
837    #[test]
838    fn expired_token() {
839        let key = HS256Key::generate();
840        let claims = Claims::create(Duration::from_secs(1));
841        let token = key.authenticate(claims).unwrap();
842        std::thread::sleep(std::time::Duration::from_secs(2));
843        let options = VerificationOptions {
844            time_tolerance: None,
845            ..Default::default()
846        };
847        let claims = key.verify_token::<NoCustomClaims>(&token, None);
848        assert!(claims.is_ok());
849        let claims = key.verify_token::<NoCustomClaims>(&token, Some(options));
850        assert!(claims.is_err());
851    }
852
853    #[test]
854    fn salt() {
855        let mut key = HS256Key::generate_with_salt();
856        let claims = Claims::create(Duration::from_secs(86400));
857        let token = key.authenticate(claims).unwrap();
858
859        let res = key.verify_token::<NoCustomClaims>(&token, None);
860        assert!(res.is_err());
861
862        let verifier_salt = key.verifier_salt().unwrap();
863        key.attach_salt(verifier_salt).unwrap();
864        key.verify_token::<NoCustomClaims>(&token, None).unwrap();
865    }
866
867    #[test]
868    fn salt2() {
869        let mut key = HS256Key::generate();
870        let claims = Claims::create(Duration::from_secs(86400));
871        let token = key.authenticate(claims).unwrap();
872
873        key.verify_token::<NoCustomClaims>(&token, None).unwrap();
874
875        let verifier_salt = Salt::Verifier(b"salt".to_vec());
876        key.attach_salt(verifier_salt).unwrap();
877        let res = key.verify_token::<NoCustomClaims>(&token, None);
878        assert!(res.is_err());
879    }
880}