Python JOSE (Demonware)
The `jose` library by Demonware is an older Python implementation of the JSON Object Signing and Encryption (JOSE) framework, supporting JSON Web Signatures (JWS) and JSON Web Encryptions (JWE). Last released in 2015 with version 1.0.0, it was primarily developed for Python 2 and relies on the unmaintained `pycrypto` library. Due to its inactivity and dependency on outdated cryptographic components, it is not recommended for new projects or secure applications.
Common errors
-
ModuleNotFoundError: No module named 'jose.jwt'
cause You are attempting to use the API of the `python-jose` library, but have installed the `jose` (Demonware) package.fixIf you intend to use `python-jose`, install it via `pip install python-jose` (preferably with `pip install python-jose[cryptography]`) and update your imports to `from jose import jwt`. If you specifically need the Demonware `jose` library, consult its documentation for correct usage (e.g., `import jose` then `jose.sign()`). -
ImportError: No module named Crypto.PublicKey
cause The `jose` (Demonware) library depends on the `pycrypto` package for its cryptographic primitives, which is not installed or incorrectly installed.fixInstall the `pycrypto` library: `pip install pycrypto==2.6.1`. Be aware that `pycrypto` is unmaintained and insecure, and its installation can be problematic on modern systems. -
ValueError: Key must be at least 2048 bits
cause When using RSA algorithms, the provided key does not meet the minimum length requirements specified by JOSE standards or the library's implementation for secure operations.fixEnsure that any RSA keys used for signing or encryption are generated with a length of at least 2048 bits (e.g., `RSA.generate(2048)`). For enhanced security, 3072 or 4096 bits are often recommended.
Warnings
- breaking Version 1.0.0 introduced a backward-incompatible change related to authentication tag computation for JWE. Tokens produced by `jose < 1.0.0` cannot be decrypted by `jose 1.0.0` due to a change in the JWE hash string calculation.
- gotcha The `jose` library (Demonware) is often confused with `python-jose`, a separate, more actively maintained library with a similar purpose but a different API. The Demonware `jose` is imported directly (e.g., `import jose`), while `python-jose` typically uses `from jose import jwt`.
- breaking This library explicitly targets Python 2, as indicated by its PyPI classifiers (`Programming Language :: Python :: 2 :: Only`). While it might run on some Python 3 environments, it has unresolved issues and is not officially supported or tested for Python 3, leading to potential unexpected behavior or errors.
- breaking The `jose` library relies on `pycrypto` for its cryptographic operations, which is an outdated, unmaintained, and potentially insecure library with known vulnerabilities. Using `jose` in production for sensitive data is a significant security risk.
Install
-
pip install jose
Imports
- sign
from jose import jwt
import jose signed_jws = jose.sign(protected_header, claims, key)
- encrypt
import jose encrypted_jwe = jose.encrypt(protected_header, claims, public_key)
- decrypt
import jose decrypted_payload = jose.decrypt(encrypted_jwe, private_key)
Quickstart
import jose
from time import time
# NOTE: For modern Python and security, consider `pip install python-jose[cryptography]` instead.
# This example is for the *Demonware jose* library, which uses the deprecated `pycrypto`.
# Ensure `pycrypto` is installed (e.g., `pip install pycrypto==2.6.1`)
# For generating RSA keys safely, a more robust library like `cryptography` or `PyCryptodome`
# would be used in a real application, not the raw `Crypto.PublicKey.RSA` as it relies on pycrypto.
try:
from Crypto.PublicKey import RSA
except ImportError:
print("Error: `pycrypto` not found. Please install it (pip install pycrypto==2.6.1).")
# Exit or handle error gracefully in a real script
exit(1)
# Generate a new RSA key pair for demonstration purposes
# In a real app, you would load pre-existing keys securely.
key = RSA.generate(2048) # Generates an RSA key with 2048 bits
claims = {
'iss': 'http://www.example.com',
'exp': int(time() + 3600), # Expiration time (1 hour from now)
'aud': 'http://www.example.org',
'sub': 'testuser',
'nbf': int(time()) # Not Before time
}
# --- JWS (JSON Web Signature) Example ---
# Define JWS Protected Header
protected_jws_header = {
'alg': 'RS256' # RSA Signature with SHA-256
}
try:
# Sign the claims with the private key
signed_jws = jose.sign(protected_jws_header, claims, key)
print("Signed JWS:", signed_jws)
# Verify the JWS with the public key
verified_claims = jose.verify(signed_jws, key.publickey())
print("Verified JWS Claims:", verified_claims)
# --- JWE (JSON Web Encryption) Example ---
# Define JWE Protected Header
protected_jwe_header = {
'alg': 'RSA-OAEP', # Algorithm for Content Encryption Key (CEK) encryption
'enc': 'A128CBC-HS256' # Algorithm for content encryption
}
# Encrypt the claims with the recipient's public key
encrypted_jwe = jose.encrypt(protected_jwe_header, claims, key.publickey())
print("Encrypted JWE:", encrypted_jwe)
# Decrypt the JWE with the recipient's private key
decrypted_jwe_payload = jose.decrypt(encrypted_jwe, key)
print("Decrypted JWE Payload:", decrypted_jwe_payload)
except jose.Error as e:
print(f"JOSE Error: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")