Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 495
codeme Avatar asked Mar 11 '19 13:03

codeme


People also ask

What is JWT signing key?

The signing key is a JSON web key (JWK) that contains a well-known public key used to validate the signature of a signed JSON web token (JWT). A JSON web key set (JWKS) is a set of keys containing the public keys used to verify any JWT issued by the authorization server and signed using the RS256 signing algorithm.

How does Spring Security Work with JWT?

We expose a public POST API for the authentication, and upon passing the correct credentials, it will generate a JWT. If a user tries to access the protected API, it will allow access only if a request has a valid JWT. Validation will happen in the filter registered in the Spring Security filter chain.


1 Answers

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);
like image 71
Les Hazlewood Avatar answered Sep 28 '22 06:09

Les Hazlewood