Tooleux

JWS Sign and Verify

Sign and verify JSON Web Signatures. Arbitrary payloads, compact or JSON serialization, HS/RS/PS/ES/EdDSA.

Runs in your browser. Nothing leaves your device.
Sign and verify JSON Web Signatures. Arbitrary payloads, compact and JSON serialization, HS/RS/PS/ES/EdDSA algorithms. Runs in your browser. Read more Show less

What is a JWS?

A JSON Web Signature (JWS, RFC 7515) is the base specification that JWT builds on. Where a JWT carries a JSON object of claims, a JWS carries arbitrary bytes - a string, a binary blob, a document - plus a cryptographic signature over those bytes and a protected header that names the signing algorithm.

JWS is used for signed webhook payloads, signed configuration files, signed documents, and any protocol that needs to prove origin and integrity without wrapping the data in JSON claims. The payload can be anything.

How to use

Pick a mode:

  • Sign - put the payload in the left box, set the key, choose an algorithm, click Sign. The output is the JWS, either as a compact string or as flattened JSON.
  • Verify - put the JWS in the left box, set the key, click Verify. The output shows whether the signature is valid and displays the payload.

Two serializations are supported. Compact is the string form (header.payload.signature, three base64url segments separated by dots). Flattened JSON is the object form (a JSON object with payload, protected, and signature members). Compact is the right choice most of the time; flattened JSON is needed when the header carries additional members.

Keys and algorithms

HMAC algorithms (HS256, HS384, HS512) use a shared secret - the same value signs and verifies. RSA, RSA-PSS, ECDSA, and EdDSA use a key pair: sign with the private key, verify with the public key.

The key field accepts a PEM string (PKCS#8 for signing, SPKI for verifying) or a JWK. HMAC secrets can be entered as text, hex, or base64. The tool refuses a private key in verify mode, and refuses a public key in sign mode, so mismatches fail early with a clear message.

JWS vs JWT

JWT is a JWS whose payload happens to be a JSON claims object, plus some naming conventions for the standard claims (iss, sub, exp). If you have a JWT and want claim checking (expiry, nbf, iat), use the dedicated JWT Sign and JWT Verify tools. Use this tool when the payload is not a JWT claims object, or when you need the JWS-level view.

FAQ

What is not supported?

Three JWS features are not implemented in this version: detached payloads (RFC 7797, where the payload is transmitted out-of-band), general JSON serialization (multiple signatures over the same payload), and unprotected headers. Attached payloads with a single signature - the common case - are fully supported.

Why does compact mode use base64url?

Compact JWS is designed to be safe in URLs and HTTP headers, so the header and payload are base64url-encoded (URL-safe alphabet, no padding). This is why the payload looks like a long opaque string even when the underlying content is short text.

Does this check standard claims like exp or nbf?

No. A JWS payload is arbitrary bytes, not necessarily JSON, so there is no concept of standard claims at this layer. If the payload happens to be a JSON object with exp, this tool displays it but does not evaluate it. Use JWT Verify for claim checking.

Is my data sent anywhere?

No. Signing and verification run entirely in your browser using the jose library. Nothing is uploaded.

Command line equivalent
# Node (jose) - sign
npm i jose
node -e 'const {CompactSign,importPKCS8}=require("jose");(async()=>{const key=new TextEncoder().encode("your-256-bit-secret");const jws=await new CompactSign(new TextEncoder().encode("hello")).setProtectedHeader({alg:"HS256"}).sign(key);console.log(jws);})()'

# Node (jose) - verify
node -e 'const {compactVerify}=require("jose");(async()=>{const key=new TextEncoder().encode("your-256-bit-secret");const r=await compactVerify(process.argv[1],key,{algorithms:["HS256"]});console.log(new TextDecoder().decode(r.payload));})()' "$JWS"

# Python (python-jose)
pip install python-jose
python3 -c "from jose import jws; print(jws.sign('hello', 'secret', algorithm='HS256'))"
python3 -c "from jose import jws; print(jws.verify('$JWS', 'secret', algorithms=['HS256']))"

# jose CLI (Rust)
cargo install jose
jose sign --alg HS256 --key secret --payload hello

# openssl (RS256, manual)
# Signing input is header_b64 + "." + payload_b64. Sign with:
# openssl dgst -sha256 -sign private.pem -out sig.bin signing-input.txt
Loads a test value into the form
Payload
JWS