Multi-Tenant JWT Debugger

Decode and inspect JWT tokens for B2B SaaS apps — tenant context, scoped permissions, role memberships, and provider conventions (Clerk, WorkOS, Auth0, Supabase, Stack Auth, Firebase, Cognito) all surfaced separately. Side-by-side comparison and a test-token generator included. Everything runs in your browser.

shield

Private: Decoding, analysis, signature verification, and token generation all run in your browser. Nothing is sent to any server, except a JWKS URL you explicitly enter and click Verify on.

What it does

Tenant context surfaced

Active tenant, role, and tenant memberships shown in dedicated cards — separate from generic claims. Recognizes tenant_id, org_id, workspace_id, account_id, team_id, and provider-specific equivalents.

Provider detection (7 providers)

Clerk, WorkOS, Auth0, Supabase, Stack Auth, Firebase, and AWS Cognito tokens are auto-detected from issuer patterns and characteristic claims. Provider-specific guidance appears alongside the analysis.

13-rule security checklist

Algorithm none, expired tokens, wildcard permissions, missing aud, super-user across many tenants, impersonation markers, long lifetimes — the multi-tenant-specific anti-patterns that generic debuggers ignore.

Side-by-side comparison

Paste two tokens, see what differs claim-by-claim. Tenant memberships diff, permissions diff, and changed claims highlighted. The fastest way to debug "why does customer A have access but customer B doesn't".

Test-token generator

Generate signed JWTs with HS256, HS384, HS512, RS256, or ES256 for local development. Auto-generates a keypair when you don't supply one. Drop-in for backend integration testing.

Signature verification

Verify HMAC tokens with a shared secret, asymmetric tokens with a PEM public key or JWK, or fetch a JWKS by URL. The only network call this tool makes — and only when you click Verify.

Markdown + redacted exports

Copy a structured Markdown analysis report (without the raw token) for bug tickets and PR comments. Or copy a redacted version of the token (sub, email, signature replaced) safe to paste in public forums.

Privacy-first by default

Token decoding, signature verification, and test-token generation all run in your browser. No analytics on token contents. No backend storage. Safe for production tokens (though short-lived ones are still a better idea).

How to use Multi-Tenant JWT Debugger

  1. 1
    Paste your JWT

    Drop a JWT into the textarea — including a Bearer prefix or surrounding quotes is fine, both are stripped automatically. Or use the "Load sample" menu to try a Clerk, WorkOS, Auth0, Supabase, Stack Auth, Firebase, or Cognito sample token.

  2. 2
    Read the summary card

    The first card tells you, in one sentence, who the token authenticates, which tenant they're active in, what role they hold, and how long until it expires. That's usually all you need for a quick "is this the right token?" check.

  3. 3
    Review findings

    The Findings panel runs a checklist for multi-tenant anti-patterns: algorithm none, expired, missing aud, wildcard permissions, super-user across many tenants. Each finding includes a fix recommendation and links to the relevant spec.

  4. 4
    Drill into tenant context

    Tenant context, the memberships table, and the permissions panel each get their own card. If you need to see the raw payload JSON, the bottom panels expand on demand.

  5. 5
    Compare two tokens (optional)

    Switch to Compare mode to paste a second token. The diff highlights which claims, permissions, and tenant memberships differ — useful when reproducing a customer-reported access bug across two sessions.

  6. 6
    Generate a test token (optional)

    Switch to "Generate test token" to produce a valid signed JWT for local development. Pick the algorithm; supply a secret/key or let the tool generate a keypair. Copy the resulting token and (for asymmetric algs) the public key into your backend.

When to use this

Reproducing a customer-reported access bug

A customer reports "I can see tenant A's data when I'm logged into tenant B." Paste the customer's tokens from each session in Compare mode and see exactly which claim is wrong.

Verifying a new auth provider integration

You just switched from Auth0 to Clerk and want to confirm the new tokens carry the same tenant context. Paste a token from each — the analyzer detects the provider and shows the equivalent claims side-by-side.

