JSON Error When Decoding JWT with Nested Object in sub Claim
When decoding a JWT with a nested object in the sub claim, jsonwebtoken fails with the error Error::Json("expected ',' or '}'", line: 1, column: 8), despite the JSON payload being valid and manually deserializable.
Steps to Reproduce
- Use
jsonwebtoken version 9.3.0 (also tested with 8.x).
- Define a claim struct with a nested object in
sub:
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct SubClaims {
user_id: i32,
tenant_name: String,
tenant_id: i32,
}
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
sub: SubClaims,
exp: usize,
iss: String,
aud: String,
}
- Encode a token with
HS256 (or HS512):
use jsonwebtoken::{encode, Header, Algorithm, EncodingKey, Validation};
let claims = Claims {
sub: SubClaims {
user_id: 105,
tenant_name: "test".to_string(),
tenant_id: 1,
},
exp: 10000000000,
iss: "Issuer".to_string(),
aud: "Audience".to_string(),
};
let secret = "SOME SECRET";
let token = encode(
&Header::new(Algorithm::HS512),
&claims,
&EncodingKey::from_secret(secret.as_ref()),
).unwrap();
- Attempt to decode:
use jsonwebtoken::{decode, DecodingKey};
let mut validation = Validation::new(Algorithm::HS512);
validation.set_audience(&["Audience"]);
validation.set_issuer(&["Issuer"]);
let claims = decode::<Claims>(
&token,
&DecodingKey::from_secret(secret.as_ref()),
&validation,
);
Expected Behavior
The token should decode successfully into the Claims struct.
Actual Behavior
Decoding fails with Error::Json("expected ',' or '}'", line: 1, column: 8).
Additional Notes
- Manual deserialization of the payload using
serde_json::from_str and serde_json::from_slice works correctly:
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
let parts: Vec<&str> = token.split('.').collect();
let payload = parts[1];
let decoded = URL_SAFE_NO_PAD.decode(payload).unwrap();
let payload_str = String::from_utf8(decoded).unwrap();
let claims = serde_json::from_str::<Claims>(&payload_str).unwrap(); // Works
let claims = serde_json::from_slice::<Claims>(&decoded).unwrap(); // Works
- Decoding works with a simple
sub claim (e.g., sub: String):
#[derive(Debug, Serialize, Deserialize)]
struct SimpleClaims {
sub: String,
exp: usize,
iss: String,
aud: String,
}
- The issue persists with
HS256, HS512, and older versions of jsonwebtoken (8.x).
- The library uses
URL_SAFE_NO_PAD for Base64 decoding (correct) and serde_json::from_slice for deserialization.
- The raw bytes of the payload are valid UTF-8 and match the JSON:
Payload: {"sub":{"userId":105,"tenantName":"info","tenantId":1},"exp":10000000000,"iss":"Issuer","aud":"Audience"}
Environment
- Rust version: 1.82.0
- jsonwebtoken: 9.3.0 (also tested with 8.x)
- serde: 1.0.210
- serde_json: 1.0.128
- base64: 0.22
Possible Cause
The issue likely stems from jsonwebtoken passing an incorrect or truncated byte slice to serde_json::from_slice when deserializing a nested object in sub, or from a deserialization incompatibility with complex structures.
Request
Please investigate why jsonwebtoken::decode fails with nested objects in sub and provide a fix or clarification on whether complex sub claims are supported.
JSON Error When Decoding JWT with Nested Object in
subClaimWhen decoding a JWT with a nested object in the
subclaim,jsonwebtokenfails with the errorError::Json("expected ',' or '}'", line: 1, column: 8), despite the JSON payload being valid and manually deserializable.Steps to Reproduce
jsonwebtokenversion 9.3.0 (also tested with 8.x).sub:HS256(orHS512):Expected Behavior
The token should decode successfully into the
Claimsstruct.Actual Behavior
Decoding fails with
Error::Json("expected ',' or '}'", line: 1, column: 8).Additional Notes
serde_json::from_strandserde_json::from_sliceworks correctly:subclaim (e.g.,sub: String):HS256,HS512, and older versions ofjsonwebtoken(8.x).URL_SAFE_NO_PADfor Base64 decoding (correct) andserde_json::from_slicefor deserialization.Environment
Possible Cause
The issue likely stems from
jsonwebtokenpassing an incorrect or truncated byte slice toserde_json::from_slicewhen deserializing a nested object insub, or from a deserialization incompatibility with complex structures.Request
Please investigate why
jsonwebtoken::decodefails with nested objects insuband provide a fix or clarification on whether complexsubclaims are supported.