4

I'm generating my JWT token using JJWT library. I generate my token as follows. I'm using dummy values as my secret key.

we can assume that jwt.security.key=security-key

   @Value("${jwt.security.key}")
    private String key;

    @Value("${ws.issuer}")
    private String issuer;

    static final long ONE_MINUTE_IN_MILLIS=60000;

    static final long TOKEN_DURATION_IN_MIN=30L;

    private SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

    @Override
    public String issueToken(String userName) {

        long nowMillis = System.currentTimeMillis();
        long expMillis = nowMillis + (ONE_MINUTE_IN_MILLIS * TOKEN_DURATION_IN_MIN);

        return  Jwts
                .builder()
                .setId("01")
                .setIssuedAt(new Date(nowMillis))
                .setHeaderParam("typ","JWT")
                .setSubject(userName)
                .setIssuer(issuer)
                .setExpiration(new Date(expMillis))
                .signWith(signatureAlgorithm, key).compact();

    }

Although the token can be successfully decoded. Everytime I verify it's signature from jwt.io debugger it always result's to an invalid signature. Which can be seen here.

Les Hazlewood
  • 18,480
  • 13
  • 68
  • 76
KyelJmD
  • 4,682
  • 9
  • 54
  • 77
  • Did you try setting the secret used to encode your token on the "Verify signature" of the "Decode" tab ? It should work that way. To verify a JWT you need to know the secret, only the client should assume that the body is correct. – Fabien Thouraud Aug 14 '16 at 08:29
  • I consider that validator broken by jwt.io (Still, apparently). Bypassing their validation check, and doing so in my application proved my secret key to be validating correctly. – Shawn Sep 27 '17 at 21:29

1 Answers1

5

security-key is not a valid Base64-encoded string. Read the JavaDoc and the argument names of the signWith(SignatureAlgorithm, String) method:

/**
 * Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
 * 
 * <p>This is a convenience method: the string argument is first BASE64-decoded to a byte array and this resulting
 * byte array is used to invoke {@link #signWith(SignatureAlgorithm, byte[])}.</p>
 *
 * @param alg                    the JWS algorithm to use to digitally sign the JWT, thereby producing a JWS.
 * @param base64EncodedSecretKey the BASE64-encoded algorithm-specific signing key to use to digitally sign the
 *                               JWT.
 * @return the builder for method chaining.
 */
JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey);

Additionally, why not consider that jwt.io might be broken? It is not an authoritative jwt tool.

Finally, I'll note that you should never use plaintext strings or random strings as signing keys. Digital signatures are always computed with byte arrays. If you want cryptography to be safe, you should always use a secure-random byte array of sufficient length for the signing algorithm you are using.

Look at JJWT's Keys.secretKeyFor method to generate a sufficiently long and strong enough key.

The jwt.io site is misleading because it doesn't make this obvious and implies you can use any old string as a signing key. While it is techically possible, you definitely shouldn't. You should always use secure-random byte arrays that are then Base64 encoded if you need to represent them as Strings. This is why JJWT's methods that accept a String as a key assume it is Base64-encoded - because if it's not, you're probably using an invalid or poorly-formed key.

Les Hazlewood
  • 18,480
  • 13
  • 68
  • 76
  • My bad for not looking at the documentation. With MacProvider.generateKey, Once it has generated the key, I'll have to encode it using Base64? then pass it to signWith? – KyelJmD Aug 14 '16 at 23:37
  • `TextCodec.BASE64.encode(key.getEncoded());` But note: the resulting Base64-encoded string, while you can pass it to JJWT, is *not* considered encrypted (just transformed from bytes to a String). You should keep the string safe and/or encrypt it before storing it. – Les Hazlewood Aug 15 '16 at 16:56
  • One last question, I created the gist so I can clarify your comments. https://gist.github.com/kyeljmd/a68567680787e0d0eeef137479cd85aa Based from the gist that I have given, The variable base64EncodeKey, I should encrypt it/keep it safe? How would the receiver of this JWT check if the token is valid or not? – KyelJmD Aug 16 '16 at 08:57
  • Also, Can you post me to the right direction on the properway of using/generating keys with JJWT – KyelJmD Aug 16 '16 at 09:08
  • Your gist looks good to me. And yes, you should encrypt and/or keep safe the resulting Base64-encoded String. – Les Hazlewood Sep 12 '16 at 17:59