spring-projects/spring-security · error · JwtEncodingException

Failed to encode the JWT due to signing error: Failed to…

Error message

Failed to encode the JWT due to signing error: Failed to select a JWK signing key

What it means

NimbusJwtEncoder.selectJwk throws this when the JWKSource query succeeds but returns an empty key list — no JWK in the source matches the JWT's headers (algorithm, key use, key ID, etc.). Without a signing key the JWT cannot be encoded, so a JwtEncodingException is raised with the static message "Failed to select a JWK signing key".

Solutions

  1. Ensure the JWKSource contains at least one signing key supporting the requested algorithm: generate with e.g. com.nimbusds.jose.jwk.KeyUse.SIGNATURE and the matching KeyType.
  2. Match the algorithm in JwtEncoderParameters' JwsHeader to an available key's algorithm, or add the required key to the JWKSet.
  3. Verify each JWK has use = KeyUse.SIGNATURE (or no use restriction) so the JWKSelector matcher can match it.
  4. If headers carry a kid, confirm it exactly matches a getKeyID() of a key in the source (or omit kid).
  5. Print/log jwkSource.get(new JWKSelector(new JWKMatcher.Builder().build()), null) to see what keys are actually available and adjust the request.

Example fix

// before
RSAKey rsaKey = new RSAKey.Builder(publicKey).privateKey(privateKey).keyID("k1").build(); // no key use
JWKSet jwkSet = new JWKSet(rsaKey);
// after
RSAKey rsaKey = new RSAKey.Builder(publicKey).privateKey(privateKey).keyID("k1")
	.keyUse(KeyUse.SIGNATURE).algorithm(JWSAlgorithm.RS256).build();
JWKSet jwkSet = new JWKSet(rsaKey);
// and request the same algorithm:
JwsHeader.with(JWSAlgorithm.RS256).build();
Defensive patterns

Strategy: validation

Validate before calling

// Before encoding, verify a key matching the requested algorithm exists in the source
JwsHeader header = params.getJwsHeaders();
String alg = header.getAlgorithm().getName();
List<JWK> matches = jwkSource.get(
	new JWKSelector(new JWKMatcher.Builder().algorithm(alg).build()), null);
if (matches.isEmpty()) {
	throw new IllegalStateException(
		"No JWK for algorithm " + alg + "; JWKSet contains: "
			+ jwkSource.get(new JWKSelector(new JWKMatcher.Builder().build()), null));
}

Try / catch

try {
	Jwt jwt = encoder.encode(params);
} catch (org.springframework.security.oauth2.jwt.JwtEncodingException ex) {
	if (ex.getMessage().endsWith("Failed to select a JWK signing key")) {
		log.error("No JWK matched headers alg={}; check JWKSet keys, key use, and kid",
			params.getJwsHeaders().getAlgorithm());
	}
	throw ex;
}

Prevention

When it happens

Trigger: encode(JwtEncoderParameters) whose JWS header algorithm (e.g. RS256, ES256) or kid does not match any key in the configured JWKSet/JWKSource — e.g. source holds only an EC key while the parameters request RSA256, no "use":"sig" set, or the kid in headers doesn't exist in the key set.

Common situations: Mismatch between the JWKSet loaded into NimbusJwtEncoder and the JWSAlgorithm passed in JwsHeader.withAlgorithm(...); keys created without "use":"sig"; kid typos after key rotation; using an octet (symmetric) key where an asymmetric one is required or vice versa; empty/default-constructed JWKSet.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/d974943895895ca0. Report an issue: GitHub.

Appendix: source

Thrown at oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java:201

		headers = addKeyIdentifierHeadersIfNecessary(headers, jwk);

		String jws = serialize(headers, claims, jwk);

		return new Jwt(jws, claims.getIssuedAt(), claims.getExpiresAt(), headers.getHeaders(), claims.getClaims());
	}

	private JWK selectJwk(JwsHeader headers) {
		List<JWK> jwks;
		try {
			JWKSelector jwkSelector = new JWKSelector(createJwkMatcher(headers));
			jwks = this.jwkSource.get(jwkSelector, null);
		}
		catch (Exception ex) {
			throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE,
					"Failed to select a JWK signing key -> " + ex.getMessage()), ex);
		}
		if (jwks.isEmpty()) {
			throw new JwtEncodingException(
					String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, "Failed to select a JWK signing key"));
		}
		if (jwks.size() == 1) {
			return jwks.get(0);
		}
		return this.jwkSelector.convert(jwks);
	}

	private String serialize(JwsHeader headers, JwtClaimsSet claims, JWK jwk) {
		JWSHeader jwsHeader = convert(headers);
		JWTClaimsSet jwtClaimsSet = convert(claims);

		JWSSigner jwsSigner = this.jwsSigners.computeIfAbsent(jwk, NimbusJwtEncoder::createSigner);

		SignedJWT signedJwt = new SignedJWT(jwsHeader, jwtClaimsSet);
		try {
			signedJwt.sign(jwsSigner);
		}

View on GitHub (pinned to 96852e8860)