Zum Inhalt springen
ecdsa.com
Ruby

ruby-jwt (jwt gem)

ruby-jwt, das Gem jwt, das die meisten Ruby- und Rails-Anwendungen nutzen: Ein explizites algorithm ist Pflicht, Schlüsseltypen werden geprüft, ES256K ist enthalten – aber EdDSA ist in 3.x in ein separates Gem gewandert, und kurze HMAC-Secrets werden stillschweigend akzeptiert.
Lizenz
MIT
Geprüfte Version
3.3.0 ·
Quellcode
github.com/jwt/ruby-jwt
Dokumentation
github.com/jwt/ruby-jwt#readme

Kompatibilität auf einen Blick

JOSE und JWT

JWS-Algorithmen
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512ES256KEdDSA

JWT.encode und JWT.decode decken HS, RS, PS und ES bei 256/384/512 sowie ES256K ab, aufgebaut auf dem openssl-Gem von Ruby. EdDSA gehört nicht mehr zum Gem jwt: Wenn nur jwt 3.3.0 geladen war, scheiterte das Kodieren mit EdDSA mit Unsupported signing method; es funktionierte erst nach dem Hinzufügen von jwt-eddsa – einem Gem, dessen native Abhängigkeit ed25519 bei der Installation einen C-Compiler braucht, der in schlanken Container-Images fehlt.

Die Prüfung verlangt, dass du den Algorithmus nennst: JWT.decode(token, key, true) ohne algorithm: scheiterte mit Expected a different algorithm. Unsignierte Tokens werden bei der Prüfung abgelehnt und lassen sich nur mit abgeschalteter Prüfung lesen (JWT.decode(token, nil, false)), was Code bei Tokens, denen er vertraut, nie tun sollte. Schlüsseltypen werden geprüft: Ein HS256-Token, das mit dem PEM-Text des EC-Schlüssels gefälscht wurde, scheiterte mit HMAC key expected to be a String, wenn der Prüfschlüssel das EC-Schlüsselobjekt war – wurde dagegen der PEM-String als HS256-Schlüssel übergeben, bestand es die Prüfung; verwende Schlüssel daher als Objekte vom Typ OpenSSL::PKey. ES256 lehnt einen P-384-Schlüssel schon beim Signieren ab.

Claim-Prüfungen musst du selbst aktivieren: keine Toleranz (Leeway), und exp ist optional, sofern der Claim nicht in required_claims steht – so macht es das Beispiel, zusammen mit dem Aussteller. HMAC-Secrets jeder Länge werden akzeptiert – mit einem 5-Byte-Schlüssel funktionierten Signieren und Prüfen ohne Warnung –, prüfe Secrets daher mit dem JWT-Secret-Checker.

ES256-Signaturen bestehen aus 64 Byte rohem r‖s; eine DER-Signatur scheitert mit Signature verification failed. Füge ein Token in den JWT-Debugger ein, um zu sehen, welche Kodierung es enthält.

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/ruby-jwt/run.sh hat ruby-jwt (jwt gem) 3.3.0 am 20. Oktober 2026 im Container-Image ruby:4.0.7-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 dem Gem jwt für HS, RS, PS und ES bei 256/384/512 sowie für ES256K; EdDSA erst nach dem Hinzufügen des Gems jwt-eddsa.

    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: EdDSA with only the jwt gem loaded: JWT::EncodeError: Unsupported signing method; after require "jwt/eddsa": ok
  • 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 JWT::VerificationError: Signature verification failed.

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

    required

    Die Prüfung ohne algorithm: scheitert mit JWT::IncorrectAlgorithm: Expected a different algorithm.

    Von der Prüfung aufgezeichnet
    fact jwt-algorithm-allowlist = required
    evidence jwt-algorithm-allowlist: JWT.decode with verify true and no algorithm option: JWT::IncorrectAlgorithm: Expected a different algorithm
  • Unsignierte Tokens (alg none)

    rejected

    Unsignierte Tokens scheitern bei der Prüfung mit Expected a different algorithm; lesen lassen sie sich nur mit verify = false.

    Von der Prüfung aufgezeichnet
    fact jwt-alg-none = rejected
    evidence jwt-alg-none: verify true, algorithm ES256: JWT::IncorrectAlgorithm: Expected a different algorithm; verify false: ok
  • Öffentlicher Schlüssel als HMAC-Secret

    rejected

    Ein HS256-Token mit dem PEM-Text als Schlüssel scheiterte am EC-Schlüsselobjekt mit HMAC key expected to be a String, bestand aber die Prüfung, wenn der PEM-String selbst als HS256-Schlüssel übergeben wurde.

    Von der Prüfung aufgezeichnet
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: algorithms [ES256, HS256] with the EC key object: JWT::VerificationKeyError: HMAC key expected to be a String
    evidence jwt-hmac-public-key: algorithm HS256 with the PEM string as key: ok
  • Abgleich der Kurve mit alg

    enforced

    Das Signieren mit ES256 und einem P-384-Schlüssel scheitert mit payload algorithm is ES256 but ES384 signing key was provided.

    Von der Prüfung aufgezeichnet
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: JWT::EncodeError: payload algorithm is ES256 but ES384 signing key was provided
  • 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 dekodieren; mit required_claims: ["exp"] scheitert es mit Missing required claim exp.

    Von der Prüfung aufgezeichnet
    fact jwt-exp-required = no
    evidence jwt-exp-required: with required_claims: ["exp"]: JWT::MissingRequiredClaim: Missing required claim exp
  • Kurzes HMAC-Secret

    accepted

    Ein HS256-Secret mit 5 Byte funktionierte beim Signieren und Prüfen ohne jede Warnung.

    Von der Prüfung aufgezeichnet
    fact jwt-hmac-short-secret = accepted
    evidence jwt-hmac-short-secret: 5-byte HS256 key: ok

Verwendung

Kodiere ein ES256-Token und dekodiere es, wobei der Algorithmus genannt ist, exp und iss verlangt werden und 30 Sekunden Toleranz gelten.
require "jwt"

key = OpenSSL::PKey::EC.generate("prime256v1")
public_key = OpenSSL::PKey.read(key.public_to_pem)
payload = { "sub" => "user-42", "iss" => "https://auth.example.com", "exp" => Time.now.to_i + 600 }
token = JWT.encode(payload, key, "ES256")

# Name the algorithm, require exp and iss, and allow some clock drift.
claims, header = JWT.decode(token, public_key, true,
                            algorithm: "ES256",
                            required_claims: %w[exp iss],
                            iss: "https://auth.example.com", verify_iss: true,
                            leeway: 30)
puts "sub: #{claims['sub']}, alg: #{header['alg']}"

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

Einrichtung
gem install --silent --no-document jwt -v 3.3.0
Befehl
ruby usage.rb
Ausgabe muss passen (regulärer Ausdruck)
sub: user-42, alg: ES256

Bibliotheken