Checking the signature tells you the token was not altered. It tells you nothing about whether you should act on it.
The order matters
- Decide the algorithm yourself, from your configuration, and reject the token if its header disagrees.
- Select the key, by
kidif present, from your own key set. - Verify the signature, reading
algonly from the protected header. - 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.