RFC7515: JSON Web Signature

This section contains the generic implementation of RFC7515.

Guide on JWS

JSON Web Signature (JWS) represents content secured with digital signatures or Message Authentication Codes (MACs) using JSON-based data structures.

There are two types of JWS Serializations:

  1. JWS Compact Serialization
  2. JWS JSON Serialization

The JWS Compact Serialization represents digitally signed or MACed content as a compact, URL-safe string. An example (with line breaks for display purposes only):

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
.
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

There are two types of JWS JSON Serialization syntax:

  1. General JWS JSON Serialization Syntax
  2. Flattened JWS JSON Serialization Syntax

An example on General JWS JSON Serialization Syntax (with line breaks within values for display purposes only):

{
  "payload":
    "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF
    tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
  "signatures":[
    {"protected":"eyJhbGciOiJSUzI1NiJ9",
     "header":{"kid":"2010-12-29"},
     "signature":
       "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZ
        mh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjb
        KBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHl
        b1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZES
        c6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AX
        LIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw"},
    {"protected":"eyJhbGciOiJFUzI1NiJ9",
     "header":{"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
     "signature":
       "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS
        lSApmWQxfKTUJqPP3-Kg6NU1Q"}]
}

An example on Flattened JWS JSON Serialization Syntax (with line breaks within values for display purposes only):

{
  "payload":
   "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF
    tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
  "protected":"eyJhbGciOiJFUzI1NiJ9",
  "header":
   {"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
  "signature":
   "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS
    lSApmWQxfKTUJqPP3-Kg6NU1Q"
 }

A JWS requires JWA to work properly. The algorithms for JWS are provided in RFC7518: JSON Web Algorithms.

Compact Serialize and Deserialize

Generate a JWS compact serialization would be easy with JWS.serialize_compact(), build a JWS instance with JWA:

from authlib.specs.rfc7515 import JWS
from authlib.specs.rfc7518 import JWS_ALGORITHMS

jws = JWS(algorithms=JWS_ALGORITHMS)
# alg is a required parameter name
protected = {'alg': 'HS256'}
payload = b'example'
secret = b'secret'
jws.serialize_compact(protected, payload, secret)

There are other alg that you could use. Here is a full list of available algorithms:

  1. HS256, HS384, HS512
  2. RS256, RS384, RS512
  3. ES256, ES384, ES512
  4. PS256, PS384, PS512

For example, a JWS with RS256 requires a private PEM key to sign the JWS:

jws = JWS(algorithms=JWS_ALGORITHMS)
protected = {'alg': 'RS256'}
payload = b'example'
with open('private.pem', 'rb') as f:
    secret = f.read()
jws.serialize_compact(protected, payload, secret)

To deserialize a JWS Compact Serialization, use JWS.deserialize_compact():

# if it is a RS256, we use public RSA key
with open('public.pem', 'rb') as f:
    key = f.read()
data = jws.deserialize_compact(s, key)
jws_header = data['header']
payload = data['payload']

A key can be dynamically loaded, if you don’t know which key to be used:

def load_key(header, payload):
    kid = header['kid']
    return get_key_by_kid(kid)

jws.deserialize_compact(s, load_key)

The result of the deserialize_compact is a dict, which contains header and payload. The value of the header is a JWSHeader.

Using JWK for keys? Find how to use JWK with Guide on JWK.

JSON Serialize and Deserialize

JWS.serialize_json() is used to generate a JWS JSON Serialization, JWS.deserialize_json() is used to extract a JWS JSON Serialization. The usage is the same as “Compact Serialize and Deserialize”, the only difference is the “header”:

# Flattened JSON serialization header syntax
header = {'protected': {'alg': 'HS256'}, 'header': {'cty': 'JWT'}}
key = b'secret'
payload = b'example'
jws.serialize_json(header, payload, key)

# General JSON serialization header syntax
header = [{'protected': {'alg': 'HS256'}, 'header': {'cty': 'JWT'}}]
jws.serialize_json(header, payload, key)

For general JSON Serialization, there may be many signatures, each signature can use its own key, in this case the dynamical key would be useful:

def load_private_key(header, payload):
    kid = header['kid']
    return get_private_key(kid)

header = [
    {'protected': {'alg': 'HS256'}, 'header': {'kid': 'foo'}},
    {'protected': {'alg': 'RS256'}, 'header': {'kid': 'bar'}},
]
data = jws.serialize_json(header, payload, load_private_key)
# data is a dict

def load_public_key(header, payload):
    kid = header['kid']
    return get_public_key(kid)

jws.deserialize_json(data, load_public_key)

Actually, there is a JWS.serialize() and JWS.deserialize(), which can automatically serialize and deserialize Compact and JSON Serializations.

The result of the deserialize_json is a dict, which contains header and payload. The value of the header is a JWSHeader.

Using JWK for keys? Find how to use JWK with Guide on JWK.

Header Parameter Names

JWS has a validation on header parameter names. It will first check if the parameter name is in “Registered Header Parameter Names” defined by RFC7515 Section 4.1. Then it will check if the parameter name is in your defined private headers.

In this case, if there are header parameter names out of the registered header parameter names scope, you can pass the names:

jws = JWS(algorithms=JWS_ALGORITHMS, private_headers=['h1', 'h2'])

API Reference

class authlib.specs.rfc7515.JWS(algorithms, private_headers=None)
REGISTERED_HEADER_PARAMETER_NAMES = frozenset({'alg', 'crit', 'typ', 'cty', 'x5u', 'kid', 'x5t#S256', 'jku', 'x5t', 'x5c', 'jwk'})

Registered Header Parameter Names defined by Section 4.1

serialize_compact(protected, payload, key)

Generate a JWS Compact Serialization. The JWS Compact Serialization represents digitally signed or MACed content as a compact, URL-safe string, per Section 7.1.

BASE64URL(UTF8(JWS Protected Header)) || '.' ||
BASE64URL(JWS Payload) || '.' ||
BASE64URL(JWS Signature)
Parameters:
  • protected – A dict of protected header
  • payload – A bytes/string of payload
  • key – Private key used to generate signature
Returns:

byte

deserialize_compact(s, key, decode=None)

Exact JWS Compact Serialization, and validate with the given key. If key is not provided, the returned dict will contain the signature, and signing input values. Via Section 7.1.

Parameters:
  • s – text of JWS Compact Serialization
  • key – key used to verify the signature
  • decode – a function to decode payload data
Returns:

JWSObject

Raise:

BadSignatureError

serialize_json(header_obj, payload, key)

Generate a JWS JSON Serialization. The JWS JSON Serialization represents digitally signed or MACed content as a JSON object, per Section 7.2.

Parameters:
  • header_obj – A dict/list of header
  • payload – A string/dict of payload
  • key – Private key used to generate signature
Returns:

JWSObject

Example header_obj of JWS JSON Serialization:

{
    "protected: {"alg": "HS256"},
    "header": {"kid": "jose"}
}

Pass a dict to generate flattened JSON Serialization, pass a list of header dict to generate standard JSON Serialization.

deserialize_json(obj, key, decode=None)

Exact JWS JSON Serialization, and validate with the given key. If key is not provided, it will return a dict without signature verification. Header will still be validated. Via Section 7.2.

Parameters:
  • obj – text of JWS JSON Serialization
  • key – key used to verify the signature
  • decode – a function to decode payload data
Returns:

JWSObject

Raise:

BadSignatureError

serialize(header, payload, key)

Generate a JWS Serialization. It will automatically generate a Compact or JSON Serialization depending on the given header. If a header is in a JSON header format, it will call serialize_json(), otherwise it will call serialize_compact().

Parameters:
  • header – A dict/list of header
  • payload – A string/dict of payload
  • key – Private key used to generate signature
Returns:

byte/dict

deserialize(s, key, decode=None)

Deserialize JWS Serialization, both compact and JSON format. It will automatically deserialize depending on the given JWS.

Parameters:
  • s – text of JWS Compact/JSON Serialization
  • key – key used to verify the signature
  • decode – a function to decode payload data
Returns:

dict

Raise:

BadSignatureError

If key is not provided, it will still deserialize the serialization without verification.

class authlib.specs.rfc7515.JWSHeader(protected, header)

Header object for JWS. It combine the protected header and unprotected header together. JWSHeader itself is a dict of the combined dict. e.g.

>>> protected = {'alg': 'HS256'}
>>> header = {'kid': 'a'}
>>> jws_header = JWSHeader(protected, header)
>>> print(jws_header)
{'alg': 'HS256', 'kid': 'a'}
>>> jws_header.protected == protected
>>> jws_header.header == header
Parameters:
  • protected – dict of protected header
  • header – dict of unprotected header
class authlib.specs.rfc7515.JWSObject(header, payload, type='compact')

A dict instance to represent a JWS object.

class authlib.specs.rfc7515.JWSAlgorithm

Interface for JWS algorithm. JWA specification (RFC7518) SHOULD implement the algorithms for JWS with this base implementation.

prepare_private_key(key)

Prepare key for sign signature.

prepare_public_key(key)

Prepare key for verify signature.

sign(msg, key)

Sign the text msg with a private/sign key.

Parameters:
  • msg – message bytes to be signed
  • key – private key to sign the message
Returns:

bytes

verify(msg, key, sig)

Verify the signature of text msg with a public/verify key.

Parameters:
  • msg – message bytes to be signed
  • key – public key to verify the signature
  • sig – result signature to be compared
Returns:

boolean