Glossary
JWS
JWT's underlying signature format
By Buğra SözeriPublished Updated
JWS (JSON Web Signature, RFC 7515) is the cryptographic signature framework that JWT is built on top of. A JWS has three parts joined by dots: header.payload.signature, each segment base64url-encoded. The header is JSON declaring the algorithm; the payload can be any bytes (typically but not necessarily JSON); the signature is computed over the dot-joined header and payload using the declared algorithm.
The JWT relationship: every JWT is a JWS whose payload is required to be a JSON object of claims. But JWS itself is more general — the payload can be raw binary, an XML document, or any other byte string. When you see a three-part dot-separated token that doesn’t base64-decode to JSON in the middle segment, it’s a JWS, not a JWT.
Common algorithms: HS256 (HMAC-SHA256, symmetric key), RS256 (RSA-SHA256, asymmetric), ES256 (ECDSA-P256-SHA256, asymmetric). The dangerous “none” algorithm means “no signature” — legal per the spec but always to be rejected server-side. Production verifiers should also explicitly check that the algorithm declared in the header matches the algorithm expected for the key.
JWS has two serialisations: compact (the dot-separated format JWT uses) and JSON (a JSON envelope wrapping the same three parts, supporting multiple signatures). The compact form is what almost every API uses; the JSON form is rare outside specific protocols.
Worked example
Take the JWS eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyXzEyMyJ9.4Adcj3UFYzPUVaHwte4eBI6vsjOvpz0yiwIM0F7sjuk. Decode the header (first segment): {"alg":"HS256"} — HMAC-SHA256 signature. Decode the payload (second segment): {"sub":"user_123"}. The signature (third segment) is HMAC-SHA256 of eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyXzEyMyJ9 using the shared secret key. Verifier reconstructs the HMAC and compares using constant-time comparison; mismatch → reject. Now compare to RS256: same structure, but the signature is RSA-SHA256, the issuer signs with a private key and verifiers check with the public key. The token bytes are longer (RSA signatures are ~342 base64 characters for a 2048-bit key vs 43 for HMAC-SHA256) but the validation semantics are identical from the caller’s perspective.
When and why it matters
JWS matters every time a service issues, transmits, or accepts a JWT — which in 2026 is most APIs. The mistakes that have repeatedly produced CVEs over the past decade: (1) failing to validate the signature at all, treating the payload as trusted just because it parsed as JSON; (2) accepting alg: none, which removes the signature entirely; (3) accepting any algorithm the token declares, enabling the HS256-with-RSA-public-key confusion attack; (4) not validating exp, allowing replay of long-expired tokens; (5) not validating iss and aud, accepting tokens issued for entirely different services. The defensive baseline: pin the expected algorithm in the verification call, fetch the verification key from a trusted source (typically a JWKS URL whitelisted at config time, not the token’s own jku), and validate exp, iss, and aud as separate post-signature checks. Reference: RFC 8725 — JWT Best Current Practices.
Why the algorithm-confusion attack still appears in CVEs: a long-running family of JWS vulnerabilities involves a server that asks the JWT library “is this token valid?” and lets the library pick the verification algorithm from the token’s own header. An attacker who knows the server’s RSA public key (which is, by definition, public) can craft a token signed with HMAC-SHA256 using the RSA public key bytes as the HMAC secret, set alg: HS256 in the header, and many libraries will verify it. The mitigation is to lock verification to the algorithm you expect — pass it as an explicit argument to the verify call rather than letting the token nominate it. The 2015 disclosure of this against multiple major libraries (Node’s jsonwebtoken, Python’s pyjwt, several Java implementations) is the standard cautionary tale.
Detached JWS — when the payload is too big to embed: RFC 7797 defines a “detached payload” mode where the middle segment is empty and the payload is transmitted out-of-band (e.g., as the HTTP body, while the JWS sits in a header). This is how some financial APIs sign large request bodies without re-base64-encoding megabytes of JSON. The signature is still computed over the original payload bytes; only the wire format changes. Reference: RFC 7515 — JSON Web Signature.
Try the calculator
Decode a JWS-encoded token to inspect its claims and signature algorithm.
Open the JWT decoder →Frequently asked questions
- What is JWS?
- JWS (JSON Web Signature, RFC 7515) is the standard that defines how to digitally sign a payload. A standard JWT is a JWS with a JSON claims object as the payload — the signature ensures the contents have not been tampered with.
- How does JWS signature verification work?
- The signer computes a signature over base64url(header) + '.' + base64url(payload) using the declared algorithm and key. The verifier recomputes the same value and compares it to the signature segment; any mismatch means the token was altered.
- What is the difference between JWS compact and JSON serialisation?
- Compact serialisation produces the familiar three-segment dot-separated string used in HTTP Authorization headers. JSON serialisation is a JSON object that can carry multiple signatures for the same payload, useful in document-signing scenarios.
- Which JWS algorithms are recommended?
- RS256 (RSA + SHA-256) and ES256 (ECDSA + SHA-256) are widely recommended asymmetric options because they allow public-key verification without sharing the signing key. HS256 (HMAC + SHA-256) is symmetric and suitable only when both parties share a secret securely.
Related
Published May 16, 2026 · Last reviewed May 31, 2026