jwt_simple/lib.rs
1//! [](https://github.com/jedisct1/rust-jwt-simple/actions)
2//! [](https://docs.rs/jwt-simple/)
3//! [](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}