2026-07-23 · 6 min read · Rahul Chitturi
- jwt
- authorization
- debugging
A JWT can pass signature verification and still fail authorization. The API may expect a scope string, the UI may send role names, and a gateway may check a different audience than the service receiving the request.
These bugs usually surface as 403 responses after a release changes permission names, tenant mapping, or provider configuration. Decoding the token is useful, but only when you compare claims against the exact check that denied the request.
Map the authorization decision
Collect a safe token fixture, the endpoint being called, and the policy or middleware that produced the denial. Mask identifiers, but keep claim names, casing, array shapes, and audience values realistic.
- Compare roles, groups, permissions, and scope claims without assuming they mean the same thing
- Check whether scope is space-delimited text or an array in your provider
- Confirm issuer and audience before debugging business permissions
- Normalize casing only if the production verifier does the same
Avoid decode-only conclusions
Decoded claims show what the token says, not whether the service should trust it. Keep signature verification, issuer checks, expiration, audience, and authorization policy as separate steps in the incident note.
If a migration changes claim names, diff an old accepted token against a new denied token. That highlights whether the break came from provider configuration, API policy, client request headers, or stale documentation.
A Flashman workflow
Use the JWT decoder for safe token fixtures, the JSON formatter to inspect nested claims, the case converter to compare naming variants, and the diff tool to review old and new authorization examples.
Finish with a policy table: endpoint, required issuer, required audience, accepted claim, accepted value, casing rule, and the component responsible for enforcing it.