Auditing tokens before going to production

Before shipping, run a representative token through the Findings panel. The 13-rule checklist catches algorithm-none mistakes, missing aud claims, wildcard permissions, and long lifetimes that should be tightened.

Local backend integration testing

Generate a test token with the exact tenant_id, role, and permissions claims your backend expects, then call your protected API. No need to spin up the auth provider locally just to test authorization paths.

Common errors & fixes

"This doesn't look like a JWT"
JWTs are three base64url-encoded parts separated by dots. If yours has more or fewer dots, it's not a JWT — it might be an opaque session token, an encrypted JWE, or a malformed string. Check what your auth provider issues.
"The header isn't valid base64url-encoded JSON"
The first segment of your token isn't decoding to JSON. Common causes: extra whitespace, accidental URL encoding, or copying from a logger that truncated the token. Re-copy from the source.
Provider detected as "unrecognized"
The token didn't match any of the seven recognized providers. That's normal for custom JWT implementations — the analyzer still surfaces tenant_id, role, permissions, and standard claims; it just won't show provider-specific guidance.
Signature verification fails with "invalid"
For HMAC: confirm the secret matches what your auth server uses. For asymmetric: confirm you pasted the public key, not the private key. For JWKS: confirm the URL is reachable from the browser and returns a valid keyset (CORS may block it).

Why a multi-tenant JWT debugger needs different rules from a generic one

A generic JWT debugger answers "what's in this token". A multi-tenant JWT debugger answers "is this token authorizing what I expect?" — which requires reasoning about tenant scoping that generic tools can't do.

For example: a token with `permissions: ["billing:write"]` is fine in isolation, but the same token with `org_id: "tenant_acme"` and `aud: "tenant_globex"` is a misconfiguration — the audience and the active tenant don't agree, and either the token shouldn't have been issued or one of those claims is wrong. A generic debugger has no concept of "tenant", so it can't flag the inconsistency.

Multi-tenant rules also need provider awareness. Clerk's `org_role` is namespaced like `org:admin`; WorkOS's `role` is a free-form string; Auth0 puts roles under a namespaced custom claim. The analyzer's provider registry maps these to a canonical "current role" concept so the Summary card reads naturally regardless of which provider issued the token.

The seven recognized provider conventions

**Clerk**: `iss` matches `https://clerk.*`. Active org in `org_id`, role in `org_role` (formatted `org:admin`), permissions in `org_permissions`. Session id in `sid`, authorized party in `azp`. Default algorithm RS256.

**WorkOS**: `iss` contains `workos`. Active org in `org_id`, role in `role`, permissions in `permissions`. Session id in `sid`. SSO sessions add `connection_id` and `directory_id`. Default algorithm RS256.

**Auth0**: `iss` matches `*.auth0.com`. Organizations feature uses `org_id` and `org_name`. Custom claims must be namespaced URIs like `https://yourapp.com/roles`. RBAC permissions in top-level `permissions` array. Default algorithm RS256.

**Supabase**: `iss` ends in `/auth/v1`. Trusted server-set claims in `app_metadata` (use this for tenant_id and role). Untrusted user-set claims in `user_metadata`. AAL (`aal1`/`aal2`) tells you whether MFA happened. Default algorithm HS256.

**Stack Auth**: Active team in `selected_team_id`, role in `team_role`, memberships in `teams[]`. Default algorithm RS256.

**Firebase Auth**: `iss` matches `https://securetoken.google.com/*`. Multi-tenant projects (GCIP) use `firebase.tenant`. Custom claims set via the Admin SDK appear at the top level. Default algorithm RS256.

**AWS Cognito**: `iss` matches `cognito-idp.*.amazonaws.com`. Groups in `cognito:groups`. Username in `cognito:username`. Custom attributes prefixed `custom:`. No built-in tenant claim — convention is `custom:tenant_id`. Default algorithm RS256.

The 13-rule security checklist explained

