Understanding JSON Web Tokens: verifying properly

Checking the signature tells you the token was not altered. It tells you nothing about whether you should act on it.

The order matters

  1. Decide the algorithm yourself, from your configuration, and reject the token if its header disagrees.
  2. Select the key, by kid if present, from your own key set.
  3. Verify the signature, reading alg only from the protected header.
  4. Then, and only then, look at the claims.

Reading claims before verifying is how a forged token gets to influence your key selection.

The claims to check

  • exp: expired tokens are refused. Allow a small clock skew, seconds, not minutes.
  • nbf: not valid yet is just as much a refusal.
  • iss: does it come from the issuer you expect? An attacker with a valid token from another issuer should get nowhere.
  • aud: is it for you? A token minted for another service is not yours to accept, even if it verifies.

iss and aud are the two most often skipped, and they are the two that make a token yours rather than merely valid.

What a JWT cannot tell you

Whether it was revoked. A self-contained token is valid until it expires, full stop. If you need revocation, you need state on your side: a deny-list keyed on jti, or short lifetimes and a refresh mechanism.

Choosing a fifteen-minute lifetime instead of building revocation is a legitimate decision. Believing that a signature makes revocation unnecessary is not.