Zum Inhalt springen
ecdsa.com
Python

JWCrypto

JWCrypto von Red Hat, die JOSE-Implementierung von FreeIPA und vielen Python-Diensten in Unternehmen: vollständige Abdeckung von JWS/JWE/JWK einschließlich ML-DSA, standardmäßig 60 Sekunden Toleranz (Leeway) und alg: none nur auf ausdrücklichen Wunsch.
Lizenz
LGPL-3.0-or-later
Geprüfte Version
1.6.1 ·
Quellcode
github.com/latchset/jwcrypto
Dokumentation
jwcrypto.readthedocs.io/en/latest/

Kompatibilität auf einen Blick

JOSE und JWT

JWS-Algorithmen
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512ES256KEdDSAEd25519Ed448ML-DSA-44ML-DSA-65ML-DSA-87

JWCrypto implementiert die JOSE-Familie auf Basis von pyca/cryptography: JWK und JWK-Sets, JWS, JWE und JWT. Alles basiert auf Schlüsselobjekten – einem jwk.JWK, gebaut aus PEM, JSON oder generate() –, sodass der Schlüsseltyp bei jedem Aufruf explizit ist. Die Bibliothek steht unter der Lizenz LGPL-3.0-or-later, was eine Rolle spielt, wenn du veränderte Kopien weitergibst.

Unter den JOSE-Bibliotheken für Python hat JWCrypto den breitesten Algorithmusumfang: die Familien HS, RS, PS und ES, ES256K, EdDSA und die vollständig spezifizierten Ed25519 und Ed448 sowie in Version 1.6.1 auch ML-DSA-44, ML-DSA-65 und ML-DSA-87 mit Schlüsseln vom Typ AKP aus dem Entwurf für Post-Quanten-JOSE – mit allen funktionierten in der Prüfung Signieren und Prüfen, und alle stehen auf der Standardliste der zulässigen Algorithmen. Genau diese Standardliste ist der Haken: Wenn du algs nicht übergibst, wird jeder davon für einen passenden Schlüssel akzeptiert; schränke die Liste also auf das ein, was dein Aussteller tatsächlich verwendet, wie es das Beispiel tut.

Unsignierte Tokens werden mit Algorithm not allowed abgelehnt, sofern none nicht aufgeführt ist, und ein HS256-Token, das mit einem öffentlichen EC-JWK geprüft wird, scheitert, weil dieser Schlüsseltyp kein HMAC ausführen kann. ES256 lehnt einen P-384-Schlüssel mit Curve requested is "P-256", but key curve is "P-384" ab. ES256-Signaturen haben die 64 Byte lange rohe Form r‖s; eine DER-Signatur scheitert mit Verification failed for all signatures – prüfe die Kodierung im JWT-Debugger.

Zwei Standardeinstellungen weichen von anderen Bibliotheken ab. Die Ablaufprüfung lässt 60 Sekunden Uhrenabweichung zu: Ein Token, das 57 Sekunden zuvor abgelaufen war, galt noch als gültig, eines, das 63 Sekunden zuvor abgelaufen war, nicht – nachsichtiger als PyJWT oder jose, die keine Abweichung zulassen. Und exp ist optional: Ein Token ohne diesen Claim galt als gültig, sofern check_claims ihn nicht nennt.

