← Back to guides

JWT debugging in production

By SlashGit Team · May 2026 · 8 min read

JSON Web Tokens power auth for APIs, SPAs, and mobile apps — and they are also the source of maddening "works on my machine" 401 errors. Production JWT debugging is not about decoding tokens in Slack threads or pasting them into random websites. It is about reading claims safely, correlating expiry with server clocks, and knowing when the token is fine but your middleware expectations are wrong. This guide uses SlashGit's JWT Decoder as a local, browser-only inspection step in a larger triage process.

Step 1: Capture the token without leaking it

Extract the token from the failing request's Authorization: Bearer header or from the secure HTTP-only cookie your app sets — never from client-side localStorage logs pasted into team channels. Work on your own machine in a private browser window. If you need help from a colleague, share the decoded claims (redacted) rather than the raw JWT string.

Confirm you are debugging the same environment as the user report. Staging tokens signed with a different secret will decode but fail verification on production APIs, producing identical 401 symptoms with completely different root causes.

Step 2: Decode and read the header

Paste the token into the JWT Decoder. Start with the header: verify alg matches what your server expects. A token declaring none or an unexpected algorithm can indicate a misconfigured issuer or an attack attempt. If your API only accepts RS256, an HS256 token from an old auth service must be rejected — decoding proves structure, not trust.

Note the kid (key ID) if present. Key rotation without updating your JWKS cache is a frequent production failure mode: new tokens validate at the issuer but fail locally until you refresh keys.

Step 3: Inspect time-based claims first

Check exp (expiration), nbf (not before), and iat (issued at). Compare exp against current UTC time, not your laptop's timezone setting. Tokens that expired seconds ago often explain intermittent failures on long-lived SPA sessions where refresh logic broke silently.

Clock skew tolerance matters: if your server rejects tokens issued "in the future" because container clocks drifted, you will see valid tokens fail until NTP syncs. When nbf is in the future relative to server time, fix infrastructure before chasing application bugs.

Step 4: Validate identity and authorization claims

Read sub (subject), iss (issuer), and aud (audience). Middleware frequently checks all three strictly. A token issued for aud: mobile-app will fail on an API expecting aud: api.slashgit.com even with a valid signature. Custom claims — role, scope, permissions, tenant_id — must match what your route guards read.

List the claim your failing endpoint requires and tick them off against the decoded payload. Missing scope entries are more common than broken crypto. Log the claim name in your API error (internally) to speed future triage without exposing details to clients.

Step 5: Reproduce with the API Tester

Once claims look correct, replay the request in the API Tester with the same Bearer token and headers. If it succeeds there but fails in the app, suspect client-side header construction — double prefixes like Bearer Bearer, JSON serialization of the token object instead of the string, or axios interceptors overwriting auth on specific routes.

If it fails in both places, the problem is server-side verification: wrong secret, stale JWKS, or revoked session IDs embedded in a custom claim. Use decoded claims as a checklist while reading server logs, not as proof the token should authenticate.

Step 6: Production safety rules

Never disable signature verification in production to "debug faster." Never log full tokens in application logs — log sub and jti only. Rotate secrets if a production token was exposed in a public channel. Set refresh token lifetimes shorter than access tokens and monitor refresh failure rates as an early signal of clock or cookie issues.

Keep the JWT Decoder and API Tester in your incident kit. Decoding tells you what the token claims; the API Tester tells you what your server actually does with it. Together they shorten auth outages from hours of log spelunking to a structured twenty-minute review.