Skip to content

feat: allow users to specify a custom header not defined in the struct #420

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 4, 2025
9 changes: 8 additions & 1 deletion src/header.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::result;

use base64::{engine::general_purpose::STANDARD, Engine};
Expand All @@ -10,7 +11,7 @@ use crate::serialization::b64_decode;

/// A basic JWT header, the alg defaults to HS256 and typ is automatically
/// set to `JWT`. All the other fields are optional.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Header {
/// The type of JWS: it can only be "JWT" here
///
Expand Down Expand Up @@ -64,6 +65,11 @@ pub struct Header {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "x5t#S256")]
pub x5t_s256: Option<String>,

/// Any additional headers
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(flatten)]
pub extra: Option<HashMap<String, String>>,
}

impl Header {
Expand All @@ -80,6 +86,7 @@ impl Header {
x5c: None,
x5t: None,
x5t_s256: None,
extra: None
}
}

Expand Down
6 changes: 5 additions & 1 deletion tests/hmac.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use jsonwebtoken::errors::ErrorKind;
use jsonwebtoken::jwk::Jwk;
use jsonwebtoken::{
Expand Down Expand Up @@ -41,7 +42,9 @@ fn encode_with_custom_header() {
company: "ACME".to_string(),
exp: OffsetDateTime::now_utc().unix_timestamp() + 10000,
};
let header = Header { kid: Some("kid".to_string()), ..Default::default() };
let mut extra = HashMap::with_capacity(1);
extra.insert("custom".to_string(), "header".to_string());
let header = Header { kid: Some("kid".to_string()), extra: Some(extra), ..Default::default() };
let token = encode(&header, &my_claims, &EncodingKey::from_secret(b"secret")).unwrap();
let token_data = decode::<Claims>(
&token,
Expand All @@ -51,6 +54,7 @@ fn encode_with_custom_header() {
.unwrap();
assert_eq!(my_claims, token_data.claims);
assert_eq!("kid", token_data.header.kid.unwrap());
assert_eq!("header", token_data.header.extra.unwrap().get("custom").unwrap().as_str());
}

#[test]
Expand Down
Loading