From e213d431b71376fdfd99295c067286448ea5b1e5 Mon Sep 17 00:00:00 2001 From: arckoor <33837362+arckoor@users.noreply.github.com> Date: Wed, 27 May 2026 12:23:44 +0200 Subject: [PATCH 1/3] Fix some pedantic clippy complaints --- src/crypto/mod.rs | 8 ++++---- src/header.rs | 2 +- src/jwk.rs | 4 ++-- src/pem/decoder.rs | 11 +++++------ src/serialization.rs | 2 +- src/validation.rs | 4 ++-- 6 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index 488f217d..0bcb8e9b 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -114,11 +114,11 @@ impl CryptoProvider { #[allow(unreachable_code)] { - const NOT_INSTALLED_ERROR: &str = r###" + const NOT_INSTALLED_ERROR: &str = r" Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features. Call CryptoProvider::install_default() before this point to select a provider manually, or make sure exactly one of the 'rust_crypto' and 'aws_lc_rs' features is enabled. See the documentation of the CryptoProvider type for more information. -"###; +"; static INSTANCE: CryptoProvider = CryptoProvider { signer_factory: |_, _| panic!("{}", NOT_INSTALLED_ERROR), @@ -151,11 +151,11 @@ impl JwkUtils { /// Initialises all values to dummies. /// Will lead to a panic when JWKs are required, so only use it if you don't want to support JWKs. pub const fn new_unimplemented() -> Self { - const NOT_INSTALLED_OR_UNIMPLEMENTED_ERROR: &str = r###" + const NOT_INSTALLED_OR_UNIMPLEMENTED_ERROR: &str = r" Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features, or your CryptoProvider does not support JWKs. Call CryptoProvider::install_default() before this point to select a provider manually, or make sure exactly one of the 'rust_crypto' and 'aws_lc_rs' features is enabled. See the documentation of the CryptoProvider type for more information. -"###; +"; Self { extract_rsa_public_key_components: |_| { panic!("{}", NOT_INSTALLED_OR_UNIMPLEMENTED_ERROR) diff --git a/src/header.rs b/src/header.rs index 6f01d947..cd470159 100644 --- a/src/header.rs +++ b/src/header.rs @@ -248,7 +248,7 @@ impl Header { zip: None, url: None, nonce: None, - extras: Default::default(), + extras: Extras::default(), } } diff --git a/src/jwk.rs b/src/jwk.rs index 615d76bc..34d8ed90 100644 --- a/src/jwk.rs +++ b/src/jwk.rs @@ -242,8 +242,8 @@ pub struct CommonParameters { #[serde(rename = "use", skip_serializing_if = "Option::is_none", default)] pub public_key_use: Option, - /// The "key_ops" (key operations) parameter identifies the operation(s) - /// for which the key is intended to be used. The "key_ops" parameter is + /// The `key_ops` (key operations) parameter identifies the operation(s) + /// for which the key is intended to be used. The `key_ops` parameter is /// intended for use cases in which public, private, or symmetric keys /// may be present. /// Should not be specified with `public_key_use`. diff --git a/src/pem/decoder.rs b/src/pem/decoder.rs index 94ff8821..cbd54b5b 100644 --- a/src/pem/decoder.rs +++ b/src/pem/decoder.rs @@ -53,9 +53,8 @@ impl PemEncodedKey { pub fn new(input: &[u8]) -> Result { match pem::parse(input) { Ok(content) => { - let asn1_content = match simple_asn1::from_der(content.contents()) { - Ok(asn1) => asn1, - Err(_) => return Err(ErrorKind::InvalidKeyFormat.into()), + let Ok(asn1_content) = simple_asn1::from_der(content.contents()) else { + return Err(ErrorKind::InvalidKeyFormat.into()); }; match content.tag() { @@ -78,7 +77,7 @@ impl PemEncodedKey { // "there is no such thing as a "PKCS#1 format" for elliptic curve (EC) keys" // This handles PKCS#8 certificates and public & private keys - tag @ "PRIVATE KEY" | tag @ "PUBLIC KEY" | tag @ "CERTIFICATE" => { + tag @ ("PRIVATE KEY" | "PUBLIC KEY" | "CERTIFICATE") => { match classify_pem(&asn1_content) { Some(c) => { let is_private = tag == "PRIVATE KEY"; @@ -187,7 +186,7 @@ impl PemEncodedKey { // Though PKCS#11 keys shouldn't have anything else. // It will get confusing with certificates. fn extract_first_bitstring(asn1: &[simple_asn1::ASN1Block]) -> Result<&[u8]> { - for asn1_entry in asn1.iter() { + for asn1_entry in asn1 { match asn1_entry { simple_asn1::ASN1Block::Sequence(_, entries) => { if let Ok(result) = extract_first_bitstring(entries) { @@ -215,7 +214,7 @@ fn classify_pem(asn1: &[simple_asn1::ASN1Block]) -> Option { let rsa_public_key_oid = simple_asn1::oid!(1, 2, 840, 113_549, 1, 1, 1); let ed25519_oid = simple_asn1::oid!(1, 3, 101, 112); - for asn1_entry in asn1.iter() { + for asn1_entry in asn1 { match asn1_entry { simple_asn1::ASN1Block::Sequence(_, entries) => { if let Some(classification) = classify_pem(entries) { diff --git a/src/serialization.rs b/src/serialization.rs index b6a12c95..f4dbe95d 100644 --- a/src/serialization.rs +++ b/src/serialization.rs @@ -21,7 +21,7 @@ pub(crate) fn b64_encode_part(input: &T) -> Result { /// This is used to decode from base64 then deserialize from JSON to several structs: /// - The user-provided struct -/// - The ClaimsForValidation struct from this crate to run validation on +/// - The `ClaimsForValidation` struct from this crate to run validation on pub(crate) struct DecodedJwtPartClaims { b64_decoded: Vec, } diff --git a/src/validation.rs b/src/validation.rs index 77ddd01d..decc0537 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -144,13 +144,13 @@ impl Validation { /// `aud` is a collection of one or more acceptable audience members /// The simple usage is `set_audience(&["some aud name"])` pub fn set_audience(&mut self, items: &[T]) { - self.aud = Some(items.iter().map(|x| x.to_string()).collect()) + self.aud = Some(items.iter().map(|x| x.to_string()).collect()); } /// `iss` is a collection of one or more acceptable issuers members /// The simple usage is `set_issuer(&["some iss name"])` pub fn set_issuer(&mut self, items: &[T]) { - self.iss = Some(items.iter().map(|x| x.to_string()).collect()) + self.iss = Some(items.iter().map(|x| x.to_string()).collect()); } /// Which claims are required to be present for this JWT to be considered valid. From 40903ea5a066e3a4896c469055a0a8cc6d511dfe Mon Sep 17 00:00:00 2001 From: arckoor <33837362+arckoor@users.noreply.github.com> Date: Thu, 28 May 2026 16:21:06 +0200 Subject: [PATCH 2/3] Add some doc, more consistent style --- src/crypto/rust_crypto/hmac.rs | 6 +++--- src/jwk.rs | 31 ++++++++++++++++++------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/crypto/rust_crypto/hmac.rs b/src/crypto/rust_crypto/hmac.rs index 2dc034b1..fdcd2e12 100644 --- a/src/crypto/rust_crypto/hmac.rs +++ b/src/crypto/rust_crypto/hmac.rs @@ -6,7 +6,7 @@ use sha2::{Sha256, Sha384, Sha512}; use signature::{Signer, Verifier}; use crate::crypto::{JwtSigner, JwtVerifier}; -use crate::errors::Result; +use crate::errors::{ErrorKind, Result}; use crate::{Algorithm, DecodingKey, EncodingKey}; type HmacSha256 = Hmac; @@ -21,7 +21,7 @@ macro_rules! define_hmac_signer { impl $name { pub(crate) fn new(encoding_key: &EncodingKey) -> Result { let inner = <$hmac_type>::new_from_slice(encoding_key.try_get_hmac_secret()?) - .map_err(|_e| crate::errors::ErrorKind::InvalidKeyFormat)?; + .map_err(|_| ErrorKind::InvalidKeyFormat)?; Ok(Self(inner)) } @@ -53,7 +53,7 @@ macro_rules! define_hmac_verifier { impl $name { pub(crate) fn new(decoding_key: &DecodingKey) -> Result { let inner = <$hmac_type>::new_from_slice(decoding_key.try_get_hmac_secret()?) - .map_err(|_e| crate::errors::ErrorKind::InvalidKeyFormat)?; + .map_err(|_| ErrorKind::InvalidKeyFormat)?; Ok(Self(inner)) } diff --git a/src/jwk.rs b/src/jwk.rs index 34d8ed90..92ea2f19 100644 --- a/src/jwk.rs +++ b/src/jwk.rs @@ -1,4 +1,3 @@ -#![allow(missing_docs)] //! This crate contains types only for working JWK and JWK Sets //! This is only meant to be used to deal with public JWK, not generate ones. //! Most of the code in this file is taken from but @@ -11,7 +10,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer, de}; use crate::crypto::CryptoProvider; use crate::serialization::b64_encode; use crate::{ - Algorithm, EncodingKey, + Algorithm, AlgorithmFamily, EncodingKey, errors::{self, Error, ErrorKind}, }; @@ -403,6 +402,7 @@ pub struct OctetKeyPairParameters { /// Algorithm specific parameters #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] #[serde(untagged)] +#[allow(missing_docs)] pub enum AlgorithmParameters { EllipticCurve(EllipticCurveKeyParameters), RSA(RSAKeyParameters), @@ -412,6 +412,7 @@ pub enum AlgorithmParameters { /// The function to use to hash the intermediate thumbprint data. #[derive(Debug, Clone, Eq, PartialEq)] +#[allow(missing_docs)] pub enum ThumbprintHash { SHA256, SHA384, @@ -419,6 +420,7 @@ pub enum ThumbprintHash { } #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] +#[allow(missing_docs)] pub struct Jwk { #[serde(flatten)] pub common: CommonParameters, @@ -435,7 +437,11 @@ impl Jwk { _ => false, } } - pub fn from_encoding_key(key: &EncodingKey, alg: Algorithm) -> crate::errors::Result { + + /// Create a `JWK` from an `EncodingKey`. + /// + /// Edwards curve based keys are not supported. + pub fn from_encoding_key(key: &EncodingKey, alg: Algorithm) -> errors::Result { Ok(Self { common: CommonParameters { key_algorithm: Some(match alg { @@ -455,13 +461,11 @@ impl Jwk { ..Default::default() }, algorithm: match key.family() { - crate::algorithms::AlgorithmFamily::Hmac => { - AlgorithmParameters::OctetKey(OctetKeyParameters { - key_type: OctetKeyType::Octet, - value: b64_encode(key.inner()), - }) - } - crate::algorithms::AlgorithmFamily::Rsa => { + AlgorithmFamily::Hmac => AlgorithmParameters::OctetKey(OctetKeyParameters { + key_type: OctetKeyType::Octet, + value: b64_encode(key.inner()), + }), + AlgorithmFamily::Rsa => { let (n, e) = (CryptoProvider::get_default() .jwk_utils .extract_rsa_public_key_components)( @@ -473,7 +477,7 @@ impl Jwk { e: b64_encode(e), }) } - crate::algorithms::AlgorithmFamily::Ec => { + AlgorithmFamily::Ec => { let (curve, x, y) = (CryptoProvider::get_default() .jwk_utils .extract_ec_public_key_coordinates)( @@ -486,8 +490,8 @@ impl Jwk { y: b64_encode(y), }) } - crate::algorithms::AlgorithmFamily::Ed => { - unimplemented!(); + AlgorithmFamily::Ed => { + unimplemented!("Edwards curves are not supported"); } }, }) @@ -549,6 +553,7 @@ impl Jwk { /// A JWK set #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[allow(missing_docs)] pub struct JwkSet { pub keys: Vec, } From d84f3891dc66e6e34d778b7b2206488c05123198 Mon Sep 17 00:00:00 2001 From: arckoor <33837362+arckoor@users.noreply.github.com> Date: Thu, 28 May 2026 16:21:43 +0200 Subject: [PATCH 3/3] Update readme --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 363387fe..97951ac2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Add the following to Cargo.toml: ```toml # You will have to select either `aws_lc_rs` or `rust_crypto` as backend if you're not using your own -jsonwebtoken = { version = "10", features = ["aws_lc_rs"] } +jsonwebtoken = { version = "11", features = ["aws_lc_rs"] } # If you do not need pem decoding, you can disable the default feature `use_pem` that way: # jsonwebtoken = {version = "10", default-features = false, features = ["aws_lc_rs"] } serde = {version = "1.0", features = ["derive"] } @@ -18,7 +18,7 @@ serde = {version = "1.0", features = ["derive"] } Two crypto backends are available via features, `aws_lc_rs` and `rust_crypto`, at most one of which must be enabled. If you select neither feature, you need to provide your own `CryptoProvider`. For examples of how to implement a `CryptoProvider`, see -- [arckoor/jsonwebtoken-botan](https://github.com/arckoor/jsonwebtoken-botan) +- [arckoor/jsonwebtoken-providers](https://github.com/arckoor/jsonwebtoken-providers) The minimum required Rust version (MSRV) is specified in the `rust-version` field in this project's [Cargo.toml](Cargo.toml). @@ -45,7 +45,7 @@ Complete examples are available in the examples directory: a basic one and one w In terms of imports and structs: ```rust use serde::{Serialize, Deserialize}; -use jsonwebtoken::{encode, decode, Header, Algorithm, Validation, EncodingKey, DecodingKey}; +use jsonwebtoken::{encode, decode, Header, Extras, Algorithm, Validation, EncodingKey, DecodingKey}; /// Our claims struct, it needs to derive `Serialize` and/or `Deserialize` #[derive(Debug, Serialize, Deserialize)] @@ -86,7 +86,7 @@ If you want to set the `kid` parameter or change the algorithm for example: let mut header = Header::new(Algorithm::HS512); header.kid = Some("blabla".to_owned()); -let mut extras = HashMap::with_capacity(1); +let mut extras = Extras::default(); extras.insert("custom".to_string(), "header".to_string()); header.extras = Some(extras); @@ -134,8 +134,8 @@ when the Jws is nested in another struct. If you have a JWK object, you can generate a thumbprint like -``` -let tp = my_jwk.thumbprint(&jsonwebtoken::DIGEST_SHA256); +```rust +let tp = my_jwk.thumbprint(&jsonwebtoken::DIGEST_SHA256)?; ``` ### Decoding