jwt_simple/
lib.rs

1//! ![GitHub CI](https://github.com/jedisct1/rust-jwt-simple/workflows/Rust/badge.svg)
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//! # JWT-Simple
6//!
7//! A new JWT implementation for Rust that focuses on simplicity, while avoiding
8//! common JWT security pitfalls.
9//!
10//! `jwt-simple` is unopinionated and supports all commonly deployed
11//! authentication and signature algorithms:
12//!
13//! * HMAC-SHA2:
14//!   * `HS256`
15//!   * `HS384`
16//!   * `HS512`
17//! * RSA
18//!   * `RS256`
19//!   * `RS384`
20//!   * `RS512`
21//!   * `PS256`
22//!   * `PS384`
23//!   * `PS512`
24//! * p256
25//!   * `ES256`
26//! * p384
27//!   * `ES384`
28//! * secp256k1
29//!   * `ES256K`
30//! * Ed25519
31//!   * `EdDSA`
32//!
33//! `jwt-simple` uses only pure Rust implementations, and can be compiled out of
34//! the box to WebAssembly/WASI. It is fully compatible with Fastly _Compute_ service.
35//!
36//! Important: JWT's purpose is to verify that data has been created by a party
37//! knowing a secret key. It does not provide any kind of confidentiality: JWT
38//! data is simply encoded as BASE64, and is not encrypted.
39//!
40//! ## Usage
41//!
42//! `cargo.toml`:
43//!
44//! ```toml
45//! [dependencies]
46//! jwt-simple = "0.10"
47//! ```
48//!
49//! Rust:
50//!
51//! ```rust
52//! use jwt_simple::prelude::*;
53//! ```
54//!
55//! ## Authentication (symmetric, `HS*` JWT algorithms) example
56//!
57//! Authentication schemes use the same key for creating and verifying tokens.
58//! In other words, both parties need to ultimately trust each other, or else
59//! the verifier could also create arbitrary tokens.
60//!
61//! ### Keys and tokens creation
62//!
63//! Key creation:
64//!
65//! ```rust
66//! use jwt_simple::prelude::*;
67//!
68//! // create a new key for the `HS256` JWT algorithm
69//! let key = HS256Key::generate();
70//! ```
71//!
72//! A key can be exported as bytes with `key.to_bytes()`, and restored with
73//! `HS256Key::from_bytes()`.
74//!
75//! Token creation:
76//!
77//! ```rust
78//! # use jwt_simple::prelude::*;
79//! # fn main() -> Result<(), jwt_simple::Error> {
80//! # let key = HS256Key::generate();
81//! /// create claims valid for 2 hours
82//! let claims = Claims::create(Duration::from_hours(2));
83//! let token = key.authenticate(claims)?;
84//! # Ok(()) }
85//! ```
86//!
87//! -> Done!
88//!
89//! ### Token verification
90//!
91//! ```rust
92//! # use jwt_simple::prelude::*;
93//! # fn main() -> Result<(), jwt_simple::Error> {
94//! # let key = HS256Key::generate();
95//! # let token = key.authenticate(Claims::create(Duration::from_secs(10)))?;
96//! let claims = key.verify_token::<NoCustomClaims>(&token, None)?;
97//! # Ok(()) }
98//! ```
99//!
100//! -> Done! No additional steps required.
101//!
102//! Key expiration, start time, authentication tags, etc. are automatically
103//! verified. The function fails with `JWTError::InvalidAuthenticationTag` if
104//! the authentication tag is invalid for the given key.
105//!
106//! The full set of claims can be inspected in the `claims` object if necessary.
107//! `NoCustomClaims` means that only the standard set of claims is used by the
108//! application, but application-defined claims can also be supported.
109//!
110//! Extra verification steps can optionally be enabled via the
111//! `ValidationOptions` structure:
112//!
113//! ```rust
114//! # use jwt_simple::prelude::*;
115//! # fn main() -> Result<(), jwt_simple::Error> {
116//! # let key = HS256Key::generate();
117//! # let token = key.authenticate(Claims::create(Duration::from_secs(10)).with_issuer("example app"))?;
118//! let mut options = VerificationOptions::default();
119//! // Accept tokens that will only be valid in the future
120//! options.accept_future = true;
121//! // Accept tokens even if they have expired up to 15 minutes after the deadline
122//! // and/or they will be valid within 15 minutes.
123//! options.time_tolerance = Some(Duration::from_mins(15));
124//! // Reject tokens if they were issued more than 1 hour ago
125//! options.max_validity = Some(Duration::from_hours(1));
126//! // Reject tokens if they don't include an issuer from that list
127//! options.allowed_issuers = Some(HashSet::from_strings(&["example app"]));
128//! // See the documentation for the full list of available options
129//!
130//! let claims = key.verify_token::<NoCustomClaims>(&token, Some(options))?;
131//! # Ok(()) }
132//! ```
133//!
134//! Note that `allowed_issuers` and `allowed_audiences` are not strings, but
135//! sets of strings (using the `HashSet` type from the Rust standard library),
136//! as the application can allow multiple return values.
137//!
138//! ## Signatures (asymmetric, `RS*`, `PS*`, `ES*` and `EdDSA` algorithms) example
139//!
140//! A signature requires a key pair: a secret key used to create tokens, and a
141//! public key, that can only verify them.
142//!
143//! Always use a signature scheme if both parties do not ultimately trust each
144//! other, such as tokens exchanged between clients and API providers.
145//!
146//! ### Key pairs and tokens creation
147//!
148//! Key creation:
149//!
150//! ```rust
151//! use jwt_simple::prelude::*;
152//!
153//! // create a new key pair for the `ES256` JWT algorithm
154//! let key_pair = ES256KeyPair::generate();
155//!
156//! // Or the `ES384` JWT algorithm
157//! let key_pair = ES384KeyPair::generate();
158//!
159//! // a public key can be extracted from a key pair:
160//! let public_key = key_pair.public_key();
161//! ```
162//!
163//! Keys can be exported as bytes for later reuse, and imported from bytes or,
164//! for RSA, from individual parameters, DER-encoded data or PEM-encoded data.
165//!
166//! RSA key pair creation, using OpenSSL and PEM importation of the secret key:
167//!
168//! ```sh
169//! openssl genrsa -out private.pem 2048
170//! openssl rsa -in private.pem -outform PEM -pubout -out public.pem
171//! ```
172//!
173//! ```no_run
174//! # use jwt_simple::prelude::*;
175//! # fn main() -> Result<(), jwt_simple::Error> {
176//! # let private_pem_file_content = "";
177//! # let public_pem_file_content = "";
178//! let key_pair = RS384KeyPair::from_pem(private_pem_file_content)?;
179//! let public_key = RS384PublicKey::from_pem(public_pem_file_content)?;
180//! # Ok(()) }
181//! ```
182//!
183//! Token creation and verification work the same way as with `HS*` algorithms,
184//! except that tokens are created with a key pair, and verified using the
185//! corresponding public key.
186//!
187//! Token creation:
188//!
189//! ```rust
190//! # use jwt_simple::prelude::*;
191//! # fn main() -> Result<(), jwt_simple::Error> {
192//! # let key_pair = Ed25519KeyPair::generate();
193//! /// create claims valid for 2 hours
194//! let claims = Claims::create(Duration::from_hours(2));
195//! let token = key_pair.sign(claims)?;
196//! # Ok(()) }
197//! ```
198//!
199//! Token verification:
200//!
201//! ```rust
202//! # use jwt_simple::prelude::*;
203//! # fn main() -> Result<(), jwt_simple::Error> {
204//! # let key_pair = Ed25519KeyPair::generate();
205//! # let public_key = key_pair.public_key();
206//! # let token = key_pair.sign(Claims::create(Duration::from_secs(10)))?;
207//! let claims = public_key.verify_token::<NoCustomClaims>(&token, None)?;
208//! # Ok(()) }
209//! ```
210//!
211//! Available verification options are identical to the ones used with symmetric
212//! algorithms.
213//!
214//! ## Advanced usage
215//!
216//! ### Custom claims
217//!
218//! Claim objects support all the standard claims by default, and they can be
219//! set directly or via convenient helpers:
220//!
221//! ```rust
222//! # use jwt_simple::prelude::*;
223//! let claims = Claims::create(Duration::from_hours(2))
224//!     .with_issuer("Example issuer")
225//!     .with_subject("Example subject");
226//! ```
227//!
228//! But application-defined claims can also be defined. These simply have to be
229//! present in a serializable type (this requires the `serde` crate):
230//!
231//! ```rust
232//! # use jwt_simple::prelude::*;
233//! # fn main() -> Result<(), jwt_simple::Error> {
234//! #[derive(Serialize, Deserialize)]
235//! struct MyAdditionalData {
236//!     user_is_admin: bool,
237//!     user_country: String,
238//! }
239//! let my_additional_data = MyAdditionalData {
240//!     user_is_admin: false,
241//!     user_country: "FR".to_string(),
242//! };
243//!
244//! // Claim creation with custom data:
245//!
246//! # use jwt_simple::prelude::*;
247//! let claims = Claims::with_custom_claims(my_additional_data, Duration::from_secs(30));
248//!
249//! // Claim verification with custom data. Note the presence of the custom data type:
250//!
251//! # let key_pair = Ed25519KeyPair::generate();
252//! # let public_key = key_pair.public_key();
253//! # let token = key_pair.sign(claims)?;
254//! let claims = public_key.verify_token::<MyAdditionalData>(&token, None)?;
255//! let user_is_admin = claims.custom.user_is_admin;
256//! # Ok(()) }
257//! ```
258//!
259//! ### Peeking at metadata before verification
260//!
261//! Properties such as the key identifier can be useful prior to tag or
262//! signature verification in order to pick the right key out of a set.
263//!
264//! ```rust
265//! # use jwt_simple::prelude::*;
266//! # fn main() -> Result<(), jwt_simple::Error> {
267//! # let token = Ed25519KeyPair::generate().sign(Claims::create(Duration::from_hours(2)))?;
268//! let metadata = Token::decode_metadata(&token)?;
269//! let key_id = metadata.key_id();
270//! let algorithm = metadata.algorithm();
271//! // all other standard properties are also accessible
272//! # Ok(()) }
273//! ```
274//!
275//! ### Creating and attaching key identifiers
276//!
277//! Key identifiers indicate to verifiers what public key (or shared key) should
278//! be used for verification. They can be attached at any time to existing
279//! shared keys, key pairs and public keys:
280//!
281//! ```rust
282//! # use jwt_simple::prelude::*;
283//! # let public_key = Ed25519KeyPair::generate().public_key();
284//! let public_key_with_id = public_key.with_key_id(&"unique key identifier");
285//! ```
286//!
287//! Instead of delegating this to applications, `jwt-simple` can also create
288//! such an identifier for an existing key:
289//!
290//! ```rust
291//! # use jwt_simple::prelude::*;
292//! # let mut public_key = Ed25519KeyPair::generate().public_key();
293//! let key_id = public_key.create_key_id();
294//! ```
295//!
296//! This creates an text-encoded identifier for the key, attaches it, and
297//! returns it.
298//!
299//! If an identifier has been attached to a shared key or a key pair, tokens
300//! created with them will include it.
301
302#![forbid(unsafe_code)]
303
304pub mod algorithms;
305pub mod claims;
306pub mod common;
307#[cfg(feature = "cwt")]
308pub mod cwt_token;
309pub mod token;
310
311mod jwt_header;
312mod serde_additions;
313
314pub mod reexports {
315    pub use anyhow;
316    pub use coarsetime;
317    pub use ct_codecs;
318    pub use rand;
319    pub use serde;
320    pub use serde_json;
321    pub use thiserror;
322    pub use zeroize;
323}
324
325mod error;
326pub use error::{Error, JWTError};
327
328pub mod prelude {
329    pub use std::collections::HashSet;
330
331    pub use coarsetime::{self, Clock, Duration, UnixTimeStamp};
332    pub use ct_codecs::{
333        Base64, Base64NoPadding, Base64UrlSafe, Base64UrlSafeNoPadding, Decoder as _, Encoder as _,
334    };
335    pub use serde::{Deserialize, Serialize};
336
337    pub use crate::algorithms::*;
338    pub use crate::claims::*;
339    pub use crate::common::*;
340    #[cfg(feature = "cwt")]
341    pub use crate::cwt_token::*;
342    pub use crate::token::*;
343
344    mod hashset_from_strings {
345        use std::collections::HashSet;
346
347        pub trait HashSetFromStringsT {
348            /// Create a set from a list of strings
349            fn from_strings(strings: &[impl ToString]) -> HashSet<String> {
350                strings.iter().map(|x| x.to_string()).collect()
351            }
352        }
353
354        impl HashSetFromStringsT for HashSet<String> {}
355    }
356
357    pub use hashset_from_strings::HashSetFromStringsT as _;
358}
359
360#[cfg(test)]
361mod tests {
362    use crate::prelude::*;
363
364    const RSA_KP_PEM: &str = r"
365-----BEGIN RSA PRIVATE KEY-----
366MIIEpAIBAAKCAQEAyqq0N5u8Jvl+BLH2VMP/NAv/zY9T8mSq0V2Gk5Ql5H1a+4qi
3673viorUXG3AvIEEccpLsW85ps5+I9itp74jllRjA5HG5smbb+Oym0m2Hovfj6qP/1
368m1drQg8oth6tNmupNqVzlGGWZLsSCBLuMa3pFaPhoxl9lGU3XJIQ1/evMkOb98I3
369hHb4ELn3WGtNlAVkbP20R8sSii/zFjPqrG/NbSPLyAl1ctbG2d8RllQF1uRIqYQj
37085yx73hqQCMpYWU3d9QzpkLf/C35/79qNnSKa3t0cyDKinOY7JGIwh8DWAa4pfEz
371gg56yLcilYSSohXeaQV0nR8+rm9J8GUYXjPK7wIDAQABAoIBAQCpeRPYyHcPFGTH
3724lU9zuQSjtIq/+bP9FRPXWkS8bi6GAVEAUtvLvpGYuoGyidTTVPrgLORo5ncUnjq
373KwebRimlBuBLIR/Zboery5VGthoc+h4JwniMnQ6JIAoIOSDZODA5DSPYeb58n15V
374uBbNHkOiH/eoHsG/nOAtnctN/cXYPenkCfeLXa3se9EzkcmpNGhqCBL/awtLU17P
375Iw7XxsJsRMBOst4Aqiri1GQI8wqjtXWLyfjMpPR8Sqb4UpTDmU1wHhE/w/+2lahC
376Tu0/+sCWj7TlafYkT28+4pAMyMqUT6MjqdmGw8lD7/vXv8TF15NU1cUv3QSKpVGe
37750vlB1QpAoGBAO1BU1evrNvA91q1bliFjxrH3MzkTQAJRMn9PBX29XwxVG7/HlhX
3780tZRSR92ZimT2bAu7tH0Tcl3Bc3NwEQrmqKlIMqiW+1AVYtNjuipIuB7INb/TUM3
379smEh+fn3yhMoVxbbh/klR1FapPUFXlpNv3DJHYM+STqLMhl9tEc/I7bLAoGBANqt
380zR6Kovf2rh7VK/Qyb2w0rLJE7Zh/WI+r9ubCba46sorqkJclE5cocxWuTy8HWyQp
381spxzLP1FQlsI+MESgRLueoH3HtB9lu/pv6/8JlNjU6SzovfUZ0KztVUyUeB4vAcH
382pGcf2CkUtoYc8YL22Ybck3s8ThIdnY5zphCF55PtAoGAf46Go3c05XVKx78R05AD
383D2/y+0mnSGSzUjHPMzPyadIPxhltlCurlERhnwPGC4aNHFcvWTwS8kUGns6HF1+m
384JNnI1okSCW10UI/jTJ1avfwU/OKIBKKWSfi9cDJTt5cRs51V7pKnVEr6sy0uvDhe
385u+G091HuhwY9ak0WNtPwfJ8CgYEAuRdoyZQQso7x/Bj0tiHGW7EOB2n+LRiErj6g
386odspmNIH8zrtHXF9bnEHT++VCDpSs34ztuZpywnHS2SBoHH4HD0MJlszksbqbbDM
3871bk3+1bUIlEF/Hyk1jljn3QTB0tJ4y1dwweaH9NvVn7DENW9cr/aePGnJwA4Lq3G
388fq/IPlUCgYAuqgJQ4ztOq0EaB75xgqtErBM57A/+lMWS9eD/euzCEO5UzWVaiIJ+
389nNDmx/jvSrxA1Ih8TEHjzv4ezLFYpaJrTst4Mjhtx+csXRJU9a2W6HMXJ4Kdn8rk
390PBziuVURslNyLdlFsFlm/kfvX+4Cxrbb+pAGETtRTgmAoCDbvuDGRQ==
391-----END RSA PRIVATE KEY-----
392    ";
393
394    const RSA_PK_PEM: &str = r"
395-----BEGIN PUBLIC KEY-----
396MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyqq0N5u8Jvl+BLH2VMP/
397NAv/zY9T8mSq0V2Gk5Ql5H1a+4qi3viorUXG3AvIEEccpLsW85ps5+I9itp74jll
398RjA5HG5smbb+Oym0m2Hovfj6qP/1m1drQg8oth6tNmupNqVzlGGWZLsSCBLuMa3p
399FaPhoxl9lGU3XJIQ1/evMkOb98I3hHb4ELn3WGtNlAVkbP20R8sSii/zFjPqrG/N
400bSPLyAl1ctbG2d8RllQF1uRIqYQj85yx73hqQCMpYWU3d9QzpkLf/C35/79qNnSK
401a3t0cyDKinOY7JGIwh8DWAa4pfEzgg56yLcilYSSohXeaQV0nR8+rm9J8GUYXjPK
4027wIDAQAB
403-----END PUBLIC KEY-----
404    ";
405
406    #[test]
407    fn hs384() {
408        let key = HS384Key::from_bytes(b"your-256-bit-secret").with_key_id("my-key-id");
409        let claims = Claims::create(Duration::from_secs(86400)).with_issuer("test issuer");
410        let token = key.authenticate(claims).unwrap();
411        let options = VerificationOptions {
412            allowed_issuers: Some(HashSet::from_strings(&["test issuer"])),
413            ..Default::default()
414        };
415        let _claims = key
416            .verify_token::<NoCustomClaims>(&token, Some(options))
417            .unwrap();
418    }
419
420    #[test]
421    fn rs256() {
422        let key_pair = RS256KeyPair::from_pem(RSA_KP_PEM).unwrap();
423        let claims = Claims::create(Duration::from_secs(86400));
424        let token = key_pair.sign(claims).unwrap();
425        let pk = RS256PublicKey::from_pem(RSA_PK_PEM).unwrap();
426        let _claims = pk.verify_token::<NoCustomClaims>(&token, None).unwrap();
427        let components = pk.to_components();
428        let hex_e = Base64::encode_to_string(components.e).unwrap();
429        let _e = Base64::decode_to_vec(hex_e, None).unwrap();
430    }
431
432    #[test]
433    fn ps384() {
434        let key_pair = PS384KeyPair::generate(2048).unwrap();
435        let claims = Claims::create(Duration::from_secs(86400));
436        let token = key_pair.sign(claims).unwrap();
437        let _claims = key_pair
438            .public_key()
439            .verify_token::<NoCustomClaims>(&token, None)
440            .unwrap();
441    }
442
443    #[test]
444    fn es256() {
445        let key_pair = ES256KeyPair::generate();
446        let claims = Claims::create(Duration::from_secs(86400));
447        let token = key_pair.sign(claims).unwrap();
448        let _claims = key_pair
449            .public_key()
450            .verify_token::<NoCustomClaims>(&token, None)
451            .unwrap();
452    }
453
454    #[test]
455    fn es384() {
456        let key_pair = ES384KeyPair::generate();
457        let claims = Claims::create(Duration::from_secs(86400));
458        let token = key_pair.sign(claims).unwrap();
459        let _claims = key_pair
460            .public_key()
461            .verify_token::<NoCustomClaims>(&token, None)
462            .unwrap();
463    }
464
465    #[test]
466    fn es256k() {
467        let key_pair = ES256kKeyPair::generate();
468        let claims = Claims::create(Duration::from_secs(86400));
469        let token = key_pair.sign(claims).unwrap();
470        let _claims = key_pair
471            .public_key()
472            .verify_token::<NoCustomClaims>(&token, None)
473            .unwrap();
474    }
475
476    #[test]
477    fn ed25519() {
478        #[derive(Serialize, Deserialize)]
479        struct CustomClaims {
480            is_custom: bool,
481        }
482
483        let key_pair = Ed25519KeyPair::generate();
484        let mut pk = key_pair.public_key();
485        let key_id = pk.create_key_id();
486        let key_pair = key_pair.with_key_id(key_id);
487        let custom_claims = CustomClaims { is_custom: true };
488        let claims = Claims::with_custom_claims(custom_claims, Duration::from_secs(86400));
489        let token = key_pair.sign(claims).unwrap();
490        let options = VerificationOptions {
491            required_key_id: Some(key_id.to_string()),
492            ..Default::default()
493        };
494        let claims: JWTClaims<CustomClaims> = key_pair
495            .public_key()
496            .verify_token::<CustomClaims>(&token, Some(options))
497            .unwrap();
498        assert!(claims.custom.is_custom);
499    }
500
501    #[test]
502    fn ed25519_der() {
503        let key_pair = Ed25519KeyPair::generate();
504        let der = key_pair.to_der();
505        let key_pair2 = Ed25519KeyPair::from_der(&der).unwrap();
506        assert_eq!(key_pair.to_bytes(), key_pair2.to_bytes());
507    }
508
509    #[test]
510    fn require_nonce() {
511        let key = HS256Key::generate();
512        let mut claims = Claims::create(Duration::from_hours(1));
513        let nonce = claims.create_nonce();
514        let token = key.authenticate(claims).unwrap();
515
516        let options = VerificationOptions {
517            required_nonce: Some(nonce),
518            ..Default::default()
519        };
520        key.verify_token::<NoCustomClaims>(&token, Some(options))
521            .unwrap();
522    }
523
524    #[test]
525    fn eddsa_pem() {
526        let sk_pem = "-----BEGIN PRIVATE KEY-----
527MC4CAQAwBQYDK2VwBCIEIMXY1NUbUe/3dW2YUoKW5evsnCJPMfj60/q0RzGne3gg
528-----END PRIVATE KEY-----\n";
529        let pk_pem = "-----BEGIN PUBLIC KEY-----
530MCowBQYDK2VwAyEAyrRjJfTnhMcW5igzYvPirFW5eUgMdKeClGzQhd4qw+Y=
531-----END PUBLIC KEY-----\n";
532        let kp = Ed25519KeyPair::from_pem(sk_pem).unwrap();
533        assert_eq!(kp.public_key().to_pem(), pk_pem);
534    }
535
536    #[test]
537    fn key_metadata() {
538        let mut key_pair = Ed25519KeyPair::generate();
539        let thumbprint = key_pair.public_key().sha1_thumbprint();
540        let key_metadata = KeyMetadata::default()
541            .with_certificate_sha1_thumbprint(&thumbprint)
542            .unwrap();
543        key_pair.attach_metadata(key_metadata).unwrap();
544
545        let claims = Claims::create(Duration::from_secs(86400));
546        let token = key_pair.sign(claims).unwrap();
547
548        let decoded_metadata = Token::decode_metadata(&token).unwrap();
549        assert_eq!(
550            decoded_metadata.certificate_sha1_thumbprint(),
551            Some(thumbprint.as_ref())
552        );
553        let _ = key_pair
554            .public_key()
555            .verify_token::<NoCustomClaims>(&token, None)
556            .unwrap();
557    }
558
559    #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
560    #[test]
561    fn expired_token() {
562        let key = HS256Key::generate();
563        let claims = Claims::create(Duration::from_secs(1));
564        let token = key.authenticate(claims).unwrap();
565        std::thread::sleep(std::time::Duration::from_secs(2));
566        let options = VerificationOptions {
567            time_tolerance: None,
568            ..Default::default()
569        };
570        let claims = key.verify_token::<NoCustomClaims>(&token, None);
571        assert!(claims.is_ok());
572        let claims = key.verify_token::<NoCustomClaims>(&token, Some(options));
573        assert!(claims.is_err());
574    }
575}