JSON Web Encryption
JSON Web Encryption (JWE) is a compact, URL-safe method of representing encrypted content using JavaScript Object Notation (JSON) data structures, enabling secure transmission of sensitive information between parties.[1] It provides both confidentiality through encryption and integrity via authentication tags, supporting authenticated encryption to protect against tampering and unauthorized access.[1]
As part of the broader JSON Object Signing and Encryption (JOSE) framework, JWE facilitates the encryption of arbitrary payloads, including JSON Web Tokens (JWTs), and is designed for use in web applications, APIs, and distributed systems where secure data exchange is essential.[1] The standard defines a modular structure comprising a JOSE header (which may be protected or unprotected), an optional JWE Encrypted Key (containing the encrypted or wrapped content encryption key (CEK) where applicable), an initialization vector (IV), additional authenticated data (AAD; often derived from the header), the ciphertext, and an authentication tag.[1] Key management is handled through four modes: direct encryption, key encryption, key wrapping, and direct key agreement, allowing flexibility in securing the CEK for single or multiple recipients.[1]
JWE supports a range of cryptographic algorithms specified in JSON Web Algorithms (JWA), including RSAES-OAEP for key encryption, AES Key Wrap for key wrapping, ECDH-ES for key agreement, AES-GCM and AES-CBC-HMAC-SHA for content encryption, and HMAC-SHA for integrity.[2] It offers two serialization formats: the compact serialization, which concatenates components with dots for simplicity and single-recipient scenarios, and the full JSON serialization, which uses a JSON object to accommodate multiple recipients and unprotected headers.[1] Published as RFC 7516 in May 2015 by the Internet Engineering Task Force (IETF), JWE builds on prior standards like XML Encryption 1.1 and CMS while addressing modern web security needs, such as mitigating chosen-ciphertext and timing attacks through careful algorithm selection and padding.[1]
Overview
Definition and Purpose
JSON Web Encryption (JWE) is a compact, URL-safe means of representing encrypted content using JSON-based data structures. Defined in RFC 7516, it provides a standardized format for securing arbitrary octet sequences through encryption and integrity protection. As part of the broader JSON Object Signing and Encryption (JOSE) framework, JWE facilitates the secure handling of structured data in networked environments.[1]
The primary purpose of JWE is to enable confidentiality for JSON payloads, ensuring that only authorized recipients can access the underlying content while maintaining data integrity. This is achieved through authenticated encryption mechanisms that protect against unauthorized disclosure and tampering. JWE is particularly valuable in web applications where sensitive information must be transmitted securely, such as in authentication and authorization flows.[1]
Key benefits of JWE include its interoperability across diverse systems and languages due to the ubiquitous use of JSON, as well as support for both symmetric and asymmetric keys to accommodate various security models. It also integrates seamlessly with JSON Web Signature (JWS) for combined encryption and signing, allowing for comprehensive protection of data in transit. These features make JWE suitable for environments requiring robust yet efficient cryptographic operations.[1][3]
In practice, JWE can be used to encrypt the payloads of JSON Web Tokens (JWTs) in protocols such as OAuth 2.0 and OpenID Connect, for example to provide additional confidentiality for identity tokens. However, such encryption is optional and less frequently implemented than signing, as transport-layer security (TLS) often suffices for confidentiality. It also secures API responses containing personal or financial data and supports encrypted communications between microservices to preserve privacy in distributed systems.[4][3][5]
Relation to JOSE Framework
The JSON Object Signing and Encryption (JOSE) framework comprises a set of IETF standards that enable the secure representation of JSON-based data structures for integrity protection and confidentiality through digital signatures, message authentication codes, and encryption.[6][1] It includes specifications such as JSON Web Signature (JWS) for signing operations and JSON Web Encryption (JWE) for encryption, along with supporting elements like JSON Web Key (JWK) for key representation and JSON Web Algorithms (JWA) for cryptographic identifiers. JOSE facilitates the creation of compact, URL-safe serialized objects that can be transmitted between parties, ensuring secure handling of JSON content in web applications and APIs.[7]
Within the JOSE framework, JWE specifically addresses the encryption of JSON payloads to provide confidentiality, allowing sensitive data to be protected from unauthorized access during transmission or storage.[1] It often integrates with JWS to produce signed-and-encrypted objects, where a JWS structure is nested as the plaintext within a JWE envelope, combining integrity verification with encryption in a single serialized format.[6] This modular approach allows developers to apply encryption selectively while leveraging shared JOSE components like headers and key management for consistency across implementations.[8]
In contrast to JWS, which focuses on ensuring the integrity and authenticity of JSON content through signatures or MACs without concealing the payload, JWE prioritizes confidentiality by encrypting the entire payload, rendering it unreadable to intermediaries.[6] JWS verifies that data has not been tampered with and originates from a trusted source, whereas JWE uses key encryption, content encryption, and optional authentication tags to protect against eavesdropping and tampering.[1] These distinct security goals enable JOSE to support diverse use cases, from public signatures in JWS to private data exchanges in JWE.[7]
JWE enhances interoperability within JOSE by serving as the underlying format for encrypted JSON Web Tokens (JWTs), where the JWT Claims Set is treated as the plaintext to be encrypted.[9] This allows JWTs to achieve end-to-end confidentiality in scenarios like secure authentication flows, with JWE's compact serialization ensuring compatibility across JOSE-compliant libraries and protocols.[10] Such integration promotes widespread adoption in standards like OAuth 2.0, where encrypted JWTs protect sensitive claims without requiring custom serialization.[11]
History and Specifications
Development Timeline
The development of JSON Web Encryption (JWE) originated within the Internet Engineering Task Force (IETF) as part of efforts to standardize JSON-based cryptographic formats. In September 2011, the IETF chartered the Javascript Object Signing and Encryption (JOSE) Working Group to address the need for compact, JSON-serialized representations of signed and encrypted content, building on emerging requirements for web authentication and authorization protocols.[7] The initial individual draft for JWE, authored primarily by Michael Jones of Microsoft, was published on September 6, 2011, as draft-jones-json-web-encryption-00, introducing a compact encryption format suitable for space-constrained environments like HTTP headers.[12] Key contributors included Jones, alongside John Bradley of Ping Identity, who played significant roles in the broader JOSE specifications and related discussions on JSON Web Tokens (JWT).[13]
The draft progressed rapidly following the JOSE Working Group's formation on September 21, 2011. It was adopted as a working group item, with the first WG version (draft-ietf-jose-json-web-encryption-00) released on January 16, 2012, co-authored by Jones and Joe Hildebrand of Cisco.[14] Over the next three years, the specification underwent numerous revisions, incorporating feedback from the JOSE community on security considerations, algorithm identifiers, and serialization formats. Influences included prior JSON standards like JWT (initially drafted in December 2010 and later standardized as RFC 7519) for claim representation, as well as lessons from XML Encryption 1.1 (XMLenc) regarding key wrapping and content encryption structures. JWE was positioned as a confidentiality mechanism within the overarching JOSE framework, which encompasses JSON Web Signature (JWS) and JSON Web Key (JWK).
Key milestones included Working Group Last Call in August 2014 and IESG approval on January 15, 2015, culminating in the publication of JWE as RFC 7516 on May 20, 2015, achieving Proposed Standard status.[15] Post-standardization, JWE saw adoption in protocols like OpenID Connect Core 1.0, finalized in November 2014, which utilized JWE for encrypting ID tokens and user info responses to enhance privacy in authentication flows.[16] Since then, updates have been limited to minor errata corrections, including a 2023 clarification on key identification in Section 6, without substantive changes to the core specification.[17]
Key RFCs and Standards
The core specification for JSON Web Encryption (JWE) is defined in RFC 7516, published in May 2015 by the Internet Engineering Task Force (IETF). This document outlines the format for representing encrypted content using JSON-based data structures, specifies the operations for creating and processing JWE objects, and establishes security requirements to ensure confidentiality and integrity.
RFC 7516 is part of the broader JSON Object Signing and Encryption (JOSE) framework and depends on complementary standards. RFC 7515 defines JSON Web Signature (JWS), which enables combined signing and encryption workflows by allowing JWS to wrap JWE objects. RFC 7518 provides the registry of cryptographic algorithms and identifiers used in JWE, including parameters for key encryption, content encryption, and key management. Additionally, RFC 7519 specifies JSON Web Tokens (JWT), a compact token format that leverages JWE for encrypting claims to protect sensitive information in transit.
The scope of RFC 7516 includes required content encryption algorithms for interoperability, such as A128CBC-HS256 and A256CBC-HS512, along with options for compact and JSON serializations. Key encryption algorithms are application-specific, with recommendations from JWA; note that RSAES-PKCS1-v1_5 is deprecated for new applications. It also defines conformance criteria for implementations, requiring support for specific header parameters and error handling to mitigate common vulnerabilities like key reuse.
Development of these specifications was led by the IETF JOSE Working Group. As of 2025, RFC 7516 has no major revisions, though extensions such as Hybrid Public Key Encryption (HPKE) integration via draft specifications enhance its applicability.[18] JWE has been integrated into broader standards, including OAuth 2.0 profiles, such as the JWT access token format in RFC 9068 which can optionally use JWE for encrypting sensitive claims, and FIDO Alliance protocols like the Credential Exchange Protocol, which uses JWE for secure credential storage and transfer.[19]
The JOSE Header in JSON Web Encryption (JWE) is a JSON object that provides metadata about the encryption operations applied to the content, including the algorithms used and optional additional claims. It typically includes required parameters such as "alg", which identifies the key encryption or key agreement algorithm (e.g., "RSA-OAEP" for RSAES-OAEP or "A128KW" for AES Key Wrap with 128-bit key), and "enc", which specifies the content encryption algorithm (e.g., "A256GCM" for AES-256 GCM).[20][21] Optional parameters may include "kid", a string hinting at the key identifier used for the recipient's public key or secret key (e.g., "2011-04-29" or "7").[22]
The header can consist of up to three parts: the JWE Protected Header (integrity-protected), the JWE Shared Unprotected Header (shared across recipients but unprotected), and Per-Recipient Unprotected Headers (specific to each recipient and unprotected). These components collectively form the JOSE Header, which is serialized as a JSON object and then Base64url-encoded without padding to produce the first part of the JWE representation (e.g., eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0 decodes to {"enc":"A128CBC-HS256"}).[8][23] This encoding ensures the header is compact and suitable for transmission in JOSE formats.
To handle implementation-specific or private parameters, the "crit" member can be used as an array listing critical header parameters that the recipient must understand and process; if present, any listed parameters not recognized by the recipient will cause processing to fail. Additionally, the "typ" parameter indicates the media type of the complete JWE object, typically set to "JWE" to signal its type to applications.[24][25]
When a JWE is nested within a JSON Web Signature (JWS) for additional integrity protection, the JOSE Header parameters must be included in the protected header to ensure they are integrity-protected by the JWS signature; unprotected headers in such combinations lack this assurance unless explicitly signed.[8]
Encrypted Key and IV
In JSON Web Encryption (JWE), the Encrypted Key represents the result of encrypting the Content Encryption Key (CEK) using a specified key encryption algorithm, such as RSA-OAEP or AES Key Wrap, to protect the symmetric key used for encrypting the actual payload. The CEK itself is a randomly generated secret key, typically 128 to 256 bits in length depending on the chosen content encryption algorithm—for instance, 256 bits for AES-256-GCM—to ensure sufficient security strength against brute-force attacks. This encryption of the CEK allows secure key distribution to recipients, often via asymmetric cryptography, without exposing the CEK in plaintext. The Encrypted Key is then Base64url-encoded without padding to form a compact, URL-safe string suitable for transmission in HTTP headers or query parameters.[26]
The Initialization Vector (IV) is a random nonce value generated for each encryption operation to provide uniqueness and prevent replay attacks in block cipher modes, such as those used in authenticated encryption algorithms like AES-GCM. For common algorithms like A256GCM, the IV consists of 96 bits (12 bytes) of cryptographically secure random data, ensuring that identical plaintexts produce different ciphertexts even under the same key. Like the Encrypted Key, the IV is Base64url-encoded and must be kept secret from unauthorized parties, as its reuse could compromise the confidentiality of the encrypted content. In the JWE header, parameters such as "alg" (for the key encryption algorithm) and "enc" (for the content encryption algorithm) indicate the methods applied to generate and use these components.[27][26]
In the compact serialization format of JWE, which concatenates components with dots for brevity, the Encrypted Key occupies the second position after the JOSE Header, followed by the IV in the third position, before the Ciphertext and Authentication Tag. For example, a compact JWE might appear as: eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdRCGnWGQ..48V1_ALb6US04U3b.5eyyyYaDdmm89imFyB8aM8ZwOaLEfm6CydfPJd..., where "OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdRCGnWGQ" is the Base64url-encoded Encrypted Key and "48V1_ALb6US04U3b" is the encoded IV. This structure facilitates efficient parsing and decryption by recipients, who first decrypt the CEK using their private key and then apply it with the IV to the ciphertext.[28][29]
Ciphertext and Authentication Tag
In JSON Web Encryption (JWE), the ciphertext represents the encrypted form of the original plaintext payload, produced through symmetric encryption using the Content Encryption Key (CEK) and Initialization Vector (IV) with the selected content encryption algorithm. This ciphertext ensures confidentiality of the payload by transforming it into an unreadable format that can only be decrypted by parties possessing the appropriate CEK. It is then encoded using Base64url encoding to facilitate safe transmission in JSON structures or compact serializations.[30]
The authentication tag, when used, provides integrity protection for both the ciphertext and the Additional Authenticated Data (AAD), which includes elements like the JOSE header. In authenticated encryption modes such as AES-GCM, the tag is a fixed-length value—typically 128 bits—generated as part of the encryption process to allow verification that the data has not been tampered with during transit. This tag is also Base64url-encoded to ensure compatibility with JSON and URL-safe contexts.[30]
In the compact serialization of a JWE, the Base64url-encoded ciphertext forms the fourth component, separated by dots from the preceding header, encrypted key, and IV components. If an authentication tag is present, it is appended as the fifth and final component in the same encoded format, resulting in a structure like: header.encrypted_key.iv.[ciphertext](/page/Ciphertext).[tag](/page/Tag). For JWE JSON Serialization, the ciphertext appears as the value of the "ciphertext" member, while the tag is the value of the optional "tag" member within the JWE Encrypted Content object. A representative example of a Base64url-encoded ciphertext from the specification is KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY, and for the tag, Mz-VPPyU4RlcuYv1IwIvzw.[31][32][29]
Algorithms and Operations
Content and Key Encryption Methods
JSON Web Encryption (JWE) supports a variety of cryptographic algorithms for encrypting the content (plaintext) and the content encryption key (CEK), ensuring confidentiality and integrity. These algorithms are identified by the "enc" parameter for content encryption and the "alg" parameter for key encryption, both specified in the JWE header as registered values in the IANA JSON Web Encryption Algorithms registry.[27][33] The choice of algorithms must align with the security requirements, including appropriate key lengths and initialization vectors or nonces to prevent attacks.[26]
Content Encryption Algorithms
Content encryption algorithms, denoted by the "enc" header parameter, are used to encrypt the plaintext using a symmetric CEK, providing both confidentiality and authentication where applicable. Implementations must support the mandatory-to-implement algorithms A128CBC-HS256 and A256CBC-HS512, which combine AES in CBC mode with HMAC for authentication.[33] A128CBC-HS256 employs a 256-bit CEK, split into a 128-bit key for AES-128-CBC encryption and a 128-bit key for HMAC-SHA-256 authentication, requiring a 128-bit initialization vector (IV) that must be unique per encryption operation.[34] Similarly, A256CBC-HS512 uses a 512-bit CEK split into 256-bit portions for AES-256-CBC and HMAC-SHA-512, also with a 128-bit IV.[35]
Recommended algorithms include authenticated encryption modes like A128GCM and A256GCM, which use AES in Galois/Counter Mode (GCM) for combined encryption and authentication. A128GCM requires a 128-bit CEK and a 96-bit nonce, while A256GCM uses a 256-bit CEK with the same nonce size; the nonce must be randomly generated and unpredictable to ensure security.[36] Optional algorithms, such as A192CBC-HS384 and A192GCM, provide intermediate security levels but are not required for compliance.[33] All content encryption algorithms must produce a ciphertext and, for authenticated modes, an authentication tag, with the CEK length strictly matching the algorithm's requirements as defined in RFC 7518.[37]
Key Encryption Algorithms
Key encryption algorithms, indicated by the "alg" header parameter, protect the CEK for transmission to the recipient, using either asymmetric or symmetric methods. There are no strictly mandatory algorithms, but recommended ones include RSA-OAEP and ECDH-ES for robust security. RSA-OAEP (RSAES-OAEP with SHA-256) encrypts the CEK with an RSA public key, supporting key sizes of at least 2048 bits to achieve adequate security levels, and is preferred over older padding due to its resistance to chosen-ciphertext attacks.[38] RSA1_5 (RSAES-PKCS1-v1_5) is also supported but deprecated in favor of OAEP, using similar RSA key sizes.[33]
For symmetric key management, dir allows direct use of a pre-shared symmetric key as the CEK without additional wrapping, suitable for scenarios with established key sharing.[39] Key wrapping algorithms like A128KW and A256KW use AES in Key Wrap mode with 128-bit or 256-bit keys to encrypt the CEK, providing confidentiality for symmetric environments.[40] ECDH-ES enables key agreement using Elliptic Curve Diffie-Hellman with an ephemeral-static key pair, deriving the CEK via a concatenation key derivation function; it supports curves like P-256 and requires coordination of the "epk" header parameter for the ephemeral public key.[41] Composite algorithms, such as ECDH-ES+A128KW, combine ECDH for key agreement with AES Key Wrap for CEK encryption. All key encryption algorithms must ensure the CEK remains confidential and are registered in the IANA registry for interoperability.[33][42]
Key Derivation and Management
In JSON Web Encryption (JWE), the Content Encryption Key (CEK) serves as a randomly generated symmetric key that encrypts the plaintext payload to produce the ciphertext, ensuring confidentiality through an authenticated encryption algorithm.[1] The CEK's length is determined by the selected content encryption algorithm, such as 256 bits for AES-256-GCM, and it must be generated using cryptographically secure random number generation methods to prevent predictability. This random generation occurs at the producer's side prior to encryption, allowing the CEK to be treated as a one-time use key for the specific JWE object.[26]
Key unwrapping is the process by which a recipient recovers the CEK from the JWE Encrypted Key, which contains the CEK encrypted or wrapped specifically for that recipient using a key encryption algorithm.[1] The recipient applies their private key—for asymmetric methods like RSA—or a shared secret—for symmetric wrapping—to decrypt this component, yielding the original CEK for subsequent payload decryption.[37] This step ensures that only authorized recipients can access the CEK, maintaining the security of the overall encryption.
For scenarios involving key agreement, such as the Elliptic Curve Diffie-Hellman Ephemeral-Static (ECDH-ES) algorithm, the CEK is not directly provided but derived from ephemeral keys using the Concatenation Key Derivation Function (Concat KDF) as defined in RFC 7518.[2] The derivation process computes a shared secret from the producer's ephemeral key pair and the recipient's static public key, then applies the Concat KDF—based on SHA-256—with inputs including the shared secret, algorithm identifiers, optional party information (via "apu" and "apv" headers), and the required key length to produce the CEK.[43] This method enables secure key agreement without transmitting the CEK in plaintext.
JWE facilitates key management for multiple recipients by encapsulating a distinct Encrypted Key for each, stored in the JWE object structure, which allows broadcasting encrypted content to diverse parties with varying key capabilities.[44] Additionally, the "kid" (key ID) header parameter provides a string identifier hinting at the specific key used for encryption or wrapping, supporting key rotation, versioning, and efficient key lookup in key management systems without revealing sensitive details.[22]
Usage and Implementation
Creating and Processing JWE Objects
Creating a JSON Web Encryption (JWE) object involves a series of cryptographic operations to securely encrypt a plaintext payload for one or more recipients. The process begins with generating a random Content Encryption Key (CEK), which is typically 256 bits long for algorithms like AES-256-GCM, to serve as the symmetric key for encrypting the payload.[26] Next, a random Initialization Vector (IV) is generated, such as a 96-bit value for GCM modes, to ensure uniqueness in encryption.[26] The plaintext is then encrypted using the CEK, IV, and Additional Authenticated Data (AAD)—derived from the Base64url-encoded protected header—via the specified content encryption algorithm, producing the ciphertext and an Authentication Tag for integrity verification.[26] The CEK is encrypted using the recipient's public key or a shared symmetric key with the chosen key encryption algorithm (e.g., RSAES-OAEP), resulting in an Encrypted Key.[26] The components are assembled into the JOSE Header (including protected and optionally unprotected parts), the Encrypted Key, IV, Ciphertext, and Authentication Tag, then each is Base64url-encoded without padding and concatenated with dots to form the compact serialization (e.g., HEADER.ENCRYPTED_KEY.IV.CIPHERTEXT.TAG). This describes the process for single-recipient compact serialization; for multiple recipients, use the JSON serialization described in the next subsection.[26]
Processing a JWE object to recover the plaintext follows a symmetric decryption workflow, starting with parsing the compact serialization string by splitting on dots to extract the five components: JOSE Header, Encrypted Key, IV, Ciphertext, and Authentication Tag.[37] The JOSE Header is Base64url-decoded to JSON and validated as valid UTF-8, with checks for duplicate parameter names and support for the specified algorithms ("alg" for key encryption and "enc" for content encryption); invalid headers must be rejected.[37] The Encrypted Key is decrypted using the corresponding private key or shared symmetric key and the header's "alg" parameter to unwrap the CEK; if the CEK is invalid, the JWE is rejected.[37] The ciphertext is then decrypted using the recovered CEK, IV, and AAD (the ASCII representation of the encoded header), with the Authentication Tag verified; a mismatch or decryption failure results in rejection.[37] Upon successful verification, the plaintext is output. This describes processing for single-recipient compact serialization; for multiple recipients, use the JSON serialization described in the next subsection.[37]
Error handling in JWE processing enforces strict security by requiring rejection of malformed or invalid structures to prevent attacks like chosen-ciphertext scenarios.[37] Specifically, the process must reject JWE objects missing required components, those with non-UTF-8 or non-JSON headers, duplicate header parameters, unsupported algorithms, or cases where the CEK cannot be decrypted or the tag verified.[37] Implementations are prohibited from providing partial information about failure reasons beyond a generic error to avoid leaking details about keys or structures.[37]
The following high-level pseudocode illustrates the creation process without invoking specific cryptographic libraries (for single recipient):
function createJWE(plaintext, recipientKey, alg, enc):
// Generate keys and IV
cek = generateRandomKey(lengthForEnc(enc))
iv = generateRandomIV(ivLengthForEnc(enc))
// Create and encode header
protectedHeader = { "alg": alg, "enc": enc } // May include other params
headerEncoded = base64urlEncode(utf8Encode(jsonSerialize(protectedHeader)))
aad = ascii(headerEncoded)
// Encrypt payload
ciphertext = encryptContent(plaintext, cek, iv, aad, enc)
authTag = computeAuthTag(ciphertext, aad, cek, enc)
// Encrypt CEK for recipient
encryptedKey = encryptKey(cek, recipientKey, alg)
// Assemble and encode
jwe = headerEncoded + "." + base64urlEncode(encryptedKey)
jwe += "." + base64urlEncode(iv)
jwe += "." + base64urlEncode(ciphertext)
jwe += "." + base64urlEncode(authTag)
return jwe
function createJWE(plaintext, recipientKey, alg, enc):
// Generate keys and IV
cek = generateRandomKey(lengthForEnc(enc))
iv = generateRandomIV(ivLengthForEnc(enc))
// Create and encode header
protectedHeader = { "alg": alg, "enc": enc } // May include other params
headerEncoded = base64urlEncode(utf8Encode(jsonSerialize(protectedHeader)))
aad = ascii(headerEncoded)
// Encrypt payload
ciphertext = encryptContent(plaintext, cek, iv, aad, enc)
authTag = computeAuthTag(ciphertext, aad, cek, enc)
// Encrypt CEK for recipient
encryptedKey = encryptKey(cek, recipientKey, alg)
// Assemble and encode
jwe = headerEncoded + "." + base64urlEncode(encryptedKey)
jwe += "." + base64urlEncode(iv)
jwe += "." + base64urlEncode(ciphertext)
jwe += "." + base64urlEncode(authTag)
return jwe
Similarly, for processing (single recipient):
function processJWE(jweString, recipientPrivateKey):
// Parse components
components = split(jweString, ".")
if len(components) != 5: reject("Invalid structure")
[headerEncoded, encryptedKeyEncoded, ivEncoded, ciphertextEncoded, tagEncoded] = components
// Validate header
headerBytes = base64urlDecode(headerEncoded)
if not isValidUtf8(headerBytes): reject("Invalid header encoding")
protectedHeader = jsonParse(utf8Decode(headerBytes))
if hasDuplicates(protectedHeader): reject("Duplicate parameters")
alg = protectedHeader["alg"]
enc = protectedHeader["enc"]
if not supportsAlg(alg) or not supportsEnc(enc): reject("Unsupported algorithm")
aad = ascii(headerEncoded)
iv = base64urlDecode(ivEncoded)
ciphertext = base64urlDecode(ciphertextEncoded)
tag = base64urlDecode(tagEncoded)
// Decrypt key
encryptedKey = base64urlDecode(encryptedKeyEncoded)
cek = decryptKey(encryptedKey, recipientPrivateKey, alg)
if cek is invalid: reject("Invalid CEK")
// Decrypt and verify
plaintext = decryptContent(ciphertext, cek, iv, aad, enc)
if not verifyAuthTag(tag, aad, iv, ciphertext, cek, enc): reject("Invalid tag")
return plaintext
function processJWE(jweString, recipientPrivateKey):
// Parse components
components = split(jweString, ".")
if len(components) != 5: reject("Invalid structure")
[headerEncoded, encryptedKeyEncoded, ivEncoded, ciphertextEncoded, tagEncoded] = components
// Validate header
headerBytes = base64urlDecode(headerEncoded)
if not isValidUtf8(headerBytes): reject("Invalid header encoding")
protectedHeader = jsonParse(utf8Decode(headerBytes))
if hasDuplicates(protectedHeader): reject("Duplicate parameters")
alg = protectedHeader["alg"]
enc = protectedHeader["enc"]
if not supportsAlg(alg) or not supportsEnc(enc): reject("Unsupported algorithm")
aad = ascii(headerEncoded)
iv = base64urlDecode(ivEncoded)
ciphertext = base64urlDecode(ciphertextEncoded)
tag = base64urlDecode(tagEncoded)
// Decrypt key
encryptedKey = base64urlDecode(encryptedKeyEncoded)
cek = decryptKey(encryptedKey, recipientPrivateKey, alg)
if cek is invalid: reject("Invalid CEK")
// Decrypt and verify
plaintext = decryptContent(ciphertext, cek, iv, aad, enc)
if not verifyAuthTag(tag, aad, iv, ciphertext, cek, enc): reject("Invalid tag")
return plaintext
These steps ensure secure generation and decryption, with the pseudocode representing the logical flow as defined in the standard for single-recipient compact serialization.[26][37]
JSON Web Encryption (JWE) supports multiple serialization formats to accommodate different use cases, balancing compactness, readability, and support for multiple recipients. These formats define how the encrypted content, headers, keys, and tags are structured and encoded, primarily using Base64url encoding for binary data and JSON for object representations. The choice of format depends on the application's requirements, such as transmission in HTTP headers versus storage in databases.[45]
The Compact Serialization represents a JWE as a single, compact string suitable for environments with space constraints, such as URI fragments or HTTP Authorization headers. It consists of exactly five parts: the Base64url-encoded JWE Protected Header, the JWE Encrypted Key, the JWE Initialization Vector (IV), the JWE Ciphertext, and the JWE Authentication Tag, all concatenated with period ('.') characters as separators. For example: eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZ_KTnhdrP3uekF9nSP9sJ1f76pJWw4aO1J0C5f6f2g.12ABCDEF.3def4567ghij.4klmNopqRstuvwxYZ.5yzA1BcDeFgHIjKlMnOpQrStUvWxYz This format supports only a single recipient and does not include unprotected headers or additional authenticated data (AAD), making it optimized for simplicity but limited in flexibility.[31]
In contrast, the JSON Serialization provides a more expressive JSON object structure, enabling encryption of the same content for multiple recipients and inclusion of additional metadata. The object includes optional members such as "protected" (Base64url-encoded protected header), "unprotected" (shared unprotected header as a JSON object), "recipients" (an array of objects each containing "header" for per-recipient unprotected headers and "encrypted_key"), "iv" (Base64url-encoded IV), "aad" (optional Base64url-encoded additional authenticated data), "ciphertext" (Base64url-encoded ciphertext), and "tag" (Base64url-encoded authentication tag). This format is neither compact nor URL-safe but is ideal for scenarios requiring detailed header information or multi-party encryption. For instance, a multi-recipient example might structure the "recipients" array with separate encrypted keys for each party.[44]
For single-recipient cases where JSON readability is preferred over compactness, the Flattened JSON Serialization simplifies the general JSON format by omitting the "recipients" array and promoting its single object's contents to top-level members: "header" (per-recipient unprotected header) and "encrypted_key". The remaining members—"protected", "unprotected", "iv", "aad", "[ciphertext](/page/Ciphertext)", and "[tag](/page/Tag)"—remain as in the general form. This variant is processed identically to the general JSON Serialization when only one recipient is present, offering a cleaner structure for applications that do not need multi-recipient support.[46]
Selection of a serialization format typically prioritizes the Compact form for single-recipient, token-like uses due to its brevity and ease of parsing, while the JSON formats are chosen for complex scenarios involving multiple recipients or extensive metadata.[45]
Security Considerations
Known Vulnerabilities
One significant vulnerability in JWE implementations arises from key reuse attacks, particularly when the content encryption key (CEK) or initialization vector (IV) is reused across multiple encryptions. In authenticated encryption modes like AES-GCM, which is supported in JWE, reusing the same IV with the same CEK can lead to decryption failures or plaintext recovery by an attacker observing ciphertexts, as the nonce uniqueness is essential for security. The JWE specification explicitly warns against such reuse, noting that the same CEK must not be used in both encryption and decryption directions even with different IVs, to prevent information leakage.[44]
Algorithm downgrade attacks target the "alg" parameter in the JWE header, which specifies the key encryption algorithm. An attacker can tamper with this parameter to force the use of a weaker algorithm, such as RSA1_5 instead of RSA-OAEP, if the recipient does not strictly validate it against expected values. This vulnerability exploits insufficient checks during key unwrapping, potentially enabling chosen-ciphertext attacks on the weaker scheme. Such issues are analogous to signature algorithm confusion in related JOSE standards but specifically affect JWE's key management.[47]
Padding oracle variants pose risks in JWE when using CBC-based content encryption algorithms, such as A128CBC-HS256. If an implementation leaks information about padding validity through error messages or timing during decryption, an attacker can perform chosen-ciphertext queries to gradually decrypt arbitrary ciphertexts without the key. This side-channel attack relies on the oracle providing feedback on whether the padding is correct, allowing byte-by-byte plaintext recovery. Certain JWE processing libraries have been susceptible to this in configurations supporting CBC modes without constant-time padding checks.[48]
A notable historical vulnerability is the invalid curve attack on JWE using ECDH-ES key agreement, identified in 2017. This attack allows recovery of the private key by crafting public keys on weak or invalid elliptic curves, exploiting libraries that fail to validate curve parameters during key derivation. The issue stems from the JWE specification (RFC 7516) not mandating strict curve validation, leading to exploitation in multiple implementations like node-jose. Recent implementation vulnerabilities as of 2025 include flaws in authentication tag validation for AES-GCM modes (e.g., CVE-2025-54887 in the Ruby jwe gem, allowing tag bypass and data exposure) and unbounded decompression in JWE processing (e.g., CVE-2025-62706 in Authlib), underscoring ongoing library risks beyond core specification issues. No core specification flaws have been reported in JWE by November 2025, but library-specific misimplementations continue to surface periodically.[49][50][51][52]
Mitigation Strategies and Best Practices
When implementing JSON Web Encryption (JWE), selecting appropriate algorithms is crucial to ensure robust security. Developers should prioritize Authenticated Encryption with Associated Data (AEAD) modes, such as A256GCM for content encryption ("enc" parameter), as they provide both confidentiality and integrity without requiring separate authentication tags. For key encryption ("alg" parameter), prefer RSA-OAEP-256 or ECDH-ES with A256KW over deprecated options like RSA1_5 to mitigate padding oracle attacks. Strictly validate and whitelist supported "alg" and "enc" values during processing, rejecting any unrecognized or mismatched combinations to prevent algorithm downgrade attacks, and ensure proper authentication tag verification in AEAD modes.[53][37]
Effective key management practices are essential to avoid exposure risks. Generate fresh, cryptographically secure random Content Encryption Keys (CEKs) and Initialization Vectors (IVs) for each encryption operation, adhering to randomness requirements outlined in RFC 4086 to ensure sufficient entropy. Implement key rotation policies with secure storage mechanisms, such as Hardware Security Modules (HSMs), to limit the impact of key compromise, and never reuse CEKs or IVs across multiple encryptions. For recipient keys, use asymmetric cryptography only with verified public keys from trusted sources, and protect symmetric keys used in direct encryption modes.[54][55]
Implementation should incorporate defenses against side-channel and implementation flaws. Employ constant-time cryptographic operations in libraries to resist timing attacks, and report all decryption errors uniformly without leaking details about the failure type. Use audited, open-source libraries like the Nimbus JOSE+JWT for Java or python-jose for Python, which implement the full JOSE suite including JWE and have undergone community security reviews. Avoid rolling custom implementations, as they are prone to subtle errors in padding, encoding, or header processing.[56][57]
To achieve compliance and broader protection, adhere to the security considerations in RFC 7516, including matching key sizes across algorithms for balanced security. Incorporate application-level replay protection by including timestamps or unique nonces in the JWE payload or claims, validating them against server state during decryption. For forward-looking resilience, plan transitions to post-quantum algorithms, such as those defined in emerging IETF drafts for JOSE.[58][59][60]