The JOSE Family — JWS, JWE, JWK, JWA, JWT
JWT is the famous one. It rides on top of a family of related specs collectively called JOSE (JavaScript Object Signing and Encryption). When people say “JWT” they almost always mean “signed JWT” = a JWS with JWT-shaped claims.
The user may have asked about “JWI” — that’s not a standard JOSE acronym. The most likely meanings: JWE (encryption, JWT’s encrypted counterpart), or possibly JWS (signature) or JWK (key). This file covers all of them briefly.
The family tree
JOSE
(JavaScript Object Signing and Encryption)
│
┌────────────┼────────────┬──────────┐
↓ ↓ ↓ ↓
JWS JWE JWK JWA
(Signature) (Encryption) (Key) (Algorithms)
│ │
└─────┬──────┘
↓
JWT
(JSON Web Token)
| Spec | RFC | What |
|---|---|---|
| JWS | 7515 | JSON Web Signature — sign a payload, verify the signature |
| JWE | 7516 | JSON Web Encryption — encrypt a payload, decrypt with a key |
| JWK | 7517 | JSON Web Key — represent a cryptographic key as JSON |
| JWA | 7518 | JSON Web Algorithms — names of algorithms (RS256, A256GCM, etc.) |
| JWT | 7519 | JSON Web Token — a payload of claims, wrapped in JWS (or JWE) |
JWT is the application; JWS/JWE provides the wire format; JWK is for key distribution; JWA is the vocabulary.
JWS — JSON Web Signature (the common case)
header.payload.signature
This is what 99% of “JWTs” actually are: a JWS with a JSON payload of claims.
eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyXzQyIiwiZXhwIjoxNzE2MzIwMDAwfQ.SflKxw...
└── header ──┘└────── payload (visible) ──────┘└── signature ──┘
- Header declares the signing algorithm.
- Payload is whatever JSON (for JWT: claims; for plain JWS: anything).
- Signature proves the payload wasn’t tampered.
The payload is not encrypted. Anyone with the token reads the claims. Signature ≠ confidentiality.
JWE — JSON Web Encryption (the encrypted alternative)
Five base64url segments (not three):
header.encryptedKey.iv.ciphertext.tag
| Segment | Means |
|---|---|
header |
algorithms used (alg for key encryption, enc for content encryption) |
encryptedKey |
the symmetric content-encryption key, encrypted with the recipient’s public key |
iv |
initialization vector for the content encryption |
ciphertext |
the actual encrypted payload |
tag |
authentication tag (AEAD) |
eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIn0.abc...def.ghi...jkl.mno...pqr.stu...vwx
The payload is encrypted, not just signed. Anyone without the recipient’s private key cannot read the contents — they see only ciphertext.
When to use JWE
- Tokens that contain PII or sensitive data.
- Multi-hop scenarios where intermediaries shouldn’t read the contents.
- Compliance / regulatory requirements (HIPAA, PCI in some cases).
When NOT to use JWE
- Most apps don’t need it. TLS already encrypts in transit; JWE adds protection at rest / in logs / at intermediaries.
- For confidentiality of session data, server-side sessions with an opaque ID are simpler.
- JWE adds significant complexity (more algorithms, key distribution, payload size).
JWE algorithm examples
Header alg |
Means | Use case |
|---|---|---|
RSA-OAEP-256 |
RSA-OAEP key wrap | recipient has RSA keypair |
ECDH-ES+A256KW |
ECDH key agreement + AES key wrap | recipient has EC keypair |
dir |
direct (the key in JWK is the content encryption key) | symmetric scenarios |
A256KW |
AES key wrap | symmetric scenarios |
Header enc (content encryption):
enc |
Means |
|---|---|
A256GCM |
AES-256-GCM (recommended) |
A128CBC-HS256 |
AES-128-CBC + HMAC-SHA-256 |
For most uses: RSA-OAEP-256 + A256GCM.
Python JWE (with python-jose)
# PyJWT does NOT support JWE.
# Use python-jose or jwcrypto:
from jose import jwe
ciphertext = jwe.encrypt(
plaintext=b'{"sub": "user_42"}',
key=recipient_public_key,
algorithm="RSA-OAEP-256",
encryption="A256GCM",
)
plaintext = jwe.decrypt(ciphertext, recipient_private_key)
JWE is rare. Most teams never touch it.
JWK — JSON Web Key
A JSON representation of a cryptographic key.
{
"kty": "RSA",
"kid": "key-2024-q1",
"use": "sig",
"alg": "RS256",
"n": "0vx7agoebGcQSuuPiL...",
"e": "AQAB"
}
Fields:
| Field | Means |
|---|---|
kty |
key type (RSA, EC, oct for symmetric, OKP for Ed25519) |
kid |
key ID (for rotation / lookup) |
use |
sig (signing) or enc (encryption) |
alg |
algorithm the key is intended for |
n, e |
RSA modulus and exponent |
crv, x, y |
EC curve and coordinates |
k |
symmetric key (base64url) |
For RSA: n and e are the public key. Private key adds d (private exponent) and others.
JWKS — JSON Web Key Set
A set of JWKs. Most OIDC providers publish their public keys at:
GET https://auth.example.com/.well-known/jwks.json
Returns:
{
"keys": [
{"kty": "RSA", "kid": "key1", "use": "sig", "alg": "RS256", "n": "...", "e": "AQAB"},
{"kty": "RSA", "kid": "key2", "use": "sig", "alg": "RS256", "n": "...", "e": "AQAB"}
]
}
Verifiers fetch this once (or on rotation), cache it, and look up the matching key by kid.
JWKS makes key rotation transparent: issuer adds a new kid, updates JWKS; verifiers fetch the new list; old kid still works until removed.
JWA — JSON Web Algorithms
Defines the names. When you see alg: RS256 in a JWT header, the meaning of “RS256” is defined in JWA: “RSASSA-PKCS1-v1_5 using SHA-256.”
Selected JWA algorithm names:
| Name | Means |
|---|---|
HS256/384/512 |
HMAC with SHA-256/384/512 |
RS256/384/512 |
RSA-PKCS1-v1_5 with SHA-256/384/512 |
ES256/384/512 |
ECDSA with P-256/384/521 + SHA-256/384/512 |
PS256/384/512 |
RSA-PSS with SHA-256/384/512 |
EdDSA |
Ed25519 / Ed448 |
none |
no signature (NEVER use) |
A128KW/A256KW |
AES key wrap |
RSA-OAEP/RSA-OAEP-256 |
RSA-OAEP |
A128GCM/A256GCM |
AES-GCM (for JWE content) |
dir |
direct key (JWE) |
The library handles the actual cryptography; JWA just standardizes the names.
Compact vs JSON serialization
JWS and JWE have two serialization formats:
| Compact | JSON | |
|---|---|---|
| Format | a.b.c (or a.b.c.d.e for JWE) |
full JSON object |
| Size | small | large |
| Multiple signatures | no | yes |
| Use | URL-friendly, headers, cookies | server-to-server, multi-signer scenarios |
JWT uses compact. JSON serialization is rare and mostly for advanced multi-recipient scenarios.
When you’ll meet each in real life
| Spec | Real-world frequency |
|---|---|
| JWT (JWS-based) | very common — OIDC, API auth, SSO |
| JWS (non-JWT) | rare — used for signing arbitrary JSON |
| JWE | rare — when JWT contents must be confidential |
| JWK | common — for OIDC verifier setup |
| JWA | implicit — every JWT references JWA names |
99% of JOSE work is JWT + JWK (for verification). JWE shows up in regulated industries.
“JWI” — what it might mean
If the interviewer said “JWI”:
| Possibility | Real name |
|---|---|
| JWE typo | JSON Web Encryption (the encrypted JWT counterpart) |
jti claim |
JWT ID (per-token unique identifier; see 03_claims.md) |
| JWS confusion | JSON Web Signature (the signed JWT counterpart) |
| Made-up | not a standard JOSE acronym |
The most defensible answer: “If ‘JWI’ means JWE — that’s encrypted JWT, used when the payload must be confidential. Most JWTs are JWS (signed only). If ‘JWI’ is the jti claim — that’s the JWT ID for replay prevention / revocation. Otherwise, the standard JOSE family is JWS, JWE, JWK, JWA, JWT.”
Common pitfalls
- Confusing JWS and JWT — every JWT is structurally a JWS (or rarely a JWE) but not every JWS is a JWT. JWT specifies a JSON payload of claims; JWS is the generic signature container.
- Assuming JWT is encrypted — it’s signed only. Use JWE for encryption.
- Hardcoding the algorithm name — JWA defines the standard names; mistype
RS256asRSA256and your library rejects it. - Loading JWKs without
kid— when keys rotate, you can’t tell which key signed an old token.
Common interview confusions
- “JWE is just an encrypted JWT.” — yes, but the use cases are rare. Most JWTs you’ll see are signed (JWS), not encrypted (JWE). For confidentiality, server-side sessions are usually simpler.
- “JWK is for symmetric keys only.” — JWK represents any key type: RSA (
kty: RSA), EC (kty: EC), symmetric (kty: oct), Ed25519 (kty: OKP). - “JOSE means JSON.” — JOSE is the umbrella spec family. JSON is just the format JOSE uses.
Interview angle
- “What’s the JOSE family?” — JavaScript Object Signing and Encryption. Five specs: JWS (signature), JWE (encryption), JWK (key representation), JWA (algorithm names), JWT (claims payload). Most “JWTs” are JWS-wrapped JSON claims.
- “JWT vs JWS vs JWE?” — JWS = a signed payload, generic. JWE = an encrypted payload, generic. JWT = a specific kind of payload (JSON claims), wrapped in JWS (signed) or rarely JWE (encrypted).
- “What’s a JWK?” — JSON representation of a cryptographic key. Includes
kty(key type),kid(key ID for rotation),use(sig/enc), and key material. JWKS = a set of them, typically published by OIDC providers at.well-known/jwks.json. - “When would you use JWE?” — when the token’s contents must be confidential (PII, sensitive data) AND TLS isn’t enough (multi-hop, logs, intermediaries). Rare; most apps use signed JWT + opaque session IDs for confidentiality.
- “How do JWS, JWE, JWT relate?” — JWT is the application (claims payload). JWS is the wire format for signed JWTs (the common case). JWE is the wire format for encrypted JWTs (rare). All three are part of the JOSE family.
- “What’s
kidfor in JWKS?” — key ID. The JWT header includeskid; the verifier looks up the matching key in the JWKS by that ID. Enables key rotation: add new keys to JWKS, oldkids keep working until removed. - “If asked about ‘JWI’…” — clarify which member of the JOSE family they mean. Most likely JWE (encrypted JWT), occasionally
jti(JWT ID claim), or just a typo. Standard JOSE specs are JWS / JWE / JWK / JWA / JWT.