JWT Encoder
The secret key and claims below never leave your browser — signing happens entirely client-side.
The single source of truth for signing — overwrites the header JSON's own alg key to match, so the two can never drift apart.
Ignored and disabled when the algorithm is "none".
Its alg key is overwritten by the selector above when signing.
Max 10 KB combined · Signs automatically as you type
Processed entirely in your browser — nothing is sent to a server.
A JSON Web Token (JWT) is a compact, signed string used to carry claims — statements about a user or session — between a client and a server. Encoding one means building the header and payload as JSON, then producing the signature that makes the token trustworthy to whoever verifies it.
The process is the reverse of decoding. The header (typically {"alg":"HS256","typ":"JWT"}) and payload (your claims — things like sub, name, or exp) are each serialized to JSON, then base64url-encoded — a URL-safe variant of Base64 that swaps +// for -/_ and drops padding. The two encoded segments are joined with a dot to form the “signing input.” For HS256, that signing input is run through HMAC-SHA256 with your secret key, and the resulting signature is itself base64url-encoded and appended as a third segment, giving the familiar three-part header.payload.signature shape. For the unsecured none algorithm, signing is skipped entirely and the token is just the two-part header.payload, with no signature segment at all.
This tool’s algorithm selector is the single source of truth for what actually gets signed — it overwrites the header JSON’s own alg key at signing time, so the two can never quietly disagree with each other even if you type a different value into the header field by hand.
All of this runs through the browser’s native Web Crypto API (SubtleCrypto.importKey and SubtleCrypto.sign), the same primitive real servers use, rather than a third-party JavaScript JWT library. That keeps the signing math itself standard while keeping the tool’s own code small enough to audit at a glance — no dependency to trust beyond the browser.
Only HS256 and the unsecured none algorithm are supported. RS256 and ES256 use asymmetric key pairs and require importing a PEM-formatted private key, which is a meaningfully larger scope than a first version needs — see the FAQ for the full reasoning. A token signed here can be pasted straight into the JWT Decoder to confirm exactly what it contains before you use it anywhere.
Examples
- Generating a test token for local API development — sign a token with a specific sub/role claim to hit an endpoint that expects a Bearer token, without running a full login flow.
- Prototyping a webhook receiver — create an HS256-signed token with a shared secret to test that a webhook endpoint correctly verifies incoming signatures before trusting the payload.
- Demonstrating why alg: none is dangerous — generate an unsecured token with the same claims a real session would carry, then confirm your own API rejects it, for a security review or a teammate walkthrough.
Frequently asked questions
Why does the secret key never leave my browser?
crypto.subtle.importKey() — there's no network call in the signing path, and the page's Content Security Policy restricts connect-src to a small, explicitly approved list that couldn't carry it anywhere even if the code tried.Why does this tool only support HS256?
What does the "none" algorithm mean, and what's the danger if I use it?
"alg": "none" is unsecured — it has only a header and payload, no signature at all, and anyone can construct one with arbitrary claims. It exists in RFC 7519 for narrow cases like an already-trusted internal pipeline. The real danger is on the verifying side: some JWT libraries, if misconfigured, will accept an incoming alg: none token as if it were validly signed. This tool generates one so you can test exactly that — confirm your own API actually rejects it — not as something to use for a real session token.