A fast, private JSON Web Token toolkit that lives in your browser's side panel — one click away while you work. Unlike online decoders, everything runs locally: your tokens, payloads, and secrets never leave the browser and no network requests are made.
- Encoder — edit header + payload as JSON with live syntax highlighting and one-click formatting; choose the algorithm (HS256/HS384/HS512) from a dropdown; the signed token updates in real time; copy with one click.
- Expiration presets — set the
expclaim to now + a preset (5 minutes → 1 year) straight into the payload. - Decoder — one button decodes a JWT straight from the clipboard, or paste manually. Shows color-highlighted header/payload, human-readable
exp/iat/nbf, an "Expired" badge, and optional signature verification. - Projects — save header + payload + secret as a named project. Full CRUD (new, save, save as, rename, delete), last opened project restored. Turn any decoded token into a new project in one click.
- Secret library — save signing secrets with friendly names and reuse them across projects, in both the encoder and decoder.
- System theme — light/dark follows your OS automatically.
WXT (Manifest V3) · React 19 · TypeScript · Tailwind CSS v4 · shadcn/ui · @tabler/icons-react · jose · chrome.storage.local
Note: the shadcn registry is unreachable in this environment, so the components under
components/ui/are hand-written in the shadcn "new-york" style with Tabler icons. Add new ones by hand rather than via the shadcn CLI.
entrypoints/
background.ts # opens the side panel on toolbar-icon click
sidepanel/ # side panel app (index.html, main.tsx, App.tsx)
components/
ui/ # shadcn/ui primitives (hand-written)
EncoderTab / DecoderTab / ProjectBar / SecretPicker / …
hooks/ # useProjects, useSecrets, useStorageList
lib/
jwt.ts # sign / verify / decode / isJwt (jose)
storage.ts # Project & Secret types + chrome.storage items
assets/tailwind.css # theme tokens + system dark mode
public/icon/ # extension icons (16–128px)
- Node.js 18+
- pnpm (
corepack enablewill provide it)
pnpm install # install deps (runs `wxt prepare` postinstall)
pnpm dev # dev build + HMR; launches a Chrome instance with the extension loaded
pnpm dev:firefox # same, for Firefoxpnpm dev opens a browser with the extension already installed and hot-reloads on save. Click the JWT Workbench toolbar icon to open the side panel.
pnpm compile # tsc --noEmit- Side panel UI — right-click inside the panel → Inspect to open DevTools for the panel document.
- Background service worker — go to
chrome://extensions, find JWT Workbench, and click the service worker link to open its DevTools (useful for the side-panel-open-on-click behavior inentrypoints/background.ts). - Stored data — in the side panel's DevTools console:
await chrome.storage.local.get()shows savedprojects,secrets, and UI state. - Manual reload — dev mode hot-reloads automatically; if a change to the manifest or background isn't picked up, reload the extension from
chrome://extensions.
pnpm build- Open
chrome://extensionsand enable Developer mode. - Click Load unpacked and select
.output/chrome-mv3. - Click the toolbar icon to open the side panel.
Branded Chrome 137+ ignores --load-extension, so automated extension testing needs Chrome for Testing (e.g. via npx @puppeteer/browsers install chrome@stable). Point a puppeteer-core script at that binary with --load-extension=.output/chrome-mv3 and drive chrome-extension://<id>/sidepanel.html.
Edit version in package.json (WXT copies it into the generated manifest.json). Use semver; the store requires a higher version than the last upload.
pnpm zip # builds and writes a zip to .output/
pnpm zip:firefox # Firefox variant, if publishing there tooThis runs a production build and packages .output/chrome-mv3 into an uploadable .zip.
- Sign in to the Chrome Web Store Developer Dashboard (one-time $5 registration fee).
- Add new item (first release) or open the existing item → Package → Upload new package, and upload the zip from
.output/. - Fill in the store listing — copy is ready in store-listing.md: name, short/detailed description, category, screenshots, and the required permission justifications, single purpose statement, and privacy policy.
- Complete the Privacy practices tab (this extension collects no data and makes no network requests — declare accordingly).
- Submit for review. Review typically takes a few hours to a few business days.
- Screenshots — 1280×800 or 640×400, up to 5. Ready-made caption frames are in docs/store-screenshots.html: open it in Chrome, drop your side-panel screenshot into each 1280×800 panel, hide the controls, and capture. Captions are also listed in store-listing.md.
- Store icon — 128×128 (already in
public/icon/128.png). - Promo tiles — optional; text suggestions in store-listing.md.
- A hosted privacy policy URL (draft text is in the listing doc).
JWT Workbench makes no network requests and transmits no data. Projects and secrets are stored locally via chrome.storage.local. The clipboard is read only when you press Decode from clipboard.
Because storage uses the local area (not sync), your projects and secrets stay on this browser profile only — they are not synced to other devices signed into the same browser account. This is deliberate: signing secrets should not be pushed to the cloud, and sync has small per-item quotas. To move data between machines, export/import it manually.
MIT
