Description
It is currently possible to create a NimbusJwtEncoder
using an ImmutableJWKSet
that contains an Ed25519 key (via OctetKeyPair
), but it is not possible to use that encoder to generate a JWT signed with Ed25519 (EdDSA).
Problem Details
JwtEncoderParameters.from(header, claims)
does not allow custom algorithms in the header.- Only enums implementing
JwsAlgorithm
orJwaAlgorithm
are allowed. - The default
SignatureAlgorithm
enum implementsJwsAlgorithm
, but does not include any EdDSA algorithms likeEdDSA
(com.nimbusds.jose.JWSAlgorithm.EdDSA
). - Even if a custom implementation of
JwsAlgorithm
is provided to represent EdDSA, it does not resolve the problem because of howNimbusJwtEncoder
internally selects a signing key. - During encoding, the
selectJwk
method is called. This uses aJWKSelector
created with a matcher generated by the privatecreateJwkMatcher
method. - Unfortunately,
createJwkMatcher
does not support the EdDSA algorithm family, which results in the JWKSelector being constructed with a null matcher. - This causes
IllegalArgumentException
to be thrown at runtime due to the missing matcher.
When running following code:
val header = JwsHeader.with(FixedSignatureAlgorithm.Ed25519).build()
val claims = JwtClaimsSet.builder()
.issuer(issuer)
.issuedAt(Instant.now())
.expiresAt(expiresAt)
.claim(SESSION_ID_CLAIM_NAME, sessionId)
.build()
jwtEncoder.encode(JwtEncoderParameters.from(header, claims)).tokenValue
public enum FixedSignatureAlgorithm implements JwsAlgorithm {
RS256(JwsAlgorithms.RS256),
RS384(JwsAlgorithms.RS384),
RS512(JwsAlgorithms.RS512),
ES256(JwsAlgorithms.ES256),
ES384(JwsAlgorithms.ES384),
ES512(JwsAlgorithms.ES512),
PS256(JwsAlgorithms.PS256),
PS384(JwsAlgorithms.PS384),
PS512(JwsAlgorithms.PS512),
EdDSA(JWSAlgorithm.EdDSA.getName()),
Ed25519(JWSAlgorithm.Ed25519.getName());
private final String name;
FixedSignatureAlgorithm(String name) {
this.name = name;
}
@Override
public String getName() {
return this.name;
}
public static FixedSignatureAlgorithm from(String name) {
for (FixedSignatureAlgorithm value : values()) {
if (value.getName().equals(name)) {
return value;
}
}
return null;
}
}
then such error is thrown:
org.springframework.security.oauth2.jwt.JwtEncodingException: An error occurred while attempting to encode the Jwt: Failed to select a JWK signing key -> The JWK matcher must not be null
at org.springframework.security.oauth2.jwt.NimbusJwtEncoder.selectJwk(NimbusJwtEncoder.java:123)
at org.springframework.security.oauth2.jwt.NimbusJwtEncoder.encode(NimbusJwtEncoder.java:108)
Caused by: java.lang.IllegalArgumentException: The JWK matcher must not be null
at com.nimbusds.jose.jwk.JWKSelector.<init>(JWKSelector.java:51)
at org.springframework.security.oauth2.jwt.NimbusJwtEncoder.selectJwk(NimbusJwtEncoder.java:119)
... 158 common frames omitted
Suggested fix
To support Ed25519/EdDSA, the following would need to be addressed:
1. Add EdDSA (JWSAlgorithm.EdDSA
) support to the SignatureAlgorithm
enum or allow flexible/custom algorithm headers in JwtEncoderParameters
.
2. Update createJwkMatcher
in NimbusJwtEncoder
to recognize and match EdDSA algorithm family keys like OctetKeyPair
with Curve.Ed25519
.
Used versions com.springframework.security:spring-security-oauth2-jose:6.3.3 com.nimbusds:nimbus-jose-jwt:9.40