pypi / pyjwt
pyjwt
What changed in pyjwt 2, from its official release notes, upgrade guides and advisories. Sources checked 2026-10-21.
7 breaking17 security1 new APIs and options2 behavior and defaults1 tooling7 fixes and other
See which of these apply to your code, ranked, in your agent:
npx @unstale/cli initpyjwt 235 changes
Breaking changes 7
The encoder adds b64 to crit, and the decoder rejects b64=false tokens that omit it.
Requires the compact-form payload segment to be empty for detached-payload JWS and no longer decodes that unused segment.
Rejects JWK-shaped JSON strings as HMAC keys, preventing algorithm confusion when symmetric and asymmetric algorithms are both allowed.
Empty HMAC keys now raise InvalidKeyError instead of being accepted with a warning.
Verification now requires the token header alg to match the algorithm bound to the PyJWK.
Rejects URIs whose scheme is not http or https, preventing access through unintended schemes.
The RFC 7515 crit header parameter is validated, affecting how tokens with critical header parameters are handled.
Security 17
PyJWT accepts inconsistent OKP x/d JWKs, causing public/private key identity confusion
PyJWT: Unauthenticated RecursionError DoS in pre-verification payload parse (PyJWKClient.get_signing_key_from_jwt / verify_signature=False)
PyJWT accepts public JWK containers as HMAC secrets
PyJWT: Asymmetric-PEM detection bypass: whitespace/line-ending-mutated public keys skip the HS/asymmetric confusion guard
PyJWT BOM Bypass
PyJWT: Malformed RSA JWK aborts parsing of an entire JWK Set
PyJWT: Non-canonical signature segments enable raw-token revocation bypass
PyJWT: Public keys in DER form are accepted as HMAC secrets, bypassing the CVE-2022-29217 guard
PyJWT: PyJWK accepts empty HMAC keys, bypassing PyJWT's empty-key validation
PyJWT: PyJWKClient follows redirects when fetching JWKS
PyJWT: PyJWKClient still amplifies unauthenticated JWKS fetches on unknown kid values (incomplete fix of CVE-2026-48524)
PyJWT: ReDoS vulnerability when calling the
is_pem_formatfunction.PyJWT: Uncaught RecursionError in jwt.decode() on deeply nested token header
A failed fetch no longer evicts valid cached JWK sets, so transient endpoint errors do not cause application-wide authentication failure.
Per-call options are forwarded to signature verification, so enforce_minimum_key_length now takes effect when passed to decode.
Keys are validated against the allowed types for their algorithm family.
Issuer claim type checks are added.
New APIs and options 1
PyJWKSet gains an iterator, allowing developers to iterate over its keys.
Behavior and default changes 2
Encoding without an explicit algorithm now uses the PyJWK algorithm.
Passing algorithm=None is mapped to the "none" algorithm.
Tooling 1
The PyJWKSet.keys annotation was updated for pyright.
Fixes and other changes 7
Adds typing_extensions as a dependency for Python versions below 3.11.
HTTPError is closed to prevent a ResourceWarning on Python 3.14.
PyJWK no longer stores a reference to the algorithms dict.
The options parameter's typing and logic are improved in decode and decode_complete.
The lifespan and timeout type annotations use float instead of int.
The method's type annotation is corrected.
PyJWT adds support for Python 3.14.