JOSE (Javascript Object Signing and Encryption) is a framework used to facilitate the secure transfer of claims between any two parties. Its specifications provide a general approach to encryption of any content, not necessarily in JSON. However, it is built on JSON for easy use in web applications.
JWT (JSON Web Token) is a standard mechanism used for authentication. It contains claims in form of a JSON payload object (in other words: key-value pairs) that will provide a target system with information about a client. This information can be verified by the server because it is digitally signed. Once the user is logged in, each subsequent request to the server that includes the JWT can be verified by the server and allows the user to access routes, services, and resources that are permitted with that token. For example your JWT could have a claim "role": "admin"
that the server uses to grant access to specific resources.
Claims is simply another word for the JSON payload object of a JWT. Apart from some required claims, the object can contain any additional information, but it is mainly used to store user information, e.g. user name, user id or user role for authorization. The JWT standard distinguishes between reserved claims, public claims, and private claims. See below for a list of standard claims.
JWS (JSON Web Signature) is used by JWT. JWS assures integrity, authentication, and non-repudiation, but it does not provide you with confidentiality. Anyone can read the payload, which can be an issue if the token holds any sort of sensitive data. To encrypt that information you have to use JWE.
JWE (JSON Web Encryption) enables encrypting a token so that only the intended recipient can read it. It standardizes the way to represent the encoded data in a JSON data structure. Combine this with JWS, and you have an encrypted token suitable for use as an access token in OAuth or an identity token in OpenID Connect.
Difference between JWT and JWS / JWE
JWT does not exist just by itself. It has to be combined with a JWS or a JWE. Consider a JWT to be like an abstract class having JWS or JWE as concrete implementations. You could also say that JWT is the parent of JWS and JWE.
Difference between Signing and Encrypting
A signature allows a JWT to be validated against modifications. Encryption, on the other hand, makes sure the content of the JWT is only readable by certain parties. This means that JWE gives you confidentiality, integrity, and authentication, while JWS gives you integrity, authentication, and non-repudiation. JWE alone does not allow you to prove that a trusted token issuer created the JWT, only that it was created by someone who knew the public key. With nested JWTs, you get the benefits of both JWE and JWS. You must always validate the Nested JWT, including its signature. Never allow unprotected Nested JWTs.
JWT example
A JWT consists of the three parts header, payload and verify signature, each encoded in Base64 and concatenated with a dot.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ. SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
The same JWT decoded:
Header
The header is used to identify the algorithm used to generate a signature.
{ "alg": "HS256", "typ": "JWT" }
Payload
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
Verify signature
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), "a-256-bit-secret-phrase" )
Standard JWT payload claims
iss
: Issuer — identifies the issuer of the claimsub
: Subject — identifying the subject of a claim, usually the unique user id or email- aud: identifies the audience that the JWT is intended for. This claim is an array of case-sensitive strings. Your server can check the aud field to see whether one of the ids in there matches the one that was given to the processing server itself. If not, the server rejects the JWT.
exp
: the expiration time on or after which the token is not accepted for processingnbf
: identifies the time before which the token is not accepted for processing. The client’s current date and time must be later than or equal to the not-before date and time listed in thenbf
claim.jti
: JWT ID — uniquely identify a claimiat
: identifies the time the JWT was issued at. You can use this claim to determine the age of a JWT
JWS – JSON Web Signature
JWS is used to represent content secured with digital signatures or Hash-based Message Authentication Codes (HMACs) with the help of JSON data structures. Header and Payload are getting signed using the algorithm specified in alg
of the header, commonly that is HS256
or RS256
.
JWE – JSON Web Encryption
Representation of the encrypted payload may be by JWE compact serialization or JWE JSON serialization (less popular).
Example JWE
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJraWQiOiIxOGIxY2Y3NThjMWQ0ZWM2YmRhNjU4OTM1N2FiZGQ4NSIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.gCbxP78o3DgpDTUQbuHniuGgYpATqgGkRGy7paC6hRrz7N7eIa6sAOWDO9Fhnj-c8ocMl4cF4Jb_mv5qRPCh9r57PBqx7jOhMIMPTwJGpjcyBaqtHlZlu1vupY5tQ3Y2jGz1Ti4BnywaeEHPyIPQJtN7F7hIAORzj7IY4sIKkVXtQJZgaKW8pEHq_GCqj8i5aaiM0uJnRG3GOh3livp9Npjv9doqp3gyPa1zjrg2H1RsOGn0j2QMGvtuVfkuNwF-SoPKFECyHOq0ZK1oH2sTO8-JwvHflbIZQr5xWTpS8q7MbUXEuqURtrg0Tj-2z6tdaOLT4b3UeDufK2ar3bBfRD4-nRALtoY0ekcMyGFOS7o1Mxl3hy5sIG-EySyWeuBVy68aDWDpi9qZoQuY1TbxxakjncCOGu_Gh1l1m_mK2l_IdyXCT_GCfzFq4ZTkPZ5eydNBAPZuxBLUb4BrMb5iDdZjT7AgGOlRre_wIRHmmKm8W9nDeQQRmbIXO23JuOw9.BDCarfq2r_Uk8DHNfsNwSQ.4DuQx1cfJXadHnudrVaBss45zxyd6iouuSzZUyOeM4ikF_7hDOgwmaCma-Z97_QZBJ5DzVn9SJhKUTAqpVR3BRGAxJ_HAXU5jaTjXqbvUaxsh7Z5TgZ9eck0FIoe1lkwv51xEvYqqQ_Xojr4MAEmLuME_9ArCK9mNaMADIzOj4VoQtaDP1l26ytocc-oENifBRYGu28LbJLkyQKzyQy6FuAOtWjLM0WCXV7-o_dvj6qfeYHNBD7YBSxyqdgD8dcxMBNd2sK73YsZPHEa0V1-8zz7hm3bH3tZelpwPWScqLLW_SUH586c0FVeI6ggvqzjfLZ_Y6eQibVSdXfOtJBk22QrLsuCXbRK8G1w9t23Pwu8ukUAw4v0l7HeaW_0SJyKSPQANRP83MyFbK7fmzTYaW9TYN2JrKN-PLpd2dIFSm2Ga_EfaCwNJBm4RDMzDNrf-O0AissvYyHb0WaALiCiFCogliYqLzRB6xDb-b4964M.J7WDOFLRRPJ7lLpTfN2mOiXLDg5xtaF-sLQ4mOeN5oc
{ "header": { "alg" : "RSA-OAEP", // encryption algorithm for the content encryption key (CEK) "enc" : "A256GCM" // content encryption algorithm "zip" : "" // if compression is used }, "encrypted_key" : "qtF60gW8O8cXKiYyDsBPX8OL0GQfhOxwGWUmYtHOds7FJWTNoSFnv5E6A_Bgn_2W" "iv" : "HRhA5nn8HLsvYf8F-BzQew", // initialization vector "ciphertext" : "ai5j5Kk43skqPLwR0Cu1ZIyWOTUpLFKCN5cuZzxHdp0eXQjYLGpj8jYvU8yTu9rwZQeN9EY0_81hQHXEzMQgfCsRm0HXjcEwXInywYcVLUls8Yik", "tag" : "thh69dp0Pz73kycQ" // Authentication tag }
The JWE compact serialization form has five main components all base64url-encoded and are concatenated using dots unlike the usual 3 sections found with a signed JWT (JWS):
- JOSE header
- JWE Content Encryption Key
- JWE initialization vector
- JWE Ciphertext
- JWE Authentication Tag
Part 1: JOSE Header
{ "alg": "RSA-OAEP", // encryption algorithm used to encrypt the Content Encryption Key (CEK) "enc": "A256CBC-HS512", // symmetric encryption algorithm used to encrypt the content itself with the CEK "kid": "18b1cf758c1d4ec6bda6589357abdd85", // refers to the public key used to encrypt the CEK (optional) "typ": "JWT", // type of this token "cty": "JWT", // type of the content (payload) of this token "zip" : "" // if compression is used (optional) }
The JOSE Header, the first element of the token, is the same as the headers of the previously mentioned JWT and JWS with some additions.
alg
(required): Defines the algorithm used to encrypt the Content Encryption Key (CEK). This MUST be set toRSA-OAEP
- enc (required): Defines the algorithm used to perform authenticated encryption on the payload (the content) to produce the Ciphertext and the Authentication Tag. This MUST be set to “A128CBC-HS256”.
cty
(required): Defines the “content type” of the payload. In this case, the value MUST be “JWT”, to indicate that a nested JWT (= our JWS) is carried inside this JWT.kid
(optional): It is a hint indicating which key was used to secure the JWE. The structure of the “kid” value is unspecified. The key hint references the public key with which the JWE was encrypted. This can be used to determine the private key needed to decrypt the JWE.zip
(optional): If token compression is needed, the JSON payload in plaintext must be compressed following the compression algorithm defined under the zip header element.
Asymmetric and symmetric encryption
This use of hybrid encryption means you use the faster symmetric encryption to encrypt the token payload, which, in theory, could be of any size, and the limited asymmetric encryption to encrypt the encryption key, which is a fixed size and relatively small. It also means you get the assurances of public-key cryptography, where many people can encrypt with the public key, but only one can decrypt with the private key. This is perfect for distributed systems and protocols such as OAuth, where there is a single token issuer and many token validators.
Additional Authenticated Data (AAD) is data you want to protect but do not want to encrypt. Using the JWE header as the AAD protects it from being modified by a malicious party.
Part 2: JWE Content Encryption Key (CEK)
During the encryption process, the issuer generates a random key, which is 256-bits in size, that is used to encrypt the payload. This is placed in the JWE Encrypted key section. The CEK is different for each token, generated for one-time use. It must never be re-used.
Part 3: JWE initialization vector
Some encryption algorithms require an initialization vector, which is a unique and randomly generated number that is used along with a secret key to encrypt data. This prevents repeated encryption of the same data using the same secret key. The recipient requires this initialization vector to decrypt the message, and hence, is placed in the JWE token. If your symmetric encryption algorithm does not require an initialization vector, then this should be an empty octet sequence.
Part 4: JWE Ciphertext (payload)
The fourth section of the token is the JWE Ciphertext that is computed by encrypting the plaintext JSON payload using the Content Encryption Key (CEK), the JWE initialization vector, and the Additional Authentication Data (AAD) value (which, when using compact serialization, is the encoded JWE protected header), with the encryption algorithm defined by the header element enc.
JWE allows you to encrypt any arbitrary payload; however, a common use case is for the payload to be another JWT. This is known as a Nested JWT.
By using a Nested JWT, you gain the benefits of asymmetric encryption, where many systems can encrypt and only one can decrypt, and the benefits of asymmetric signatures, where only one system can create signatures while many can validate them.
This means that JWE gives you confidentiality, integrity, and authentication, while JWS gives you integrity, authentication, and non-repudiation. JWE alone does not allow you to prove that a trusted token issuer created the JWT, only that it was created by someone who knew the public key. With nested JWTs, you get the benefits of both JWE and JWS. You must always validate the Nested JWT, including its signature. Never allow unprotected Nested JWTs.
Part 5: JWE Authentication Tag
The JWE Authentication Tag created during authenticated encryption allows the verifier to prove the integrity of the ciphertext and the AAD (the header). This tag is created during encryption and validated as part of decryption.
If your symmetric encryption algorithm does not use an authentication tag, then this should be an empty octet sequence.
JWK – JSON Web Key
JWK is a JSON structure representing a set of public keys as a JSON object using the Elliptic Curve or RSA algorithms. Public key representations can help verify the signature with the corresponding private key.