java-jwt erzeugt Tokens mit JWT.create()…sign(algorithm) und prüft sie mit JWT.require(algorithm)…build().verify(token). Das Objekt Algorithm trägt sowohl den Algorithmus als auch den Schlüssel, sodass ein Verifizierer immer nur diesen einen Algorithmus akzeptiert: Ein RS256-Token, ein unsigniertes Token und ein mit dem PEM-Text des EC-Schlüssels gefälschtes HS256-Token scheiterten an einem ES256-Verifizierer allesamt mit AlgorithmMismatchException.
Dieser Schutz greift nur, solange das Objekt Algorithm anhand der Konfiguration gewählt wird. JWT.require(Algorithm.none()) akzeptiert unsignierte Tokens, und mit Algorithm.HMAC256(pemBytes) bestand das gefälschte HS256-Token die Prüfung – Code, der das Objekt Algorithm anhand des Headers alg im Token auswählt oder Schlüssel als rohe Bytes lädt, bringt die Algorithm-Confusion-Fehler zurück, die die API sonst verhindert. JWT.decode() parst, ohne die Signatur oder irgendeinen Claim zu prüfen; die Methode gab ein Token zurück, das eine Stunde zuvor abgelaufen war.
Die verfügbaren Algorithmen sind HMAC256/384/512, RSA256/384/512 und ECDSA256/384/512 – kein PS256, kein ES256K und kein EdDSA –, sodass Tokens von Ausstellern, die auf RSA-PSS oder Ed25519 umgestiegen sind, Nimbus oder JJWT brauchen. ES256 lehnt einen P-384-Schlüssel schon beim Signieren ab.
ES256-Signaturen sind das 64 Byte lange rohe r‖s, und eine DER-Signatur scheitert mit der allgemeinen Meldung The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA; der JWT-Debugger zeigt die Länge der Signatur. Standardmäßig gibt es keine Toleranz (Leeway), und exp ist optional: Das Beispiel ergänzt neben der Prüfung des Ausstellers withClaimPresence("exp") und acceptLeeway(30).