Issue
I am new to spring boot and want to create and sign JWT in Spring boot from an existing secret and pyload similar to the following Js method. What would be the best way for doing that?
/**
* const
* secret = 'lkjfjkfpofpofwrtvrhvghjbjtzjnzuiom89oölfknwundidmttdhvtotunkbzilrorjfnliozknbdgbM',
* solName = 'mysolution';
*
* // Step 1: prepare header and payload
* const
* header = {"typ": "JWT", "alg": "HS256"},
* date = (new Date()).toISOString(),
* payload = {"date": date, "name": solName};
*
* // Step 2: create JSON Web Token
* const
* // helper function for url compatible base64 encoding
* base64url = (s) => CryptoJS.enc.Base64.stringify(s).replace(/=+$/, '').replace(/\+/g, '-').replace(/\//g, '_'),
*
* // encode header and payload
* encodedHeader = base64url(CryptoJS.enc.Utf8.parse(JSON.stringify(header))),
* encodedPayload = base64url(CryptoJS.enc.Utf8.parse(JSON.stringify(payload))),
*
* // build token
* token = encodedHeader + "." + encodedPayload,
*
* // sign token
* signature = base64url(CryptoJS.HmacSHA256(token, secret)),
*
* // concatenate token and signature to get the full JSON Web Token
* jwt = token + "." + signature;
*
* // Step 3: set request headers
* console.log(`Setting request HTTP headers:`, {
* "X-DC-DATE": date,
* "X-DC-FRIEND": jwt
* });
* pm.request.headers.add({key: 'X-DC-DATE', value: date });
* pm.request.headers.add({key: 'X-DC-FRIEND', value: jwt });
*/
Solution
You could do something like this:
add this to your pom.xml
:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
and create a util class for generating your tokens:
@Service
public class JwtUtil {
private String secret;
private int jwtExpirationInMs;
@Value("${jwt.secret}")
public void setSecret(String secret) {
this.secret = secret;
}
@Value("${jwt.expirationDateInMs}")
public void setJwtExpirationInMs(int jwtExpirationInMs) {
this.jwtExpirationInMs = jwtExpirationInMs;
}
// generate token for user
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
Collection<? extends GrantedAuthority> roles = userDetails.getAuthorities();
if (roles.contains(new SimpleGrantedAuthority("ROLE_ADMIN"))) {
claims.put("isAdmin", true);
}
if (roles.contains(new SimpleGrantedAuthority("ROLE_USER"))) {
claims.put("isUser", true);
}
return doGenerateToken(claims, userDetails.getUsername());
}
private String doGenerateToken(Map<String, Object> claims, String subject) {
return Jwts.builder().setClaims(claims).setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + jwtExpirationInMs))
.signWith(SignatureAlgorithm.HS512, secret).compact();
}
}
Take a look at hashicorp vault for a secure way of storing your secret (you dont want this in your property file)
add the following to your properties file and choose sensible defaults for your use case:
jwt.jwtExpirationInMs=18000000
you can modify the algorithm to HS256 on this line:
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(
new Date(System.currentTimeMillis())).setExpiration(new Date(System.currentTimeMillis()+jwtExpirationInMs)
)
.signWith(SignatureAlgorithm.HS512,secret).compact();
but I prefer HS512 (it's faster on 64 bit machines)
Answered By - Arno_Geismar
Answer Checked By - Cary Denson (JavaFixing Admin)