Measure a JWT exactly — Base64URL without padding, real UTF-8 bytes — then check it against the cookie, Authorization header and URL limits it has to fit.
Paste your claims as a JSON object. Whitespace is ignored — a JOSE library serialises the object, so the token carries the minified form.
There is no maximum in the JWT specification itself — the limit always comes from whatever carries the token. The cookie figure counts the name, the value and every attribute.
| Where the limit bites | Bytes | Source |
|---|---|---|
| One cookie, name + value + attributes | 4,096 | RFC 6265 §6.1 |
| One request header field (nginx default) | 8,192 | nginx large_client_header_buffers |
| One request header field (Apache default) | 8,190 | Apache LimitRequestFieldSize |
| Whole request header block (Node.js default) | 16,384 | Node.js http.maxHeaderSize |
| URI length senders should support | 8,000 | RFC 9110 |
HMAC signatures are the hash output (RFC 7518 §3.2). RSA and RSA-PSS are the size of the modulus, so they follow the key length you picked (§3.3, §3.5). ECDSA concatenates R and S at the curve's order length (§3.4). EdDSA signatures are 2b bits (RFC 8032 §5.1).
| alg | Algorithm | Signature bytes | Encoded chars |
|---|---|---|---|
| HS256 | HMAC SHA-256 | 32 | 43 |
| HS384 | HMAC SHA-384 | 48 | 64 |
| HS512 | HMAC SHA-512 | 64 | 86 |
| RS256 | RSASSA-PKCS1-v1_5 SHA-256 | 256 | 342 |
| RS384 | RSASSA-PKCS1-v1_5 SHA-384 | 256 | 342 |
| RS512 | RSASSA-PKCS1-v1_5 SHA-512 | 256 | 342 |
| PS256 | RSASSA-PSS SHA-256 | 256 | 342 |
| PS384 | RSASSA-PSS SHA-384 | 256 | 342 |
| PS512 | RSASSA-PSS SHA-512 | 256 | 342 |
| ES256 | ECDSA P-256 | 64 | 86 |
| ES384 | ECDSA P-384 | 96 | 128 |
| ES512 | ECDSA P-521 | 132 | 176 |
| EdDSA | EdDSA Ed25519 | 64 | 86 |
| EdDSA | EdDSA Ed448 | 114 | 152 |
| none | Unsecured, no signature | 0 | 0 |
You might also find these calculators useful
Assess security risk of OAuth 2.0 scope configurations
Calculate days until your SSL certificate expires
See which AES, RSA, ECC and hash key sizes are equally strong.
Generate and verify SHA-256, MD5, SHA-1, SHA-512 and SHA-3 digests
Paste your token's claims, pick the algorithm you sign with, and get its exact length in characters together with a check on whether it fits in a cookie, an Authorization header or a URL. All three limits count the wrapper as well as the token.
A JSON Web Token is three Base64URL-encoded parts joined by dots: header, payload and signature. Two details decide its exact length and both are easy to get wrong. First, a JWS uses Base64URL with all trailing '=' padding omitted (RFC 7515 §2), so a part of n bytes encodes to ⌈4n/3⌉ characters — an HS256 signature is 43 characters, not 44. Second, the n being encoded is UTF-8 bytes, not characters: a name written in Spanish, Arabic or Chinese costs more than its length suggests, and an emoji costs four bytes. Signature length comes from the algorithm — 32 bytes for HS256, the size of the modulus for RSA, 64 bytes for ECDSA P-256 — and the payload is whatever claims you put in it, which is the only part you control.
JWT Size Formula
Price the token together with the cookie name and the attributes you actually set, because that sum is what the 4096-byte guarantee covers.
Paste the payload you have and the payload you want, and compare. Roles and permissions arrays dominate almost every real token.
The same payload is shown signed every documented way, so the cost of RS256 over ES256 or EdDSA is a number rather than a guess.
A dev server with a 16 KB header block will happily accept a token that nginx refuses at 8 KB. The table shows all three defaults side by side.
RFC 6265 §6.1 guarantees only 4096 bytes per cookie, measured across the name, the value and every attribute. A 4,050-character token plus 'session=' and '; Path=/; Secure; HttpOnly; SameSite=Lax' is already over.
A bearer token is re-sent with each call. An extra kilobyte of claims is an extra kilobyte on every request from every client, which shows up as latency long before it shows up as an error.
nginx rejects a request header field larger than one 8k buffer with 400, and Apache's LimitRequestFieldSize default is 8190. Neither failure reaches your application, so it is hard to diagnose from the inside.
Swapping RS256 for ES256 takes the signature from 342 encoded characters to 86. It is a fixed saving on every token, and it costs nothing in security.
A display name in Spanish or Chinese is measured in UTF-8 bytes before encoding. Counting characters instead understates the token, which is exactly the direction you do not want to be wrong in when checking a limit.
The JWT specifications set no maximum — every limit comes from whatever carries the token. In practice: 4096 bytes for a cookie including its name and attributes (RFC 6265 §6.1), 8192 bytes for a single request header field on nginx and 8190 on Apache, 16384 bytes for the whole header block on Node.js, and 8000 octets for a URI that RFC 9110 says senders should support. The tightest of these is almost always the cookie, because the attributes count toward it.
Because a JWS drops the Base64 padding. RFC 7515 §2 defines Base64URL encoding as base64url "with all trailing '=' characters omitted", so n bytes become ⌈4n/3⌉ characters rather than ⌈n/3⌉×4. A 32-byte HMAC-SHA-256 output is 43 characters. The same rule takes an RS256 2048-bit signature to 342 characters and an ES256 signature to 86.
Base64 represents every 3 bytes as 4 characters, so the encoded form is 4/3 the size — roughly 33% more. That ratio is constant and applies to each of the three parts. It is not the same number as the share of your token that is not payload, which ranges from a few percent on a large token to most of a small one.
EdDSA with Ed25519 and ECDSA P-256 both produce 64-byte signatures, which encode to 86 characters, and HS256 produces 32 bytes and 43 characters. RSA and RSA-PSS signatures are the size of the key: 256 bytes at 2048 bits (342 characters), 384 at 3072 (512 characters) and 512 at 4096 (683 characters). Moving from RS256 to ES256 saves 256 characters on every request.
Yes, and by more than you would expect. The payload is encoded from its UTF-8 bytes, and an accented Latin character is 2 bytes, a Chinese or Arabic character 3, and an emoji 4. A twenty-character Chinese display name is 60 bytes, not 20, and encodes to 80 characters rather than 27.
A little, and exactly. Adding the type takes the header from 15 bytes to 27, which encodes to 20 and 36 characters — a difference of 16 characters, once, for the life of the token. A 'kid' costs far more: a 27-character key id adds 35 bytes of header and 48 characters of token.
Only what a resource server checks on the request. Registered claims (iss, sub, aud, exp, nbf, iat, jti) are three letters each for a reason. Large role or permission arrays are the usual cause of an oversized token; sending an identifier and resolving the rest server-side is the standard fix. Never put anything secret in a payload — it is encoded, not encrypted.
Not in localStorage: anything injected into your page can read it, which turns a size problem into an exfiltration problem. The usual answer is to stop sending the claims. Issue a short opaque session identifier in the cookie and keep the claims in the session store, or split the token so only what the browser needs travels in the cookie.