5

I'm trying to implement a Spring Boot Rest backend with JWT-security, based on Springs new authorization server and this example: https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/jwt/login

It uses Asymmetric keys to sign and verify tokens which seems like an overkill, since both authentication (where the token is generated) and authorization (verified) happens on the same server. So, to simplify deployment (just pass in a single secret via an environment variable), I have been trying to rewrite it to use a single shared secret. The example code implements two Bean-components, one to create the JwtEncoder (using a private RSA key) and one for the JWTDecoder (using the matching public key). I have rewritten the Decoder as explained in chapter 15 in the book “Spring Security in Action” so I assume this should work, since the NimbusJwtDecoder offers a withSecretKey method.

//Will eventually come via an environment variable
static byte[] secret = "j8IoV1jF67".getBytes();
@Bean
JwtDecoder jwtDecoder() {
  //      return NimbusJwtDecoder.withPublicKey(this.key).build();
  SecretKey theKey = new SecretKeySpec(secret, 0, secret.length, "AES");
  return NimbusJwtDecoder.withSecretKey(theKey).build();
}

I have implemented the Encoder, which is coursing the problem, like so (code commented out, is the original code using the private RSA Key:

@Bean
JwtEncoder jwtEncoder() {
  // JWK jwk = new RSAKey.Builder(this.key).privateKey(this.priv).build();
  // JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
  // return new NimbusJwtEncoder(jwks);
  SecretKey originalKey = new SecretKeySpec(secret, 0, secret.length, "AES");
  JWKSource<SecurityContext> immutableSecret = new ImmutableSecret<SecurityContext>(originalKey);
  return new NimbusJwtEncoder(immutableSecret);
}

When I login (via the POST /token endpoint) the line that uses the encoder:

return this.encoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();

Throws this exception

org.springframework.security.oauth2.jwt.JwtEncodingException: An error occurred while attempting to encode the Jwt: Failed to select a JWK signing key
    at org.springframework.security.oauth2.jwt.NimbusJwtEncoder.selectJwk(NimbusJwtEncoder.java:134)
    at org.springframework.security.oauth2.jwt.NimbusJwtEncoder.encode(NimbusJwtEncoder.java:108)

Any suggestions to how to implement this example with a simple shared secret, instead of asymmetric keys?

Plaul
  • 7,191
  • 5
  • 19
  • 22
  • https://github.com/spring-projects/spring-security/issues/10807 Similar to this? – Kryrena Nov 15 '22 at 05:46
  • No, its not similar to that question. In the `JwtGenerator` class `JwsAlgorithm ` is initialized: `JwsAlgorithm jwsAlgorithm = SignatureAlgorithm.RS256`. `NimbusJwtEncoder` class creates `JWKMatcher` which, based on the `JwsAlgorithm` expects the key to be of the RSA key type - `KeyType.RSA`. The reason why the exception `Failed to select a JWK signing key` happens is because this particular key (`Secret Key`) is of `KeyType.OCT` - `[{"kty":"oct","k":"ajhJb1YxakY2Nw"}] `. I'm not sure how to change the `JwsAlgorithm` to `JWSAlgorithm.Family.HMAC_SHA`, then the key should be found? – dplesa Nov 15 '22 at 08:42

0 Answers0