This document specifies how to sign arbitrary data structures in a Web-friendly way, and how to verify signatures on them. This is similar to, and inspired by, Magic Signatures, but a little bit different, as the result is a token that can be included in URLs (as opposed to the JSON or XML format output by Magic Signatures).
JSON Tokens are created by issuers, and consumed by verifiers.
A server descriptor is a https or http URL. This URL resolves to a document that describes the server (such as keys used to sign requests or tokens, location of certain endpoints, etc.). Details of the document are described below in the Discovery section.
A verifier must be able to determine the server descriptor of the issuer from the “issuer” field in the token payload (see below). For example, verifiers could specify that issuers put their service descriptor directly in the “issuer” field. Alternatively, verifiers could require issuers to pre-register with the verifier, create a “client id” for the issuer, and maintain a mapping from client ids to server descriptors of issuers. In this latter case, issuers would include their client id into the “issuer” field of the token payload.
Token Structure
JSON tokens have the following structure (|| means concatenation):
payload || “.” || signature
payload is an unpadded websafe-base64-encoded JSON that includes at least the following fields:
Name | Value Type | Value Semantics |
issuer | string | A string that allows the verifier to determine the server descriptor of the issuer. This could be the service descriptor itself, or some form of client id, which the verifier can map to a server descriptor (see above). |
key_id | string | Identifies the key uses by the issuer. |
algorithm | string | Identifies the signing algorithm used. |
not_before | integer | When does this token becomes valid (seconds since midnight 1/1/1970 zulu). |
not_after | integer | When does this token expire (seconds since midnight 1/1/1970 zulu). |
audience | string | The audience for this token. The precise semantics of this field, and how it is validated, depends on the application. |
Issuers can include more fields (of arbitrary types) in the payload.
signature is a websafe-base64-encoded string of the signature bits. The signature is over the actual octets of the payload.
When receiving a JSON Token, a client can validate the token, provided it has access to a signature verification key (discussed in further detail below). It needs to perform the following steps:
We define two signature algorithms in this document: HMAC-SHA256 and RSA-SHA256. HMAC keys are obtained differently from RSA keys. RSA-SHA256 must be used with the RSASSA-PSS algorithm (in Java the corresponding RSA-SHA256 algorithm name is “SHA256withRSAandMGF1”).
To obtain an RSA verification key, the client accesses the Server Descriptor of the issuer (perhaps after mapping the issuer string obtained from the token payload to the Server Descriptor), and parses the returned document. The returned document may include one or more public keys, labeled with key identifiers (details below in the Discovery section). The key that matches the key_id from the token’s payload shall be used to verify the token.
To obtain an HMAC verification key, the verifier has to exchange, in an out-of-band fashion, shared keys with the issuer. Each key must be labeled with an identifier, unless there is only one shared key at any given point in time, in which case no label is necessary, and the key_id parameter in the payload will be ignored by the client.
Server Descriptors resolve directly to “server information” documents that contain data about the servers. For now, we only describe the “verification_keys” data type, but it’s easy to imagine how other information can be embedded in these documents.
Server information documents are a simple JSON dictionary - for now, only the “verification_keys” dictionary key is defined. The value of the verification_keys key is a dictionary that maps from key identifiers to public keys. A public key is either of the form “RSA.<modulus>.<exponent>” as explained in the Magic Signatures spec, or of the form “X509.<certificate>”, in which the certificate is the websafe-base64-encoded DER representation of an X.509 certificate (using the web-safe base64 alphabet and no chunks).
Below is an example server info document:
{
"verification_keys": {"key1":"RSA.ALqcwR..."}
}
Server info documents can be cached by verifiers for as long as the HTTP response headers indicate. If the verifier encounters a JSON Token with a key id that is not in the cached server document, it should re-resolve the issuer’s Server Descriptor. If the verifier encounters a JSON Token with a key id from an expired server info document, the verifier must re-resolve the issuer’s Server Descriptor and validate the JSON Token only if a key with that key id is still present in the server descriptor document.