Go look at any online JWT tool. Somewhere on the page there's a line telling you not to paste production tokens.
Nobody listens. The whole reason ...
For further actions, you may consider blocking this person and/or reporting abuse
The algorithm-confusion refusal is the detail that stands out — I've seen that exact
jwt.verify(token, publicKey, { algorithms: [header.alg] })pattern in real codebases, almost always copy-pasted from a Stack Overflow answer nobody read past the first green checkmark. It's a clean target for a static-analysis rule too: flag anyalgorithmsarray whose value traces back to the token payload instead of a literal in the code. The beacon anecdote is honestly the better lesson though — "trust me, nothing is sent" is a claim, and the only way to verify a claim is to watch the wire yourself, same as I'd tell anyone reviewing AI-generated code not to trust the docstring over the diff.The static-analysis idea is good - "algorithms array traces back to the token" is exactly the taint pattern. And yes, the beacon lesson generalizes: the claim is never the artifact, the wire is.
The two-verdict split is the right call, but there's a third row hiding inside your "Time" row that bites people harder than expiry:
nbffailures caused by clock skew, not by a genuinely-not-yet-valid token. A token minted on a server whose clock is 40 seconds ahead of the validator reads as "not yet valid" for those 40 seconds, and it looks identical to a config bug. Most production JWT libraries default to a leeway/clock-tolerance window precisely because of this, and a lot of people don't know it exists until they trip over it. If your Time row just says pass/fail against the rawexp/nbf, consider showing the actual delta — "expired 8s ago" or "nbf in the future by 31s" — because "how far off" is exactly the signal that tells you skew from a real staleness problem.One thing I'd verify rather than assume: your alg-confusion refusal is correct for the HS256-with-public-key case, but the nastier variant is when someone genuinely runs a mixed HS/RS setup and legitimately passes a shared secret. Make sure the refusal is keyed on "you handed me a public key for an HMAC alg," not just "the header says HS256," or you'll false-positive on the people who actually have a valid reason to be there.
Update: shipped. Turns out the deltas were already in the verdicts ("EXPIRED 3 minutes ago"), but your skew point was the real gap - deltas under ~90 seconds now explicitly say they're likely clock skew and that most verifiers allow leeway. Live now, with tests. Thank you again for making the tool better.
No problem, glad I could help. Take care!!
Both points are well taken. Showing the delta ("expired 8s ago" / "nbf 31s in the future") is a genuinely better design than pass/fail and I'm going to add it; you're right that the magnitude is what distinguishes skew from staleness.
On the refusal: it's keyed on the key material, not the header - a shared secret with an HS256 token verifies normally; the refusal only fires when you hand asymmetric public key material to an HMAC alg. Mixed HS/RS setups work.
This is awesome! How does it actually not matter if you paste real tokens? Is it
Thanks! It's all WebCrypto in the browser - decoding, signature verification, key parsing, generation. There's no backend to send anything to.
The way to check rather than take my word for it: open devtools, select the Network tab, paste a token. Nothing fires. Then close the tab - still no network traffic. No analytics, no cookies, no beacons anywhere on the site. Source is public if you want to read it: github.com/kalisada/tokenbench
The rule of never sending the token to a server is exactly the kind of constraint that changes whether a debugging tool is safe to use under pressure. I also like the split between signature validity and time validity, because a lot of JWT tooling collapses those into a vague green or red result that does not help during incident triage. In practice the next useful step is making the unsafe cases impossible by design, not just documented in a warning banner. Nice example of turning a security footgun into a product constraint.
"Impossible by design, not documented in a warning" is the phrasing I wish I'd used in the article. Thanks.
Interesting take on JWT debugging—removing the risk of token exposure is a solid security win. In my work with secure GPU environments, I've seen similar patterns where isolating sensitive operations in air-gapped or confidential computing contexts can eliminate side-channel risks. It's reassuring to see this principle applied to a common developer tool.
Thanks - same principle, different scale: the cheapest side channel to eliminate is the one you never create.
Browser-local inspection is the right trust boundary for this kind of tool. The best security UX is not a warning that users will eventually ignore, but a design where the risky data never leaves.
That's exactly it. A warning is a request to be careful; a design where the data can't leave doesn't need the user to be careful at all.