spring-projects / spring-projects/spring-security
NimbusJwtEncoder should select only private keys for signing JWTs
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.6k
- Forks
- 6.3k
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 52
Description
Expected Behavior
Given a JWKSource for a bunch of JWKs, the JWKSelector used in NimbusJwtEncoder should select for signing only JWKs that include the private key material.
Current Behavior
The JWKSelector selects privateOnly keys for HMAC_SHA but not for RSA or EC.
Context
NimbusJwtEncoder uses a JWKSelector to select candidate keys for signing the JWT. For HMAC-based algorithms (symmetric "signature") the selector includes privateOnly(true), correctly but arguably unnecessarily since symmetric keys are based on shared secrets, which are always private. Conversely, for RSA and EC algorithms (using private/public key-pairs) the selector does not include privateOnly(true), even though only private keys are suitable for JWT signing.
Having a JWKSource that exposes a set of keys where only the current signing key contains private key material, while older keys are retained as public-only JWKs for JWT verification, is a legitimate use case. This is a common pattern when signing keys are rotated regularly and previously issued JWTs must remain verifiable until they expire. However, it is not supported out of the box, as the JWKSelector would select both private and public-only keys, and it would fail with
Failed to select a key since there are multiple for the signing algorithm
I understand I can provide a custom Converter<List<JWK>, JWK> for further selection, e.g.:
Converter<List<JWK>, JWK> jwkConverter = jwks -> {
List<JWK> privateJwks = new ArrayList<>();
for (JWK jwk : jwks) {
if (jwk.isPrivate()) {
privateJwks.add(jwk);
}
}
if (privateJwks.size() != 1) {
throw new JwtEncodingException("...");
}
return privateJwks.getFirst();
};
but why is this the default behavior?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java around the JWKSelector at line 227. Inspect how RSA, EC, and HMAC candidates are selected for signing, then verify the behavior with a JWKSource containing private and public-only keys; done means signing selects only suitable private key material for rotated keys.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- backend, security
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100