π JWT Encoder
Create and sign HS256 JSON Web Tokens locally.
π Your data never leaves your browser
Signed Token
Create signed JSON Web Tokens directly in your browser. Edit the header and payload JSON, enter a secret, and get a ready-to-use HS256 token signed locally with the WebCrypto HMAC-SHA256 implementation, so your data never leaves your machine. It is built for testing authenticated APIs, reproducing token-related bugs, and learning how JWTs are put together.
How Signing Works
A JWT has three base64url segments separated by dots: header.payload.signature. The encoder does the following:
- Parse the header and payload as JSON, failing fast if either is invalid.
- Base64url-encode each JSON string exactly as written (padding stripped,
+β-,/β_). - Compute
signature = HMAC-SHA256(header + "." + payload, secret)and base64url-encode the raw bytes.
The result is the token. Every segment uses base64url, which is case-sensitive and strips the trailing = padding. Verification is the same operation in reverse: the server recomputes the HMAC with its copy of the secret and compares. If a single character of the payload changes, the signature no longer matches.
Step by Step
- Edit the header β the default
{"alg": "HS256", "typ": "JWT"}works unless you need extra header fields such askid. - Edit the payload β add claims such as
sub,name,iat,exp, orroles. Values must be valid JSON. - Enter a secret β type the shared HMAC key. Use a throwaway test value, never a production secret.
- Read the token β the field re-signs automatically as you type, and the Sign button forces a re-run.
- Copy β one click copies the finished token.
Worked Example: Reproducing a Known Token
Header (compact, no spaces):
{"alg":"HS256","typ":"JWT"}
Payload:
{"sub":"1234567890","name":"John Doe","iat":1516239022}
Secret: your-256-bit-secret. The encoded pieces are:
- header β
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 - payload β
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ - signature β
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
giving the full token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Change the secret by one character and the signature segment changes completely, while the first two segments stay identical. That is the whole point: the payload is public, the signature is the proof.
Signing Is Not Encryption
This is the most misunderstood part of JWTs. HS256 provides integrity and authenticity, not confidentiality. Decode the token above with the JWT Decoder and the claims appear in plain text β base64url is an encoding, not a cipher. Anyone who intercepts the token can also replay it until it expires, so:
- Put only non-sensitive claims in the payload: user id, roles, scopes, expiry.
- Keep secrets, passwords, and personal data server-side.
- Use TLS so the token cannot be lifted in transit.
- Verify the signature and the
expclaim on the server before trusting anything.
The tool itself also cannot make a weak secret safe. A leaked or guessable HMAC secret lets anyone mint valid tokens, which is why this page is for development only.
Common Mistakes
- Pasting a production secret. Sign test tokens with test secrets and rotate anything that has ever been entered into a browser tool.
- Forgetting whitespace matters. The default header in the textarea contains newlines and indentation, so its signature differs from the compact form above even though the JSON is semantically identical.
- Expecting claim validation.
expin the past,nbfin the future, or a misspelledroleclaim all sign without complaint. Validation is the serverβs job. - Using HS256 across untrusted parties. A symmetric secret must stay secret on every verifier. If multiple services need to verify, prefer an asymmetric algorithm.
- Treating the token as encrypted. See above β assume the payload is readable.
HS256 vs RS256
HS256 is symmetric: one secret both signs and verifies, so every service that verifies must also be able to sign, and a leak in any of them compromises all of them. RS256 and ES256 are asymmetric: a private key signs and a public key verifies. That separation lets API gateways and resource servers verify tokens without holding signing power, which is why public-key algorithms dominate multi-service architectures.
This encoder supports only HS256 because a browser test needs no private-key management. If your target system uses RS256, mint tokens with your own tooling and use the JWT Decoder to confirm the structure and claims β the decoded header will read "alg": "RS256".
Verifying a Token Outside the Browser
You can reproduce the signature without any JWT library. A short Node script using the built-in crypto module does exactly what a server does on each request:
const crypto = require('crypto');
const [h, p, sig] = token.split('.');
const expected = crypto.createHmac('sha256', secret)
.update(`${h}.${p}`).digest('base64url');
console.log(expected === sig); // true only if the secret matches
Both Node and modern browsers expose base64url, so no manual +// replacement is needed. If the comparison is false, the token was signed with a different secret, the payload was altered, or the header and payload strings were re-serialised with different whitespace. Reject it and move on.
Related Tools
- JWT Decoder β Inspect the header, payload, and signature of any token.
- Base64 Encoder/Decoder β See the raw bytes behind each JWT segment.
- Hash Generator β Compare HMAC output and other digest algorithms.
- Password Generator β Generate a strong random HMAC secret.
Frequently Asked Questions
Which signing algorithm does this JWT encoder support?
It signs with HS256 (HMAC-SHA256), the most widely deployed symmetric JWT algorithm, using the browser's native WebCrypto API. The same secret string both signs and later verifies the token. Asymmetric algorithms such as RS256 need a public/private key pair and are not supported here.
Is a JWT encrypted or signed?
Signed, not encrypted. HS256 guarantees the token was created by someone holding the secret and that the payload was not altered, but the header and payload are only base64url-encoded β anyone can decode and read them. Never put passwords, API keys, or personal data in a JWT payload.
What should the header and payload look like?
Both fields expect valid JSON. The header is normally {"alg": "HS256", "typ": "JWT"} and the payload carries your claims, such as sub, name, iat, and exp. The tool preloads a working sample you can edit freely; invalid JSON stops signing and shows an error.
Does this tool validate my claims or expiration?
No. It signs exactly what you type. It does not check whether exp is in the past, whether nbf is in the future, or whether claim names follow the registered-claim conventions. To inspect a finished token without verifying it, use the JWT Decoder.
Why does my token differ from another encoder's output?
The signature covers the exact bytes of the encoded header and payload, and the encoder trims leading and trailing whitespace but preserves everything inside the JSON. A space after a colon, a newline, or a different key order changes the base64url string and therefore the signature β all of them can still be valid tokens.
How long should an HS256 secret be?
At least 32 bytes (256 bits) of random data, matching the SHA-256 output size. WebCrypto accepts any string length, so this tool will happily sign with a short password, but a short secret can be brute-forced offline. Generate a long random secret for anything real.
Reviewed by the HandyTools Hub team Β· Last updated