What is a JWT's jti claim for, and what uniqueness must the issuer guarantee?
answer
- Names the token, not the user
- One session, many of them
- Collisions must be negligible everywhere
- Counters and timestamps do not qualify
- A name does nothing until something reads it
basics
~20 sjti is a unique identifier for the token itself. The issuer must assign it so the chance of accidentally reusing a value is negligible, and when several issuers are in play, values must not collide across them either.
solid answer
~50 s`jti` — the JWT ID — names the individual token, not the user and not the session. The specification's requirement is strict: the value must be assigned so that the probability of the same value being accidentally given to a different token is negligible, and when an application involves multiple issuers, collisions must be prevented **across** issuers as well. In practice that means a random UUID or an equivalently large random value, not a per-user counter and not a timestamp. The value is a string and is compared **case-sensitively** as a string, so no normalization, trimming or case folding. Two things it gives you: a stable handle for correlating one token across logs and audit records, and the identifier any per-token bookkeeping keys on. Note that `jti` is inert on its own — a token carrying it behaves exactly like one without it unless some component reads and uses it.
code
json · 7 lines{
"iss": "https://auth.example.com",
"sub": "user-42",
"jti": "9c1a7f6e-3b2d-4f81-a0e5-7d2c4b6a9013",
"iat": 1767225600,
"exp": 1767229200
}go deeper
Know that jti is a unique id for the individual token, typically a random UUID, and that it is not the user id.
State the uniqueness requirement, including the cross-issuer clause, and explain why counters and timestamps fail it while random values succeed.
Show you emit jti into structured logs and audit records so a token can be traced without logging the credential, and that you preserve its exact case end to end.
Own whether per-token state is worth keeping at all: what it costs in storage and latency, and which flows justify it against the stateless model tokens exist to provide.
## What jti identifies The JWT ID claim identifies *this token*. Not the subject — that is `sub`. Not the login session — a session may span many tokens, and each one gets its own `jti`. Not the request. If an issuer mints ten tokens for the same user in a minute, that is ten distinct `jti` values. ## The uniqueness requirement The specification is unusually explicit here: the value must be assigned in a manner that ensures a *negligible probability* that the same value will be accidentally assigned to a different token; and if the application uses multiple issuers, collisions must be prevented among values produced by different issuers as well. Two practical readings follow. First, "negligible probability" points at randomness with enough entropy — a version-4 UUID or a comparable random string — rather than at coordination. Second, the cross-issuer clause rules out anything scoped to one issuer's local state. A per-issuer sequence number satisfies uniqueness within one issuer and collides immediately across two. So do timestamps: two issuers minting in the same millisecond produce identical values, and a single issuer with concurrent requests can too. A random UUID sidesteps both problems without any coordination between issuers, which is why it is the default choice. A subtlety worth naming: even with cryptographically random values, `jti` is not itself a secret. It travels in a readable payload and appears in logs. It is an identifier, not a capability, and nothing should be authorized on the strength of knowing one. ## Comparison rules The value is a case-sensitive string. That matters because identifiers get passed through systems that like to normalize — a lower-casing log pipeline, a case-insensitive database collation, a trimming form binder. Any of those can turn two distinct tokens into apparent duplicates or make a stored value fail to match the token that produced it. Store and compare it byte-for-byte as text. ## What it is actually used for **Correlation.** The most common everyday use is diagnostic. Emitting `jti` in structured logs at each hop lets you follow one token through an authorization service, a gateway and several downstream services, and to answer questions like "which token was used for this action?" without logging the token itself — a real benefit, since logging the whole token would log a live credential. **Audit.** Recording `jti` alongside a sensitive action ties the action to the exact credential that authorized it, which is stronger evidence than "user X did this" when a credential may have been compromised. **A handle for per-token state.** When an application needs to track something about an individual token, `jti` is the natural key. Whether to keep such state at all — and what it costs — is a design decision with real tradeoffs; `jti` simply provides the identifier if you choose to. ## Inert unless consumed The most important thing to say in an interview is that including `jti` changes nothing by itself. A verifier that does not read it treats a token carrying `jti` identically to one without it. Candidates sometimes describe the claim as though its presence protects against reuse; it does not. It is a name, and names only matter when something looks them up. ## When to include it It is optional like every registered claim. Including it is cheap — a few dozen bytes — and pays for itself in traceability, so many issuers emit it unconditionally. The argument against is payload size on very hot paths, and even then the claim is small relative to a typical claims set.
- Why is a per-issuer sequence number a poor jti?It satisfies uniqueness only within that issuer. The specification also requires collisions to be prevented across issuers when an application uses several, and two issuers counting independently produce identical values immediately. A large random value achieves both without any coordination between them.
- Does including jti stop a token from being replayed?No. The claim is inert unless a component reads it and does something with it; a verifier that ignores jti treats the token exactly as it would without one. The claim supplies an identifier — deciding to track it, and paying for that state, is a separate design choice.
- Is jti sensitive information?It is an identifier, not a secret. It rides in a readable payload and is meant to appear in logs and audit records — that visibility is the point, since it lets you trace a token without logging the credential itself. Nothing should be authorized on the basis of knowing a jti.
saying these in an interview costs you the question
- Says jti identifies the user or the session
- Uses a timestamp or counter as the value
- Compares jti case-insensitively
- Claims that including jti prevents replay by itself
- Treats jti as a secret that must be protected