JWT signing explained
Signing turns a set of claims into a token that anyone can read but only the key holder can create. Here is exactly what happens, what it protects — and what it doesn't.
What signing does, step by step
- Serialize the header, e.g.
{"alg":"RS256","typ":"JWT","kid":"2026-09"}, and Base64URL-encode it. - Serialize the claims and Base64URL-encode them.
- Join them with a dot to form the signing input.
- Compute the signature over the signing input with the private key or secret, using exactly the algorithm in the header.
- Append a dot and the Base64URL-encoded signature.
input = b64url(header) + "." + b64url(payload)
signature = RSASSA-PKCS1-v1_5-SIGN(privateKey, SHA-256(input)) // RS256
token = input + "." + b64url(signature)Signing is not encryption
The header and payload are encoded, not encrypted. Anyone holding the token can read the claims — paste any token into JWTDecoder to see for yourself. Never put passwords, secrets or sensitive personal data in a signed JWT. If the claims must be confidential, encrypt the token (JWE) or keep the data server-side and reference it by ID.
Symmetric vs asymmetric keys
With HMAC (HS*), the same secret signs and verifies. It is simple and fast, but every verifier can also forge tokens. With RSA or ECDSA (RS*, PS*, ES*), only the private key can sign; verifiers use the public key, which can be published openly as a JWKS. Choose asymmetric keys when more than one service verifies your tokens.
Self-verification
JWTEncoder verifies every token it signs before you copy it — with the same secret for HMAC, or with the public key derived from your private key. A mismatch between the algorithm, key type and curve is reported with a specific explanation rather than a generic “invalid key”.
Build claims, choose an algorithm and sign — then copy the token, a Bearer header or a cURL flag.
Sign a token