**Critical (5 rules):** Algorithm is `none` (forgeable token); symmetric algorithm with public-facing issuer (HS256 distributed across many verifiers is risky); expired (exp in past); not yet valid (nbf in future); no exp claim at all (token never expires).

**Warning (5 rules):** Tenant id embedded in `sub` (anti-pattern that conflates user and tenant); wildcard permission present (`*:*` or `admin:*` accumulate over time); token lifetime exceeds 24 hours; missing aud (no audience validation possible); admin/owner role in more than five tenants (possible super-user worth confirming).

**Info (3 rules):** Impersonation markers present (`act`, `impersonator`, `on_behalf_of` — informational, often legitimate); uncommon algorithm; no jti (limits revocation); iat in the future (clock skew warning).

Each rule is declarative: an id, severity, detection function, and remediation. Adding a new rule is one append to the rules array. The list is intentionally biased toward false positives — better to flag something legitimate than miss a real issue.

Frequently Asked Questions

Is it safe to paste production tokens into this tool?

Decoding, analysis, signature verification, and token generation all run client-side in your browser. The token is never sent to a server. The only network call this tool makes is fetching a JWKS, and only when you explicitly click Verify after typing a JWKS URL. That said, JWTs can carry sensitive user information — for production tokens, prefer short-lived ones and avoid pasting tokens whose signatures grant high-privilege access.

How does this differ from jwt.io or DevZone's JWT Decoder?

jwt.io and the basic [JWT Decoder](/tools/jwt-decoder) show the header, payload, and signature for any JWT. This Multi-Tenant JWT Debugger goes further: it knows about tenant claims (tenant_id, org_id, etc.), runs a multi-tenant-specific security checklist, detects seven auth providers, supports side-by-side comparison for cross-tenant bugs, and generates test tokens for local development. It's designed for B2B SaaS work specifically.

Which auth providers does the analyzer detect?

Clerk, WorkOS, Auth0, Supabase, Stack Auth, Firebase, and AWS Cognito. Detection is heuristic — based on `iss` URL patterns and characteristic claims. For each detected provider, the Notes panel shows where to find the active tenant, the role, and the permissions. Tokens from other providers fall back to a generic analysis using the universal claim registry.

Can I verify a JWT signature in the browser?

Yes — for HMAC tokens (HS256/HS384/HS512) you paste the shared secret, for asymmetric tokens (RS256/ES256/etc.) you paste the public key in PEM or JWK format, or you provide a JWKS URL the tool fetches once. The verification uses the [`jose`](https://github.com/panva/jose) library, which is well-audited and browser-friendly. Signature verification only loads when you open the panel — it's not on the critical path for decoding.

How do I generate a test token for my backend?

Switch to "Generate test token" mode. Fill in the user, tenant, role, and permissions fields, pick an algorithm (HS256 is fine for HMAC, RS256/ES256 for asymmetric), and click Generate. For asymmetric algorithms the tool auto-generates a keypair you can copy into your backend for verification. Use these tokens for local integration tests only — never in production.

How does the Compare mode help me?

Paste two tokens (e.g., from a customer's session in tenant A and tenant B). The Compare view shows a per-claim diff: which claims are added, removed, or changed. The permissions diff shows which permissions are unique to each token. The tenants table diff shows which memberships changed. It's the quickest way to debug "why does this user see different things" across sessions.

What does the analyzer do with my token after I'm done?

Nothing — there's no server side. The token lives in your browser's memory until you close the tab or paste a new one. There's no localStorage, no IndexedDB, no analytics event with token contents. Errors that mention the token are scrubbed of any token-shaped strings before display, and the export buttons produce reports that intentionally exclude the raw token.

My token is encrypted (JWE), not signed (JWS) — does this work?

No. JWEs (JSON Web Encryption) are five base64url segments separated by four dots and require the recipient's private key to decrypt. This tool handles JWS (JSON Web Signature) tokens — three segments, two dots — which is what 99% of authentication tokens are. If your provider issues JWEs, decrypt server-side first and analyze the inner claims here.

Related Tools