Zum Inhalt springen
ecdsa.com
Python

PyJWT

PyJWT von José Padilla, die meistgenutzte JWT-Bibliothek für Python: Eine explizite Liste algorithms ist Pflicht, alg: none besteht die Prüfung nie, und öffentliche Schlüssel werden als HMAC-Secrets abgelehnt – aber eine Ablaufzeit ist optional und die Toleranz (Leeway) null.
Lizenz
MIT
Geprüfte Version
2.15.1 ·
Quellcode
github.com/jpadilla/pyjwt
Dokumentation
pyjwt.readthedocs.io/en/stable/

Kompatibilität auf einen Blick

JOSE und JWT

JWS-Algorithmen
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512ES256KEdDSA

PyJWT kodiert und dekodiert JSON Web Tokens mit jwt.encode() und jwt.decode() und holt Signaturschlüssel mit PyJWKClient von einem JWKS-Endpunkt. Asymmetrische Algorithmen kommen über das Extra crypto, das pyca/cryptography mitinstalliert; damit beherrschte 2.15.1 die Familien HS, RS, PS und ES sowie ES256K und EdDSA, nicht aber die neueren Namen Ed25519 und Ed448, die NotImplementedError: Algorithm not supported auslösten.

Die Standardeinstellungen der Prüfung sind streng. jwt.decode() ohne algorithms scheitert mit It is required that you pass in a value for the "algorithms" argument, ein unsigniertes Token mit alg: none bestand die Prüfung nie – nicht einmal mit algorithms=["none"] –, und ein öffentlicher Schlüssel in PEM oder OpenSSH, als HS256-Secret verwendet, wurde mit InvalidKeyError abgelehnt. ES256 ist an P-256 gebunden: Das Signieren mit einem P-384-Schlüssel scheiterte, weil die Kurve nicht passte.

Was PyJWT dir überlässt: exp ist optional, sodass sich ein Token ohne diesen Claim für immer dekodieren lässt, sofern du ihn nicht im Argument options unter require aufführst, und leeway ist standardmäßig null, sodass Server, deren Uhren wenige Sekunden auseinanderliegen, schon uneins darüber sind, ob ein Token abgelaufen ist. Kurze HMAC-Secrets werden nur mit einer InsecureKeyLengthWarning akzeptiert, die in Logs leicht untergeht – teste ein Secret mit dem JWT-Secret-Checker.

ES256-Signaturen haben die 64 Byte lange rohe Form r‖s, die JWS verlangt; ein Token, dessen Signatur als DER zusammengesetzt wurde – etwa aus einem Signaturaufruf an ein KMS –, scheitert mit der allgemeinen Meldung Signature verification failed. Füge das Token in den JWT-Debugger ein, um die Länge der Signatur zu sehen, und konvertiere mit dem Konverter DER ⇄ Raw.

