Skip to content

Signature algorithms

This framework comes with several signature algorithms. These algorithms are in the following namespace: Jose\Component\Signature\Algorithm.

Algorithm Description
HS256
HS384
HS512
HMAC with SHA-2 Functions
ES256
ES384
ES512
Elliptic Curve Digital Signature Algorithm (ECDSA)
ES256K ECDSA over the secp256k1 curve with SHA-256 (RFC 8812). Since 4.3, see below
RS256
RS384
RS512
RSASSA-PKCS1 v1_5
PS256
PS384
PS512
RSASSA-PSS
Ed25519
Ed448
Edwards-curve Digital Signature Algorithm (EdDSA), fully-specified per RFC 9864. Since 4.3; Ed448 needs PHP 8.4
ML-DSA-44
ML-DSA-65
ML-DSA-87
Module-Lattice-Based Digital Signature Algorithm (ML-DSA, FIPS 204), post-quantum, per RFC 9964. Since 4.3; needs PHP 8.4 and OpenSSL 3.5
EdDSA (only with the Ed25519 curve) Deprecated by RFC 9864, use Ed25519. See below
none Not a secure algorithm. Please use with caution

The ES256K algorithm

ES256K — ECDSA over the secp256k1 curve with SHA-256, RFC 8812 — is a standard algorithm that lived in the experimental package for historical reasons. Since 4.3 it is Jose\Component\Signature\Algorithm\ES256K, next to ES256, and the Symfony Bundle registers it under the ES256K alias like any other algorithm. Keys are EC keys with crv: secp256k1; an ES256KKeyAnalyzer checks them.

<?php

use Jose\Component\Signature\Algorithm\ES256K;

Warning

Jose\Experimental\Signature\ES256K still works — it is a deprecated subclass of the new class, and the bundle keeps its service for the applications that inject it — but it is removed in 5.0. Change the use statement.

Known limitation, unchanged: a secp256k1 key exported to PEM cannot be loaded back through the key loader on some OpenSSL builds. Keep such keys as JWK.

The Ed25519 and Ed448 algorithms

RFC 9864 registers the fully-specified Ed25519 and Ed448 algorithms and deprecates the polymorphic EdDSA: the name of the algorithm alone must say which curve is in use. The keys are unchanged — an OKP key with crv: Ed25519 or crv: Ed448 — only the alg value differs.

<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Signature\Algorithm\Ed25519;
use Jose\Component\Signature\Algorithm\Ed448;

$algorithmManager = new AlgorithmManager([new Ed25519(), new Ed448()]);

Each algorithm accepts its own curve only: Ed25519 refuses a key on Ed448 and Ed448 a key on Ed25519, with an InvalidKeyException.

  • Ed25519 runs on the sodium extension when it is loaded, as EdDSA always did, and on OpenSSL otherwise (PHP 8.4 or later).
  • Ed448 runs on OpenSSL only, and needs PHP 8.4 or later — before that version PHP cannot ask OpenSSL for the digest-less signature the Edwards curves require. Ed448::isSupported() tells whether the platform can run it; the constructor throws a MissingDependencyException when it cannot, and the Symfony Bundle registers the algorithm only when it can run.

Warning

EdDSA is deprecated since 4.3. It keeps working — the tokens already in circulation still verify — and signing with it raises a deprecation notice. Migrate the issuer first, then the verifiers:

  1. register Ed25519 next to EdDSA on the verifiers, so that both alg values are accepted;
  2. switch the issuer to Ed25519: same key, alg: Ed25519 in the header;
  3. once no EdDSA token is in circulation any more, drop EdDSA from the verifiers.

A key carrying alg: EdDSA is refused by the Ed25519 algorithm, and a key carrying alg: Ed25519 by EdDSA: update the alg of the keys with the issuer, or leave it out during the migration. The key analyzer reports keys still declaring alg: EdDSA.

The ML-DSA-44, ML-DSA-65 and ML-DSA-87 algorithms

