Open
Description
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
(orHS512
):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
andserde_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 ofjsonwebtoken
(8.x). - The library uses
URL_SAFE_NO_PAD
for Base64 decoding (correct) andserde_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.
Metadata
Metadata
Assignees
Labels
No labels