9

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?

codeme
  • 861
  • 2
  • 12
  • 29

2 Answers2

15

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 https://github.com/jwtk/jjwt#jws-key-create :

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);
Les Hazlewood
  • 18,480
  • 13
  • 68
  • 76
  • Hello, i'm wondering why at the end of the token generation you added : expiration(expirationDateTime.toString()).build() after setting up setExpiration(Date.from(expirationDateTime)) – aurny2420289 Sep 29 '19 at 14:40
  • @aurny2420289 it was just a copy-paste of the OP's question content. What you're seeing is a chaining of their `JwtToken.builder().value(...)` API, which is not JJWT's API. So I don't know what that class does. – Les Hazlewood Sep 30 '19 at 16:19
  • @LesHazlewood , I'm using HS512 with ```Keys.secretKeyFor(SignatureAlgorithm.HS256);```. Once I generated the key where and how I could store the key for future validations when a request comes in with access_token generated with the method. Considering during validation of the request I should use the same secret . I use Spring boot 2.2.5. Any leads? – Rajesh2389 Feb 03 '21 at 08:02
  • @Rajesh2389 ideally in one of your `@Configuration` classes, you convert the String into a `Key` instance and that would be a bean that you could reference elsewhere. Spring will create only one instance of it if you reference it as a bean. – Les Hazlewood Feb 16 '21 at 01:09
2

Please see my answer to a similar question.

https://stackoverflow.com/a/71149603/1808417

//Generating a safe HS256 Secret key
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS512);
String secretString = Encoders.BASE64.encode(key.getEncoded());
logger.info("Secret key: " + secretString);
ACV
  • 9,964
  • 5
  • 76
  • 81
saneryee
  • 3,239
  • 31
  • 22