Skip to content

Commit

Permalink
back to 1 fn, with impl AsRef<[u8]>
Browse files Browse the repository at this point in the history
  • Loading branch information
kvc0 committed Apr 24, 2024
1 parent e340d75 commit abf4e7e
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 75 deletions.
22 changes: 4 additions & 18 deletions benches/jwt.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use jsonwebtoken::{
decode, decode_bytes, decode_header, decode_header_bytes, encode, Algorithm, DecodingKey,
EncodingKey, Header, Validation,
decode, decode_header, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation,
};
use serde::{Deserialize, Serialize};

Expand All @@ -21,27 +20,16 @@ fn bench_encode(c: &mut Criterion) {
}

fn bench_decode(c: &mut Criterion) {
let token = b"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
let key = DecodingKey::from_secret("secret".as_ref());

let mut group = c.benchmark_group("decode");
group.throughput(criterion::Throughput::Bytes(token.len() as u64));

group.bench_function("bytes", |b| {
b.iter(|| {
decode_bytes::<Claims>(
black_box(token),
black_box(&key),
black_box(&Validation::new(Algorithm::HS256)),
)
})
});

group.bench_function("str", |b| {
b.iter(|| {
decode::<Claims>(
// Simulate the cost of validating &str before decoding
black_box(std::str::from_utf8(black_box(token)).expect("valid utf8")),
black_box(token),
black_box(&key),
black_box(&Validation::new(Algorithm::HS256)),
)
Expand All @@ -56,12 +44,10 @@ fn bench_decode(c: &mut Criterion) {
b.iter(|| {
decode_header(
// Simulate the cost of validating &str before decoding
black_box(std::str::from_utf8(black_box(token)).expect("valid utf8")),
black_box(token),
)
})
});

group.bench_function("bytes", |b| b.iter(|| decode_header_bytes(black_box(token))));
}

criterion_group!(benches, bench_encode, bench_decode);
Expand Down
63 changes: 9 additions & 54 deletions src/decoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ fn verify_signature_bytes<'a>(
}

let (signature, message) = expect_two!(token.rsplitn(2, |b| *b == b'.'));
let (header, payload) = expect_two!(message.splitn(2, |b| *b == b'.'));
let (payload, header) = expect_two!(message.rsplitn(2, |b| *b == b'.'));
let header = Header::from_encoded(header)?;

if validation.validate_signature && !validation.algorithms.contains(&header.alg) {
Expand Down Expand Up @@ -250,46 +250,16 @@ fn verify_signature_bytes<'a>(
/// company: String
/// }
///
/// let token = "a.jwt.token".to_string();
/// let token = "a.jwt.token";
/// // Claims is a struct that implements Deserialize
/// let token_message = decode::<Claims>(&token, &DecodingKey::from_secret("secret".as_ref()), &Validation::new(Algorithm::HS256));
/// let token_message = decode::<Claims>(token, &DecodingKey::from_secret("secret".as_ref()), &Validation::new(Algorithm::HS256));
/// ```
pub fn decode<T: DeserializeOwned>(
token: &str,
key: &DecodingKey,
validation: &Validation,
) -> Result<TokenData<T>> {
decode_bytes(token.as_bytes(), key, validation)
}

/// Decode and validate a JWT
///
/// If the token or its signature is invalid or the claims fail validation, it will return an error.
///
/// This differs from decode() in the case that you only have bytes. By decoding as bytes you can
/// avoid taking a pass over your bytes to validate them as a utf-8 string. Since the decoding and
/// validation is all done in terms of bytes, the &str step is unnecessary.
/// If you already have a &str, decode is more convenient. If you have bytes, consider using this.
///
/// ```rust
/// use serde::{Deserialize, Serialize};
/// use jsonwebtoken::{decode_bytes, DecodingKey, Validation, Algorithm};
///
/// #[derive(Debug, Serialize, Deserialize)]
/// struct Claims {
/// sub: String,
/// company: String
/// }
///
/// let token = b"a.jwt.token";
/// // Claims is a struct that implements Deserialize
/// let token_message = decode_bytes::<Claims>(token, &DecodingKey::from_secret("secret".as_ref()), &Validation::new(Algorithm::HS256));
/// ```
pub fn decode_bytes<T: DeserializeOwned>(
token: &[u8],
token: impl AsRef<[u8]>,
key: &DecodingKey,
validation: &Validation,
) -> Result<TokenData<T>> {
let token = token.as_ref();
match verify_signature_bytes(token, key, validation) {
Err(e) => Err(e),
Ok((header, claims)) => {
Expand All @@ -309,26 +279,11 @@ pub fn decode_bytes<T: DeserializeOwned>(
/// ```rust
/// use jsonwebtoken::decode_header;
///
/// let token = "a.jwt.token".to_string();
/// let header = decode_header(&token);
/// ```
pub fn decode_header(token: &str) -> Result<Header> {
let (_, message) = expect_two!(token.rsplitn(2, '.'));
let (_, header) = expect_two!(message.rsplitn(2, '.'));
Header::from_encoded(header)
}

/// Decode a JWT without any signature verification/validations and return its [Header](struct.Header.html).
///
/// If the token has an invalid format (ie 3 parts separated by a `.`), it will return an error.
///
/// ```rust
/// use jsonwebtoken::decode_header_bytes;
///
/// let token = b"a.jwt.token";
/// let header = decode_header_bytes(token);
/// let token = "a.jwt.token";
/// let header = decode_header(token);
/// ```
pub fn decode_header_bytes(token: &[u8]) -> Result<Header> {
pub fn decode_header(token: impl AsRef<[u8]>) -> Result<Header> {
let token = token.as_ref();
let (_, message) = expect_two!(token.rsplitn(2, |b| *b == b'.'));
let (_, header) = expect_two!(message.rsplitn(2, |b| *b == b'.'));
Header::from_encoded(header)
Expand Down
4 changes: 1 addition & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ mod serialization;
mod validation;

pub use algorithms::Algorithm;
pub use decoding::{
decode, decode_bytes, decode_header, decode_header_bytes, DecodingKey, TokenData,
};
pub use decoding::{decode, decode_header, DecodingKey, TokenData};
pub use encoding::{encode, EncodingKey};
pub use header::Header;
pub use validation::{get_current_timestamp, Validation};

0 comments on commit abf4e7e

Please sign in to comment.