Skip to content

Commit e5ba5a1

Browse files
authored
Merge branch 'master' into new-backends
2 parents e061882 + c733c78 commit e5ba5a1

File tree

6 files changed

+58
-7
lines changed

6 files changed

+58
-7
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
include:
3838
- build: pinned
3939
os: ubuntu-20.04
40-
rust: 1.67.0
40+
rust: 1.73.0
4141
- build: stable
4242
os: ubuntu-20.04
4343
rust: stable

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "jsonwebtoken"
3-
version = "9.2.0"
3+
version = "9.3.0"
44
authors = ["Vincent Prouillet <hello@vincentprouillet.com>"]
55
license = "MIT"
66
readme = "README.md"
@@ -17,12 +17,12 @@ include = [
1717
"README.md",
1818
"CHANGELOG.md",
1919
]
20-
rust-version = "1.67.0"
20+
rust-version = "1.73.0"
2121

2222
[dependencies]
2323
serde_json = "1.0"
2424
serde = { version = "1.0", features = ["derive"] }
25-
base64 = "0.21.0"
25+
base64 = "0.22"
2626
# For PEM decoding
2727
pem = { version = "3", optional = true }
2828
simple_asn1 = { version = "0.6", optional = true }

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jsonwebtoken = "9"
1414
serde = {version = "1.0", features = ["derive"] }
1515
```
1616

17-
The minimum required Rust version (MSRV) is 1.67.
17+
The minimum required Rust version (MSRV) is specified in the `rust-version` field in this project's [Cargo.toml](Cargo.toml).
1818

1919
## Algorithms
2020
This library currently supports the following:
@@ -160,6 +160,8 @@ This library automatically validates the `exp` claim, and `nbf` is validated if
160160
those require setting the expected values in the `Validation` struct. In the case of `aud`, if there is a value set in the token but
161161
not in the `Validation`, the token will be rejected.
162162

163+
Validation is only made on present fields in the claims. It is possible to define the required claims, hence verifying that a JWT has a value for each of these claims before it is considered for validation. The required claims can be set in the `Validation` struct. The default option requires the `exp` claim to be present.
164+
163165
Since validating time fields is always a bit tricky due to clock skew,
164166
you can add some leeway to the `iat`, `exp`, and `nbf` validation by setting the `leeway` field.
165167

examples/validation.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ fn main() {
2727
let mut validation = Validation::new(Algorithm::HS256);
2828
validation.sub = Some("b@b.com".to_string());
2929
validation.set_audience(&["me"]);
30+
validation.set_required_spec_claims(&["exp", "sub", "aud"]);
3031
let token_data = match decode::<Claims>(&token, &DecodingKey::from_secret(key), &validation) {
3132
Ok(c) => c,
3233
Err(err) => match *err.kind() {

src/validation.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use crate::errors::{new_error, ErrorKind, Result};
2424
/// // or issuer
2525
/// validation.set_issuer(&["Me"]); // a single string
2626
/// validation.set_issuer(&["Me", "You"]); // array of strings
27+
/// // Setting required claims
28+
/// validation.set_required_spec_claims(&["exp", "iss", "aud"]);
2729
/// ```
2830
#[derive(Debug, Clone, PartialEq, Eq)]
2931
pub struct Validation {
@@ -39,6 +41,13 @@ pub struct Validation {
3941
///
4042
/// Defaults to `60`.
4143
pub leeway: u64,
44+
/// Reject a token some time (in seconds) before the `exp` to prevent
45+
/// expiration in transit over the network.
46+
///
47+
/// The value is the inverse of `leeway`, subtracting from the validation time.
48+
///
49+
/// Defaults to `0`.
50+
pub reject_tokens_expiring_in_less_than: u64,
4251
/// Whether to validate the `exp` field.
4352
///
4453
/// It will return an error if the time in the `exp` field is past.
@@ -49,29 +58,44 @@ pub struct Validation {
4958
///
5059
/// It will return an error if the current timestamp is before the time in the `nbf` field.
5160
///
61+
/// Validation only happens if `nbf` claim is present in the token.
62+
/// Adding `nbf` to `required_spec_claims` will make it required.
63+
///
5264
/// Defaults to `false`.
5365
pub validate_nbf: bool,
5466
/// Whether to validate the `aud` field.
5567
///
5668
/// It will return an error if the `aud` field is not a member of the audience provided.
5769
///
70+
/// Validation only happens if `aud` claim is present in the token.
71+
/// Adding `aud` to `required_spec_claims` will make it required.
72+
///
5873
/// Defaults to `true`. Very insecure to turn this off. Only do this if you know what you are doing.
5974
pub validate_aud: bool,
6075
/// Validation will check that the `aud` field is a member of the
6176
/// audience provided and will error otherwise.
6277
/// Use `set_audience` to set it
6378
///
79+
/// Validation only happens if `aud` claim is present in the token.
80+
/// Adding `aud` to `required_spec_claims` will make it required.
81+
///
6482
/// Defaults to `None`.
6583
pub aud: Option<HashSet<String>>,
6684
/// If it contains a value, the validation will check that the `iss` field is a member of the
6785
/// iss provided and will error otherwise.
6886
/// Use `set_issuer` to set it
6987
///
88+
/// Validation only happens if `iss` claim is present in the token.
89+
/// Adding `iss` to `required_spec_claims` will make it required.
90+
///
7091
/// Defaults to `None`.
7192
pub iss: Option<HashSet<String>>,
7293
/// If it contains a value, the validation will check that the `sub` field is the same as the
7394
/// one provided and will error otherwise.
7495
///
96+
/// Validation only happens if `sub` claim is present in the token.
97+
/// Adding `sub` to `required_spec_claims` will make it required.
98+
///
7599
/// Defaults to `None`.
76100
pub sub: Option<String>,
77101
/// The validation will check that the `alg` of the header is contained
@@ -94,6 +118,7 @@ impl Validation {
94118
required_spec_claims: required_claims,
95119
algorithms: vec![alg],
96120
leeway: 60,
121+
reject_tokens_expiring_in_less_than: 0,
97122

98123
validate_exp: true,
99124
validate_nbf: false,
@@ -250,7 +275,8 @@ pub(crate) fn validate(claims: ClaimsForValidation, options: &Validation) -> Res
250275
if options.validate_exp || options.validate_nbf {
251276
let now = get_current_timestamp();
252277

253-
if matches!(claims.exp, TryParse::Parsed(exp) if options.validate_exp && exp < now - options.leeway)
278+
if matches!(claims.exp, TryParse::Parsed(exp) if options.validate_exp
279+
&& exp - options.reject_tokens_expiring_in_less_than < now - options.leeway )
254280
{
255281
return Err(new_error(ErrorKind::ExpiredSignature));
256282
}
@@ -371,6 +397,17 @@ mod tests {
371397
assert!(res.is_ok());
372398
}
373399

400+
#[test]
401+
#[wasm_bindgen_test]
402+
fn exp_in_future_but_in_rejection_period_fails() {
403+
let claims = json!({ "exp": get_current_timestamp() + 500 });
404+
let mut validation = Validation::new(Algorithm::HS256);
405+
validation.leeway = 0;
406+
validation.reject_tokens_expiring_in_less_than = 501;
407+
let res = validate(deserialize_claims(&claims), &validation);
408+
assert!(res.is_err());
409+
}
410+
374411
#[test]
375412
#[wasm_bindgen_test]
376413
fn exp_float_in_future_ok() {
@@ -379,6 +416,17 @@ mod tests {
379416
assert!(res.is_ok());
380417
}
381418

419+
#[test]
420+
#[wasm_bindgen_test]
421+
fn exp_float_in_future_but_in_rejection_period_fails() {
422+
let claims = json!({ "exp": (get_current_timestamp() as f64) + 500.123 });
423+
let mut validation = Validation::new(Algorithm::HS256);
424+
validation.leeway = 0;
425+
validation.reject_tokens_expiring_in_less_than = 501;
426+
let res = validate(deserialize_claims(&claims), &validation);
427+
assert!(res.is_err());
428+
}
429+
382430
#[test]
383431
#[wasm_bindgen_test]
384432
fn exp_in_past_fails() {

tests/rsa/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ openssl x509 -req -sha256 -days 358000 -in certificate_rsa_pkcs1.csr -signkey pr
1414
### RSA PKCS8
1515

1616
```
17-
openssl genpkey -algorithm RSA -out private_rsa_pkcs8.pem -pkeyopt rsa_keygen_bits:2048`
17+
openssl genpkey -algorithm RSA -out private_rsa_pkcs8.pem -pkeyopt rsa_keygen_bits:2048
1818
openssl rsa -pubout -in private_rsa_pkcs8.pem -out public_rsa_pkcs.pem
1919
openssl req -new -key private_rsa_pkcs8.key -out certificate_rsa_pkcs8.csr
2020
openssl x509 -req -sha256 -days 358000 -in certificate_rsa_pkcs8.csr -signkey private_rsa_pkcs8.key -out certificate_rsa_pkcs8.crt

0 commit comments

Comments
 (0)