RFC 9964 registers ML-DSA (FIPS 204, the module-lattice signature scheme) for JOSE: the first post-quantum signature of the registries. The three parameter sets are the pure ML-DSA of FIPS 204 with an empty context — no HashML-DSA, which section 7.2 of the RFC excludes.

The keys are of the AKP type (section 3), with pub the encoded public key and priv the 32-byte seed — the only private key representation the RFC allows (section 4), from which the whole key is derived. alg is required on every AKP key: the type says nothing about the algorithm.

<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\KeyManagement\JWKFactory;
use Jose\Component\Signature\Algorithm\MLDSA44;
use Jose\Component\Signature\Algorithm\MLDSA65;
use Jose\Component\Signature\Algorithm\MLDSA87;

$algorithmManager = new AlgorithmManager([new MLDSA44(), new MLDSA65(), new MLDSA87()]);

$key = (new JWKFactory())->mldsa('ML-DSA-65', ['use' => 'sig']);
// {"kty":"AKP","alg":"ML-DSA-65","pub":"...","priv":"...32-byte seed...","use":"sig"}

Before OpenSSL sees a key, the algorithm checks it as section 7.3 requires: alg present and equal to the algorithm, pub of the size of the parameter set (1312, 1952 or 2592 bytes), priv of exactly 32 bytes, and — when the key carries both — that pub is the key the seed expands to. Signatures are 2420, 3309 or 4627 bytes; a signature of another length is false before any computation.

Warning

Platform requirement. The computation is OpenSSL's, and needs PHP 8.4 (the first version able to sign without a digest through OpenSSL) and an OpenSSL 3.5 runtime. The OpenSSL check is a runtime probe — OPENSSL_VERSION_TEXT reports the headers PHP was built against, not the library it loaded — so MLDSA44::isSupported() tells whether the platform can run the algorithms; the constructors throw a MissingDependencyException naming the missing piece, and the Symfony Bundle registers the algorithms only when they can run.

The none algorithm

Since 4.3, none lives in its own package, so that enabling it is an explicit and auditable decision:

composer require web-token/jwt-unsecured
<?php

use Jose\Unsecured\Signature\None;

It is deliberately not part of web-token/jwt-experimental: none is perfectly standard, and an application asking for Blake2b should not get it in the bargain.

Warning

Jose\Component\Signature\Algorithm\None still works — it is an empty subclass of the new class — but it is deprecated since 4.3 and removed in 5.0. In the Symfony Bundle, the configuration alias is unchanged: none still names the algorithm.

Danger

none disables signature verification altogether. Read Security Recommendations before enabling it.

Experimental algorithms

The following signature algorithms are experimental and must not be used in production unless you know what you are doing. They are proposed for testing purpose only.

They are provided through the package web-token/jwt-experimental.

Algorithm Description
RS1 RSASSA-PKCS1 v1_5 with SHA-1 hashing function
HS1 HMAC with SHA-1 hashing function
HS256/64 HMAC with SHA-256 truncated to 64 bits
BP256R1 ECDSA using the brainpoolP256r1 curve (BP-256) and SHA-256
BP384R1 ECDSA using the brainpoolP384r1 curve (BP-384) and SHA-384
BP512R1 ECDSA using the brainpoolP512r1 curve (BP-512) and SHA-512
Blake2b Blake2b MAC algorithm. Sodium extension required

Warning

The Brainpool algorithms and their curves are not registered with IANA. The identifiers BP256R1/BP384R1/BP512R1 and BP-256/BP-384/BP-512 follow the convention already adopted by the other implementations, so tokens using them are only interoperable with the implementations sharing that convention.

The curves themselves are part of the core library: creating a Brainpool key or using one with ECDH-ES/ECDH-SS does not require the experimental package.

How to use

These algorithms have to be used with the Algorithm Manager. They do not need any arguments.

Example:

<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Signature\Algorithm\PS256;
use Jose\Component\Signature\Algorithm\ES512;
use Jose\Component\Signature\Algorithm\None;

$algorithm_manager = new AlgorithmManager([
    new PS256(),
    new ES512(),
    new None(),
]);