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