We held two back-to-back sessions at IIW on Tuesday intended to produce consensus positions on JSON Web Tokens, including signing and encryption. Substantial consensus emerged, which is described in the notes below.

These consensus decisions were in place by the start of the session:

  • There is an envelope (a.k.a. header) that completely describes the cryptographic algorithm(s) used
  • There is a payload (a.k.a. body) that is distinct from the envelope
  • There is a signature that is distinct from the envelope and payload
  • Base64url encoding without padding is used to encode the parts above
  • The compact token representation separates the three encoded parts above by periods
  • No line breaks or other whitespace may be present in this representation
  • Encryption must be supported as well as signatures
  • The token representation should be compact
  • In particular, this means that multiple base64url encodings of the same content should be avoided
  • Any need for canonicalization should be avoided

Open issues identified at the start of the session were:

  • Ordering of the fields
  • Ordering of the signing and encryption operations
  • What can be in an envelope (a small fixed set of things or is it extensible)?
  • What to sign (envelope.payload or just payload)?
  • What can be in the payload (only sets of JSON token claims or arbitrary base64url encoded byte streams)?
  • Do we need to support multiple signatures?
  • Should we specify a JSON serialization as well as a compact serialization?

These issues were resolved as follows:

  • Ordering of the fields

By a vote of 8 to 1, people preferred the ordering envelope.payload.signature over the ordering signature.envelope.payload. Two reasons were cited: First, this allows for stream-mode operations, where consumers can begin operations based upon the contents of the envelope before the signature has arrived without having to buffer the signature, and where producers can compute the signature in parallel with the transmission of the envelope and payload. The counter-argument advanced by Paul Tarjan of Facebook (in abstentia) is that all languages have a string operation to split a string on the first occurrence of a character.

  • Ordering of the signing and encryption operations

How to compose these operations depends upon scenario requirements. Goals identified include Integrity, Confidentiality + Integrity, and Non-Repudiation. Brad Hill identified four sets of relevant operations, which were public key signature, symmetric key MAC, symmetric key confidentiality + MAC, and key wrap/key transport/agreement with Diffie-Hellman. Some took the position that we should define a small set of fixed configurations that are known to safely achieve the intended goals; others argued for general composability of operations. This was the one topic that we had to defer to a follow-on session to be held the next day, due to time limitations.

  • What can be in an envelope (a small fixed set of things or is it extensible)?

We reached a consensus that the envelope needs to be extensible (but should be extended only with great care).

  • What to sign (envelope.payload or just payload)?

Given that the envelope is extensible and therefore may contain security-sensitive information, we reached a consensus (with input from Ben Laurie via IM) that the combination envelope.payload must be signed.

  • What can be in the payload (only sets of JSON token claims or arbitrary base64url encoded byte streams)?

By a vote of 9 to 2, the group decided that the spec should support signing/encrypting of arbitrary base64url encoded byte streams. They also decided that the spec should define the syntax and semantics of a set of claims when what is being signed is a set of JSON claims.

  • Do we need to support multiple signatures?

The group voted 5 to 2 that it must be possible to support multiple signatures in some manner. Two variants of multiple signatures were discussed: the “gateway case”, where additional signatures are added to a token as it is passed between parties, and the parallel case, where multiple parties sign the same contents up front. However the group also decided that it would be overly complicated to support multiple signatures in the compact serialization. Support for multiple signatures was pushed to the JSON serialization (per the next issue).

  • Should we specify a JSON serialization as well as a compact serialization?

The group decided by a vote of 11 to 1 that there were use cases for a JSON serialization, and that multiple signatures would be possible in that serialization. The syntax agreed upon simply uses the three base64url encoded fields, while allowing there to be parallel arrays of envelopes and signatures. Specifically, the syntax agreed upon was:
{"envelope":["<envelope 1 contents>",...,"<envelope N contents>"],
 "payload":"<payload contents>",
 "signature":["<signature 1 contents>",...,"<signature N contents>"]
}

and where the ith signature is computed on the concatenation of <envelope i contents>.<payload contents>.