Stelle Schlüsselsätze mit dem JWKS-Builder zusammen und untersuche verschlüsselte Tokens mit dem JWE-Inspektor; für ML-DSA-Schlüssel und -Signaturen zeigt der Playground für Post-Quanten-Signaturen die jeweiligen Größen.

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/jwcrypto/run.sh hat JWCrypto 1.6.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

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512ES256KEdDSAEd25519Ed448ML-DSA-44ML-DSA-65ML-DSA-87

    Signieren und Prüfen funktionierten mit HS, RS, PS und ES bei 256/384/512 Bit, mit ES256K, EdDSA, Ed25519, Ed448 und ML-DSA-44/65/87 (mit Schlüsseln vom Typ AKP); alle stehen auf der Standardliste der zulässigen Algorithmen.

    Von der Prüfung aufgezeichnet
    fact jws-algorithms = HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, ES256K, EdDSA, Ed25519, Ed448, ML-DSA-44, ML-DSA-65, ML-DSA-87
    evidence jws-algorithms: ML-DSA-44: JWK kty AKP
    evidence jws-algorithms: ML-DSA-65: JWK kty AKP
    evidence jws-algorithms: ML-DSA-87: JWK kty AKP
    evidence jws-algorithms: default allowed list: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384, PS512, EdDSA, ES256K, Ed25519, Ed448, ML-DSA-44, ML-DSA-65, ML-DSA-87
  • 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

    Eine DER-kodierte ES256-Signatur scheitert mit InvalidJWSSignature: Verification failed for all signatures.

    Von der Prüfung aufgezeichnet
    fact jws-der-signature = rejected
    evidence jws-der-signature: InvalidJWSSignature: Verification failed for all signatures["Failed: [InvalidJWSSignature('Verification failed')]"]
  • Allowlist der Algorithmen

    from-key

    Ohne algs gilt die Standardliste, und der Schlüsseltyp entscheidet: Ein ES256-Token bestand die Prüfung mit einem EC-Schlüssel, ein RS256-Token scheiterte an demselben Schlüssel.

    Von der Prüfung aufgezeichnet
    fact jwt-algorithm-allowlist = from-key
    evidence jwt-algorithm-allowlist: no algs argument: verified; RS256 token with the EC key: InvalidJWSSignature: Verification failed for all signatures["Failed: [InvalidJWSSignature('Verification failed')]"]
  • Unsignierte Tokens (alg none)

    opt-in

    Ein unsigniertes Token scheitert standardmäßig mit Algorithm not allowed und besteht die Prüfung nur mit algs=["none"].

    Von der Prüfung aufgezeichnet
    fact jwt-alg-none = opt-in
    evidence jwt-alg-none: with the EC key: InvalidJWSSignature: Verification failed for all signatures["Failed: [InvalidJWSOperation('Algorithm not allowed')]"]
    evidence jwt-alg-none: algs ['none'] with an empty oct key: verified
  • Öffentlicher Schlüssel als HMAC-Secret

    rejected

    Ein HS256-Token scheiterte am öffentlichen EC-JWK; erst mit einem gezielt gebauten JWK vom Typ oct, der den PEM-Text enthält, bestand es die Prüfung.

    Von der Prüfung aufgezeichnet
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: HS256 token checked with the EC public JWK: InvalidJWSSignature: Verification failed for all signatures["Failed: [InvalidJWSSignature('Verification failed')]"]
    evidence jwt-hmac-public-key: only an explicit oct JWK made from the PEM text verifies it: True
  • Abgleich der Kurve mit alg

    enforced

    Das Signieren mit ES256 und einem P-384-Schlüssel löst Curve requested is "P-256", but key curve is "P-384" aus.

    Von der Prüfung aufgezeichnet
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: InvalidJWKValue: Curve requested is "P-256", but key curve is "P-384"
  • Standardtoleranz für Uhrabweichungen

    60s

    Die Ablaufprüfung lässt standardmäßig 60 Sekunden Uhrenabweichung zu: Ein Token, das 57 Sekunden zuvor abgelaufen war, galt als gültig, eines, das 63 Sekunden zuvor abgelaufen war, nicht.

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

    no

    Ein Token ohne exp galt als gültig; führe exp in check_claims auf, um den Claim zur Pflicht zu machen.

    Von der Prüfung aufgezeichnet
    fact jwt-exp-required = no
    evidence jwt-exp-required: verified

Verwendung

Signiere ein ES256-Token mit Schlüssel-ID und prüfe es mit eingeschränkter Algorithmusliste und verpflichtendem iss und exp.
import json
import time

from jwcrypto import jwk, jwt

key = jwk.JWK.generate(kty="EC", crv="P-256", kid="2026-10")
public = jwk.JWK.from_json(key.export_public())

token = jwt.JWT(header={"alg": "ES256", "kid": "2026-10"}, claims={"sub": "user-42", "iss": "https://auth.example.com", "exp": int(time.time()) + 600})
token.make_signed_token(key)

# algs narrows the default list; check_claims makes iss and exp mandatory.
checked = jwt.JWT(
    jwt=token.serialize(),
    key=public,
    algs=["ES256"],
    check_claims={"iss": "https://auth.example.com", "exp": None},
)
print("sub:", json.loads(checked.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 jwcrypto==1.6.1 cryptography==50.0.2
Befehl
python usage.py
Ausgabe muss passen (regulärer Ausdruck)
sub: user-42

Bibliotheken