Das Beispiel legt Algorithmus, Aussteller und Audience fest, verlangt exp und lässt 30 Sekunden Uhrenabweichung zu – die vier Einstellungen, mit denen sich jwt.decode() gefahrlos auf Tokens eines anderen Dienstes anwenden lässt.

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/pyjwt/run.sh hat PyJWT 2.15.1 unter cryptography 50.0.2 am 20. Oktober 2026 im Container-Image python:3.14.8-slim-trixie ausgeführt; die Seite muss mit seiner Ausgabe übereinstimmen, und jeder Fakt führt die zugehörigen Zeilen auf.

  • JWS-Algorithmen

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512ES256KEdDSA

    Signieren und Prüfen funktionierten mit HS, RS, PS und ES bei 256/384/512 Bit sowie mit ES256K und EdDSA; Ed25519 und Ed448 lösten NotImplementedError: Algorithm not supported aus.

    Von der Prüfung aufgezeichnet
    fact jws-algorithms = HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, ES256K, EdDSA
    evidence jws-algorithms: Ed25519: NotImplementedError: Algorithm not supported
    evidence jws-algorithms: Ed448: NotImplementedError: Algorithm not supported
  • Kodierung von ES256-Signaturen

    raw

    ES256-Signaturen bestehen aus 64 Byte rohem r‖s.

    Von der Prüfung aufgezeichnet
    fact jws-ecdsa-encoding = raw
  • DER-Signatur in einer JWS

    rejected

    Ein Token mit einer DER-kodierten ES256-Signatur scheitert mit InvalidSignatureError: Signature verification failed.

    Von der Prüfung aufgezeichnet
    fact jws-der-signature = rejected
    evidence jws-der-signature: InvalidSignatureError: Signature verification failed
  • Allowlist der Algorithmen

    required

    jwt.decode() ohne algorithms löst DecodeError: It is required that you pass in a value for the "algorithms" argument when calling decode(). aus.

    Von der Prüfung aufgezeichnet
    fact jwt-algorithm-allowlist = required
    evidence jwt-algorithm-allowlist: DecodeError: It is required that you pass in a value for the "algorithms" argument when calling decode().
  • Unsignierte Tokens (alg none)

    rejected

    Ein unsigniertes Token wird gegen einen ES256-Schlüssel mit The specified alg value is not allowed abgelehnt und selbst mit algorithms=["none"] mit Signature verification failed; lesen lässt es sich nur mit verify_signature: False.

    Von der Prüfung aufgezeichnet
    fact jwt-alg-none = rejected
    evidence jwt-alg-none: with an ES256 key: InvalidAlgorithmError: The specified alg value is not allowed
    evidence jwt-alg-none: algorithms ['none'] and no key: InvalidSignatureError: Signature verification failed
    evidence jwt-alg-none: verify_signature False: returned claims
  • Öffentlicher Schlüssel als HMAC-Secret

    rejected

    Ein öffentlicher Schlüssel in PEM oder OpenSSH, als HS256-Secret verwendet, löst InvalidKeyError: The specified key is an asymmetric key or x509 certificate and should not be used as an HMAC secret. aus.

    Von der Prüfung aufgezeichnet
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: PEM public key as HS256 secret: InvalidKeyError: The specified key is an asymmetric key or x509 certificate and should not be used as an HMAC secret.
    evidence jwt-hmac-public-key: OpenSSH public key as HS256 secret: InvalidKeyError: The specified key is an asymmetric key or x509 certificate and should not be used as an HMAC secret.
  • Abgleich der Kurve mit alg

    enforced

    Das Signieren mit ES256 und einem P-384-Schlüssel löst The key's curve 'secp384r1' does not match the expected curve 'secp256r1' for this algorithm aus.

    Von der Prüfung aufgezeichnet
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: InvalidKeyError: The key's curve 'secp384r1' does not match the expected curve 'secp256r1' for this algorithm
  • Standardtoleranz für Uhrabweichungen

    0s

    Standardmäßig keine Toleranz (Leeway): Ein Token, das drei Sekunden zuvor abgelaufen war, wurde abgelehnt.

    Von der Prüfung aufgezeichnet
    fact jwt-clock-skew = 0s
  • Ablauf-Claim erforderlich

    no

    Ein Token ohne exp ließ sich erfolgreich dekodieren; mach den Claim zur Pflicht, indem du exp im Argument options unter require aufführst.

    Von der Prüfung aufgezeichnet
    fact jwt-exp-required = no
  • Kurzes HMAC-Secret

    accepted-with-warning

    Ein HMAC-Secret mit 5 Byte funktionierte beim Signieren und Prüfen; einziger Hinweis war eine InsecureKeyLengthWarning.

    Von der Prüfung aufgezeichnet
    fact jwt-hmac-short-secret = accepted-with-warning
    evidence jwt-hmac-short-secret: 5-byte HMAC secret: accepted; warnings: InsecureKeyLengthWarning

Verwendung

Stelle ein ES256-Token aus und dekodiere es, wobei Algorithmus, Aussteller und Audience festgelegt sind, exp verlangt wird und 30 Sekunden Toleranz gelten.
import datetime

import jwt
from cryptography.hazmat.primitives.asymmetric import ec

key = ec.generate_private_key(ec.SECP256R1())
now = datetime.datetime.now(tz=datetime.timezone.utc)

token = jwt.encode(
    {"sub": "user-42", "iss": "https://auth.example.com", "aud": "api", "exp": now + datetime.timedelta(minutes=10)},
    key,
    algorithm="ES256",
)

# algorithms is mandatory; also require exp and allow a little clock drift.
claims = jwt.decode(
    token,
    key.public_key(),
    algorithms=["ES256"],
    audience="api",
    issuer="https://auth.example.com",
    leeway=30,
    options={"require": ["exp", "iss", "aud"]},
)
print("sub:", claims["sub"])

Die Snippet-Testumgebung führt jedes Beispiel unverändert im Container-Image python:3.14.8-slim-trixie aus, und der Lauf schlägt fehl, wenn die Ausgabe nicht übereinstimmt.

Einrichtung
pip install --quiet --root-user-action=ignore 'PyJWT[crypto]==2.15.1' cryptography==50.0.2
Befehl
python usage.py
Ausgabe muss passen (regulärer Ausdruck)
sub: user-42

Bibliotheken