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

2

16

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?

Openhearted answered 11/3, 2019 at 13:29 Comment(2)
why are you using io.jsonwebtoken:jjwt-api instead of io.jsonwebtoken:jjwt' version: '0.9.1' ?Boser
@AbdelghaniRoussi because JJWT >= 0.10.0 split the dependencies to ensure proper plugin usage.Kristoforo
K
23

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);
Kristoforo answered 10/4, 2019 at 20:21 Comment(4)
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))Airtight
@Airtight 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.Kristoforo
@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?Surfeit
@Surfeit 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.Kristoforo
P
5

Please see my answer to a similar question.

//Generating a safe HS256 Secret key
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS512);
String secretString = Encoders.BASE64.encode(key.getEncoded());
logger.info("Secret key: " + secretString);
Psaltery answered 16/2, 2022 at 21:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.