I'm trying to decode and verify an EdDSA JWT using Spring Security in the role of a Resource Server. Spring doesn't seem to want to support EdDSA, so I started writing my own JwtDecoder that looks like this
class CustomJwtDecoder : JwtDecoder {
override fun decode(token: String): Jwt {
val signedJwt = SignedJWT.parse(token)
try {
val claimsSet = signedJwt.jwtClaimsSet
val headers = signedJwt.header
return Jwt(
token,
claimsSet.issueTime.toInstant(),
claimsSet.expirationTime.toInstant(),
headers.toJSONObject(),
claimsSet.claims,
)
} catch (ex: JOSEException) {
throw RuntimeException("Failed to decode JWT: ${ex.message}", ex)
}
}
}
For verifying these JWTs, I started looking at using tink via this dependency
<dependency>
<groupId>com.google.crypto.tink</groupId>
<artifactId>tink</artifactId>
<version>1.6.1</version>
</dependency>
However, when trying to verify a token with this library, the advice is to do something like this
val verifier: JWSVerifier = Ed25519Verifier(publicJWK)
But in this case, the publicJwk
here has to come from the jwks uri on the authentication server by mapping the kid
claim of the signedJwt
to the public key on the jwks uri. So the question is can I get the publicJwk from the jwks uri using standard spring mechanisms, or will I have to completely fork the nimbus-jose library to add support for EdDSA and then pull that into my project to override the Spring Security dependency?
Additionally, does the token verification have to go in the JwtDecoder, or does the verification come in in a different step of the Spring authN/authZ process? And how should that verification step look in this context?
If there's a better/simpler way to decode/verify the EdDSA JWT in the context of Spring Security, then I'd love to hear that as well.
To decode and verify EdDSA JWTs in Spring Security, you will need to integrate a library that supports EdDSA signatures, such as Nimbus JOSE+JWT or Google tink (soon to be in tink-crypto ), as you mentioned.
You would need to:
fetch the public key corresponding to the private key that was used to sign the JWT (to check the signature). Typically, this is available through a JWKS (JSON Web Key Set) endpoint. You can use
RestTemplate
or any HTTP client to fetch the JWKS and parse it to get the public key.verify the signature of the JWT (using the public key). Since you are using Tink, you can use
Ed25519Verifier
as you have mentioned. Alternatively, if you decide to use Nimbus JOSE+JWT, you can useEd25519Verifier
from that library.Your custom
JwtDecoder
should be responsible for both decoding the token and verifying its signature.Once your custom
JwtDecoder
is implemented, you will need to integrate it with Spring Security. You can do this by configuring it as a bean and using it as theJwtDecoder
in your security configuration.For instance:
This would show how you can create a custom
JwtDecoder
that verifies the signature of JWTs using the EdDSA algorithm and integrate it into Spring Security. ThegetPublicKey
method should contain the logic for fetching the public key from the JWKS endpoint. You can use Spring'sRestTemplate
for this purpose.That should allow you to integrate EdDSA JWTs into Spring Security without having to fork the Nimbus JOSE+JWT library or replace Spring Security's dependencies.