spring-bootspring-securityjjwt

How to create a Spring Security Key for signing a JWT token?


I use implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.10.6' as dependency.

I would like to create a JWT token as follows:

@Value("${jwt.token.secret}")
private Key secret;

JwtToken.builder().value(Jwts.builder()
                .setClaims(createClaims(account))
                .setSubject(subject.toString())
                .setIssuedAt(Date.from(createdDateTime))
                .setExpiration(Date.from(expirationDateTime))
                .signWith(secret)
                .compact()).expiration(expirationDateTime.toString()).build()

I have used to provide a String in the application.properties and reference that key as shown above, but giving a String as a secretkey is deprecated. How should I create the Key secret?


Solution

  • You need to convert the key string to a Java Key instance.

    Is your key string Base64-encoded? If so, do this:

    @Value("${jwt.token.secret}")
    private String secret;
    
    private Key getSigningKey() {
      byte[] keyBytes = Decoders.BASE64.decode(this.secret);
      return Keys.hmacShaKeyFor(keyBytes);
    }
    
    JwtToken.builder().value(Jwts.builder()
                    .setClaims(createClaims(account))
                    .setSubject(subject.toString())
                    .setIssuedAt(Date.from(createdDateTime))
                    .setExpiration(Date.from(expirationDateTime))
                    .signWith(getSigningKey())
                    .compact()).expiration(expirationDateTime.toString()).build()
    

    If your key is not base64-encoded (and it probably should be, because if you're using a raw password for example, your key is probably incorrect or not well formed), you can do that via:

    private Key getSigningKey() {
      byte[] keyBytes = this.secret.getBytes(StandardCharsets.UTF_8);
      return Keys.hmacShaKeyFor(keyBytes);
    }
    

    This second example is generally not recommended however because it likely means you have a poorly formed key. A well-formed, secure-random key is not human-readable, so to store it as a string, the key bytes are usually base64 encoded first.

    From the documentation :

    If you want to generate a sufficiently strong SecretKey for use with the JWT HMAC-SHA algorithms, use the Keys.secretKeyFor(SignatureAlgorithm) helper method:

    SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); //or HS384 or HS512
    

    Under the hood, JJWT uses the JCA provider's KeyGenerator to create a secure-random key with the correct minimum length for the given algorithm.

    If you have an existing HMAC SHA SecretKey's encoded byte array, you can use the Keys.hmacShaKeyFor helper method. For example:

    byte[] keyBytes = getSigningKeyFromApplicationConfiguration();
    SecretKey key = Keys.hmacShaKeyFor(keyBytes);