Skip to content
Lesson 6 of 14

Step 1 of 5 · Reading · ~4 min

Read

Claims & Validation

Standard Claim Validation

A valid signature tells you the token was not altered and came from someone holding the key. It says nothing about whether it is still good, or whether it was meant for you. Separate questions, asked in a strict order.

The rule that comes before every other rule

Check the signature first. Read no claim until it passes.

RFC 7519 §11.1: a JWT's contents cannot be relied on for a trust decision unless cryptographically secured. Before verification the payload is a string a stranger sent you — logging sub from it hands the attacker a result they chose.

Rendering diagram…

The four checks, with their exact predicates

ClaimReject whenMeaning
expnow > exp + leewayexpired
nbfnow < nbf - leewaynot valid yet
ississ != expected_isssomeone else minted it
audyour id is not among the valuesnot meant for you

Every one is OPTIONAL per the RFC — a token may carry none. Your policy is not: decide whether a missing exp is acceptable and enforce it. Silence is not permission.

Getting the expiry boundary right

RFC 7519 §4.1.4 requires the current time to be before exp, so by the spec alone a token is dead the instant the clock reads exp itself. Leeway pushes that edge outward, and this course treats the grace window as inclusive of its right edge — the live boundary is:

expired    now>exp+leeway\text{expired} \iff \text{now} > \text{exp} + \text{leeway}

Those two rules differ by exactly one second when leeway is 0: the spec would call now == exp expired, the predicate below still calls it valid. With any real leeway the distinction disappears, and every exercise here sets one. Pick a convention, write it down, and apply it to nbf the same way — what breaks systems is two services disagreeing about the edge, not which edge you chose.

The > does real work: at exactly exp + leeway the token is still inside the grace window, dying a second later.

                exp = 970              exp + leeway = 1000
                    |                          |
   ── valid ────────|──── grace (leeway 30) ───|──── expired ──>
                                               |
                              now = 1000  still OK
                              now = 1001  EXPIRED
python

Write >= and the middle line flips to EXPIRED — a one-character bug visible only at the boundary, which is exactly where the grader looks.

nbf is the mirror image, and its leeway points the other way — the token becomes usable a little early — so you subtract: not-yet-valid when now < nbf - leeway. With nbf 5000 and leeway 60 the token wakes up at 4940, so 4939 is NOT_YET_VALID and 4940 is already OK.

Why leeway exists

Two servers never agree on the time. Clocks drift seconds to minutes apart, and a verifier running fast rejects tokens that were valid when issued. The RFC permits "some small leeway, usually no more than a few minutes"; thirty seconds to five minutes is normal. Do not reach for an hour — leeway is extra life for a token you wanted dead.

aud is a MUST, and it is usually skipped

RFC 7519 §4.1.3: if aud is present and the service processing it does not find itself among the values, the JWT MUST be rejected. It is an array in general, and may be a bare string for a single audience, so handle both:

python

Skip it and every token from your provider works against every one of your services — one minted for the analytics API is accepted by billing.

What "expired" has to do

Reject the request. Not "log them in as anonymous", not "accept and refresh server-side". Expiry is the only revocation a stateless JWT has; treat it as a soft warning and you have none.

Your exercise

You will fill in validate(), checking in the order exp, nbf, iss, aud and returning the first failure.

The visible test sets NOW 1000 and LEEWAY 30, then validates "exp":970 and expects OK. Since 970 + 30 == 1000 the token sits exactly on the boundary: now > exp + leeway is false, so it survives. Write >= and you return EXPIRED, fail that line, and fail the end-to-end exercise later for the same reason. The nbf boundary is tested the same way — subtract the leeway there, do not add it.

Up nextKey Rotation with kidClaims & Validation

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…