fix: crash when decoding JWTs with null 'kid' header#1177
Conversation
auvipy
left a comment
There was a problem hiding this comment.
tests are failing. please cross check
There was a problem hiding this comment.
Pull request overview
This PR aims to restore decoding compatibility for JWTs whose JOSE header explicitly contains "kid": null, while preserving header validation behavior elsewhere in PyJWT.
Changes:
- Adjusts JWS header validation to skip
kidtype validation when the value isNone. - Adds a JWT decode regression test for tokens with a null
kidheader.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
jwt/api_jws.py |
Updates kid validation logic in shared JWS header validation. |
tests/test_api_jwt.py |
Adds coverage for decoding a JWT with an explicit null kid header. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| token = jwt.encode( | ||
| payload, | ||
| secret, | ||
| headers={"kid": None}, | ||
| ) |
There was a problem hiding this comment.
I have refactored the test to use a pre-encoded, signed JWT string literal with a null 'kid' header (and 'iss': 'teebee' as payload).
7ea0462 to
b94b58b
Compare
|
Hi @auvipy, thank you for the feedback! I have refactored the test to use a pre-encoded, signed JWT string literal with a null 'kid' header (and 'iss': 'teebee' as payload). This completely isolates the decoder behavior, removes the runtime dependency on The fix and the refined test are now bundled into the amended commit. |
Commit 051ea34 introduced _validate_headers during decoding, which triggers an InvalidTokenError if the 'kid' header property is explicitly set to null (None in Python). According to RFC 7515, 'kid' is optional, and while typically omitted, some Identity Providers emit 'kid': null by default. This change ensures _validate_kid is only executed if 'kid' is present and not None, restoring compatibility with Confluent MDS tokens, for instance. Signed-off-by: teebee <733833@gmx.de>
b94b58b to
af5349b
Compare
|
Hi @auvipy, I have updated the branch. I refined |
|
Hi @auvipy, Just a quick heads-up and my apologies: While integrating the suggestions from Copilot, my local git history got a bit tangled, and I accidentally overwrote your explicit commit (7ea0462). I honestly didn't notice your commit at the time, so please don't think I was trying to "improve" or discard your work on purpose! However, I kept your exact logic intact. I just split it into a nested if "kid" in headers:
# When decoding, treat a null-valued 'kid' header parameter
# the same as if the parameter was omitted entirely.
if encoding or headers["kid"] is not None:
self._validate_kid(headers["kid"])The logic remains 100% equivalent to your flat If you prefer your original single-line statement for the sake of the history or clean hierarchy, please feel free to overwrite or amend this section directly. Sorry again for the mix-up! |
|
there is not need for force push |
Description
This PR fixes a regression introduced in commit 051ea34 (#GHSA-752w-5fwx-jx9f) where JWTs containing an explicit
nullvalue for thekidheader parameter causedecode()to crash with anInvalidTokenError: Key ID header parameter must be a string.According to RFC 7515, the
kidparameter is optional. While it is usually omitted, some Identity Providers emit"kid": nullwhen no specific key ID is assigned. Prior to thecritheader validation update in v2.12.0, PyJWT safely ignored this during decoding.Real-world Impact
This is not just a theoretical RFC edge-case. For example, the Confluent Kafka Metadata Server (MDS) issues production-level JWT tokens that explicitly include
"kid": nullin their header.Due to the recent regression, any Python-based Kafka client or microservice trying to validate Confluent Kafka MDS tokens using PyJWT will instantly crash.
Changes
_validate_headersinjwt/api_jws.pyto only trigger_validate_kidifkidis present and notNone.tests/test_api_jwt.pyto ensure tokens withnullkeys are correctly tolerated during decoding without introducing regressions to other components.