1#![forbid(unsafe_code)]
27
28pub mod algorithms;
29pub mod claims;
30pub mod common;
31pub mod token;
32
33mod jwt_header;
34mod serde_additions;
35
36mod error;
37pub use error::{Error, JWTError};
38
39pub mod prelude {
40 pub use std::collections::HashSet;
41
42 pub use coarsetime::{self, Clock, Duration, UnixTimeStamp};
43 pub use serde::{Deserialize, Serialize};
44
45 pub use crate::algorithms::*;
46 pub use crate::claims::*;
47 pub use crate::common::*;
48 pub use crate::token::*;
49
50 mod hashset_from_strings {
51 use std::collections::HashSet;
52
53 pub trait HashSetFromStringsT {
54 fn from_strings(strings: &[impl ToString]) -> HashSet<String> {
56 strings.iter().map(|x| x.to_string()).collect()
57 }
58 }
59
60 impl HashSetFromStringsT for HashSet<String> {}
61 }
62
63 pub use hashset_from_strings::HashSetFromStringsT as _;
64}
65
66#[cfg(test)]
67mod tests {
68 use crate::prelude::*;
69
70 #[cfg(feature = "ecdsa")]
71 #[test]
72 fn es256() {
73 let key_pair = ES256KeyPair::generate();
74 let claims = Claims::create(Duration::from_secs(86400));
75 let token = key_pair.sign(claims).unwrap();
76 let _claims = key_pair
77 .public_key()
78 .verify_token::<NoCustomClaims>(&token, None)
79 .unwrap();
80 }
81
82 #[cfg(feature = "ecdsa")]
83 #[test]
84 fn es384() {
85 let key_pair = ES384KeyPair::generate();
86 let claims = Claims::create(Duration::from_secs(86400));
87 let token = key_pair.sign(claims).unwrap();
88 let _claims = key_pair
89 .public_key()
90 .verify_token::<NoCustomClaims>(&token, None)
91 .unwrap();
92 }
93
94 #[cfg(feature = "ecdsa")]
95 #[test]
96 fn es256k() {
97 let key_pair = ES256kKeyPair::generate();
98 let claims = Claims::create(Duration::from_secs(86400));
99 let token = key_pair.sign(claims).unwrap();
100 let _claims = key_pair
101 .public_key()
102 .verify_token::<NoCustomClaims>(&token, None)
103 .unwrap();
104 }
105
106 #[cfg(feature = "eddsa")]
107 #[test]
108 fn ed25519() {
109 #[derive(Serialize, Deserialize)]
110 struct CustomClaims {
111 is_custom: bool,
112 }
113
114 let key_pair = Ed25519KeyPair::generate();
115 let mut pk = key_pair.public_key();
116 let key_id = pk.create_key_id().unwrap();
117 let key_pair = key_pair.with_key_id(&key_id);
118 let custom_claims = CustomClaims { is_custom: true };
119 let claims = Claims::with_custom_claims(custom_claims, Duration::from_secs(86400));
120 let token = key_pair.sign(claims).unwrap();
121 let options = VerificationOptions {
122 required_key_id: Some(key_id),
123 ..Default::default()
124 };
125 let claims: JWTClaims<CustomClaims> = key_pair
126 .public_key()
127 .verify_token::<CustomClaims>(&token, Some(options))
128 .unwrap();
129 assert!(claims.custom.is_custom);
130 }
131
132 #[cfg(feature = "eddsa")]
133 #[test]
134 fn ed25519_der() {
135 let key_pair = Ed25519KeyPair::generate();
136 let der = key_pair.to_der();
137 let key_pair2 = Ed25519KeyPair::from_der(&der).unwrap();
138 assert_eq!(key_pair.to_bytes(), key_pair2.to_bytes());
139 }
140
141 #[test]
142 fn require_nonce() {
143 let key_pair = Ed25519KeyPair::generate();
144 let nonce = "some-nonce".to_string();
145 let claims = Claims::create(Duration::from_hours(1)).with_nonce(nonce.clone());
146 let token = key_pair.sign(claims).unwrap();
147
148 let options = VerificationOptions {
149 required_nonce: Some(nonce),
150 ..Default::default()
151 };
152 key_pair
153 .public_key()
154 .verify_token::<NoCustomClaims>(&token, Some(options))
155 .unwrap();
156 }
157
158 #[cfg(feature = "eddsa")]
159 #[test]
160 fn eddsa_pem() {
161 let sk_pem = "-----BEGIN PRIVATE KEY-----
162MC4CAQAwBQYDK2VwBCIEIMXY1NUbUe/3dW2YUoKW5evsnCJPMfj60/q0RzGne3gg
163-----END PRIVATE KEY-----\n";
164 let pk_pem = "-----BEGIN PUBLIC KEY-----
165MCowBQYDK2VwAyEAyrRjJfTnhMcW5igzYvPirFW5eUgMdKeClGzQhd4qw+Y=
166-----END PUBLIC KEY-----\n";
167 let kp = Ed25519KeyPair::from_pem(sk_pem).unwrap();
168 assert_eq!(kp.public_key().to_pem(), pk_pem);
169 }
170
171 #[cfg(feature = "eddsa")]
172 #[test]
173 fn key_metadata() {
174 let mut key_pair = Ed25519KeyPair::generate();
175 let thumbprint = key_pair.public_key().sha256_thumbprint().unwrap();
176 let key_metadata = KeyMetadata::default()
177 .with_certificate_sha256_thumbprint(&thumbprint)
178 .unwrap();
179 key_pair.attach_metadata(key_metadata).unwrap();
180
181 let claims = Claims::create(Duration::from_secs(86400));
182 let token = key_pair.sign(claims).unwrap();
183
184 let decoded_metadata = Token::decode_metadata(&token).unwrap();
185 assert_eq!(
186 decoded_metadata.certificate_sha256_thumbprint(),
187 Some(thumbprint.as_ref())
188 );
189 let _ = key_pair
190 .public_key()
191 .verify_token::<NoCustomClaims>(&token, None)
192 .unwrap();
193 }
194
195 #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
196 #[test]
197 fn expired_token() {
198 let key_pair = Ed25519KeyPair::generate();
199 let claims = Claims::create(Duration::from_secs(1));
200 let token = key_pair.sign(claims).unwrap();
201 std::thread::sleep(std::time::Duration::from_secs(2));
202 let options = VerificationOptions {
203 time_tolerance: None,
204 ..Default::default()
205 };
206 let claims = key_pair
207 .public_key()
208 .verify_token::<NoCustomClaims>(&token, None);
209 assert!(claims.is_ok());
210 let claims = key_pair
211 .public_key()
212 .verify_token::<NoCustomClaims>(&token, Some(options));
213 assert!(claims.is_err());
214 }
215}