Javascript Object Signing and Encryption (JOSE)


JOSE [1] is a framework intended to provide a method to securely transfer claims (such as authorization information) between parties. The JOSE framework provides a collection of specifications to serve this purpose. A JSON Web Token (JWT) [2] contains claims that can be used to allow a system to apply access control to resources it owns. One potential use case of the JWT is as the means of authentication and authorization for a system that exposes resources through an OAuth 2.0 model [5].

Claims are a set of key/value pairs that provide a target system with sufficient information about the given client to apply the appropriate level of access control to resources under its ownership. Claim names are split into three classes: Registered (IANA), Public and Private. Further details about claims can be found in section 4 of the JWT specification.

JWTs can be represented as either JSON Web Signature (JWS) [3] or a JSON Web Encryption (JWE) [4] objects. Claims within a JWS can be read as they are simply base64-encoded (but carry with them a signature for authentication). Claims in a JWE on the other hand, are encrypted and as such, are entirely opaque to clients using them as their means of authentication and authorization.


A JSON Web Key (JWK) [6] is a JSON data structure that represents a cryptographic key. Using a JWK rather than one or more parameters allows for a generalized key as input that can be applied to a number of different algorithms that may expect a different number of inputs. All JWE and JWS operations expect a JWK rather than inflexible function parameters.

JWK format

jwk = {'k': <password>}

Currently, the only key/value pair that’s required throughout the JWE and JWS flows is ‘k’, indicating the key, or password.


The password must match algorithm requirements (i.e. a key used with an RSA algorithm must be at least 2048 bytes and be a valid private or public key, depending on the cryptographic operation). Other fields may be required in future releases.



A deserialized JWS is represented as a namedtuple with the following definition:


import jose

claims = {
    'iss': '',
    'exp': int(time()) + 3600,
    'sub': 42,

jwk = {'k': 'password'}

jws = jose.sign(claims, jwk, alg='HS256')
# JWS(header='eyJhbGciOiAiSFMyNTYifQ',
# payload='eyJpc3MiOiAiaHR0cDovL3d3dy5leGFtcGxlLmNvbSIsICJzdWIiOiA0MiwgImV4cCI6IDEzOTU2NzQ0Mjd9',
# signature='WYApAiwiKd-eDClA1fg7XFrnfHzUTgrmdRQY4M19Vr8')

# issue the compact serialized version to the clients. this is what will be
# transported along with requests to target systems.

jwt = jose.serialize_compact(jws)
# 'eyJhbGciOiAiSFMyNTYifQ.eyJpc3MiOiAiaHR0cDovL3d3dy5leGFtcGxlLmNvbSIsICJzdWIiOiA0MiwgImV4cCI6IDEzOTU2NzQ0Mjd9.WYApAiwiKd-eDClA1fg7XFrnfHzUTgrmdRQY4M19Vr8'

jose.verify(jose.deserialize_compact(jwt), jwk, 'HS256')
# JWT(header={u'alg': u'HS256'}, claims={u'iss': u'', u'sub': 42, u'exp': 1395674427})

Algorithm support

Symmetric HS256, HS384, HS512
Asymmetric RS256, RS384, RS512


import jose
from time import time
from Crypto.PublicKey import RSA

# key for demonstration purposes
key = RSA.generate(2048)

claims = {
    'iss': '',
    'exp': int(time()) + 3600,
    'sub': 42,

# encrypt claims using the public key
pub_jwk = {'k': key.publickey().exportKey('PEM')}

jwe = jose.encrypt(claims, pub_jwk)
# JWE(header='eyJhbGciOiAiUlNBLU9BRVAiLCAiZW5jIjogIkExMjhDQkMtSFMyNTYifQ',
# cek='SsLgP2bNKYDYGzHvLYY7rsVEBHSms6_jW-WfglHqD9giJhWwrOwqLZOaoOycsf_EBJCkHq9-vbxRb7WiNdy_C9J0_RnRRBGII6z_G4bVb18bkbJMeZMV6vpUut_iuRWoct_weg_VZ3iR2xMbl-yE8Hnc63pAGJcIwngfZ3sMX8rBeni_koxCc88LhioP8zRQxNkoNpvw-kTCz0xv6SU_zL8p79_-_2zilVyMt76Pc7WV46iI3EWIvP6SG04sguaTzrDXCLp6ykLGaXB7NRFJ5PJ9Lmh5yinAJzCdWQ-4XKKkNPorSiVmRiRSQ4z0S2eo2LtvqJhXCrghKpBNgbtnJQ',
# iv='Awelp3ryBVpdFhRckQ-KKw',
# ciphertext='1MyZ-3nky1EFO4UgTB-9C2EHpYh1Z-ij0RbiuuMez70nIH7uqL9hlhskutO0oPjqdpmNc9glSmO9pheMH2DVag',
# tag='Xccck85XZMvG-fAJ6oDnAw')

# issue the compact serialized version to the clients. this is what will be
# transported along with requests to target systems.

jwt = jose.serialize_compact(jwe)
# 'eyJhbGciOiAiUlNBLU9BRVAiLCAiZW5jIjogIkExMjhDQkMtSFMyNTYifQ.SsLgP2bNKYDYGzHvLYY7rsVEBHSms6_jW-WfglHqD9giJhWwrOwqLZOaoOycsf_EBJCkHq9-vbxRb7WiNdy_C9J0_RnRRBGII6z_G4bVb18bkbJMeZMV6vpUut_iuRWoct_weg_VZ3iR2xMbl-yE8Hnc63pAGJcIwngfZ3sMX8rBeni_koxCc88LhioP8zRQxNkoNpvw-kTCz0xv6SU_zL8p79_-_2zilVyMt76Pc7WV46iI3EWIvP6SG04sguaTzrDXCLp6ykLGaXB7NRFJ5PJ9Lmh5yinAJzCdWQ-4XKKkNPorSiVmRiRSQ4z0S2eo2LtvqJhXCrghKpBNgbtnJQ.Awelp3ryBVpdFhRckQ-KKw.1MyZ-3nky1EFO4UgTB-9C2EHpYh1Z-ij0RbiuuMez70nIH7uqL9hlhskutO0oPjqdpmNc9glSmO9pheMH2DVag.Xccck85XZMvG-fAJ6oDnAw'

# decrypt on the other end using the private key
priv_jwk = {'k': key.exportKey('PEM')}

jwt = jose.decrypt(jose.deserialize_compact(jwt), priv_jwk)
# JWT(header={u'alg': u'RSA-OAEP', u'enc': u'A128CBC-HS256'},
# claims={u'iss': u'', u'sub': 42, u'exp': 1395606273})

Algorithm support


There are two different encryption algorithms employed to fully encrypt a JWE: Encryption of the Content Encryption Key (CEK) and encryption of the JWT claims. The encryption algorithm used to encrypt the CEK is set through the alg parameter of encrypt() and the claims encryption is defined by the enc parameter.

CEK Encryption (alg)

Symmetric [None]
Asymmetric RSA-OAEP

Claims Encryption (enc)

Symmetric A128CBC-HS256, A192CBC-HS256, A256CBC-HS512
Asymmetric [N/A]


A JWT is a namedtuple result produced by either decrypting or verifying a JWE or a JWS.