Note: This is a follow-up to the Stateless Authentication with Spring Security and JWT tutorial. If you’re here to see what’s changed since then, read on! Otherwise, you may want to read the original tutorial first and then come back to this article to see what’s changed.

If you want to skip the explanation and just look at the code changes, click here.

Stronger Tokens

An observant fellow by the name of Florian Schmitt noticed in my original tutorial that the same token is always generated for a given username. This is worrisome because it increases the risk that a user’s credentials or even the application’s secret key will be compromised!

To reduce this risk, we can add entropy to the token — data that an attacker cannot predict that is different from our secret key — and we can minimize the time in which someone can use a token.

Florian had some great suggestions that are really easy to implement using JJWT. Here’s what the new token generator looks like:

TokenHandler.java

1
2
3
4
5
6
7
8
9
10
11
public String createTokenForUser(User user) {
    Date now = new Date();
    Date expiration = new Date(now.getTime() + TimeUnit.HOURS.toMillis(1l));
    return Jwts.builder()
            .setId(UUID.randomUUID().toString())
            .setSubject(user.getUsername())
            .setIssuedAt(now)
            .setExpiration(expiration)
            .signWith(SignatureAlgorithm.HS512, secret)
            .compact();
}

Less Buggy Tokens

Florian also noticed I wasn’t Base64-encoding the secret key when signing the tokens. D’oh! This violation of the spec might prevent alternative JWT frameworks within your application’s ecosystem from properly verifying tokens.

Fortunately, this is a one-line fix to the token handler’s constructor:

TokenHandler.java

1
2
3
4
public TokenHandler(String secret, UserService userService) {
    this.secret = Base64.getEncoder().encodeToString(StringConditions.checkNotBlank(secret).getBytes());
    this.userService = Preconditions.checkNotNull(userService);
}

The fix can be verified by pasting one of the tutorial’s generated tokens into JWT.io and typing in the default secret key “tooManySecrets”. Notice the giant “Signature Verified” message in the image below.

Don't trust me, try it for yourself!

Authenticating with Google

After going months without thinking about this tutorial, it was a struggle for me to figure out how to generate Google OAuth credentials to use in this example. To save myself and others the agony of figuring that out again, I also added better instructions to the tutorial’s README in GitHub.