JWSkate (JSON Web Crypto for Python)
JWSkate is a Pythonic implementation of the JOSE (JSON Object Signing and Encryption) / JSON Web Crypto related RFCs, including JWS, JWK, JWA, JWT, and JWE. It simplifies cryptographic operations by providing a consistent API built on top of the `cryptography` library. The current version is 0.12.2, with an active release cadence, typically seeing several updates per year.
Warnings
- breaking In v0.11.0, several method parameters accepting a Jwk instance (e.g., `jwk`, `sig_jwk`, `enc_jwk`) were renamed to `key`, `sig_key`, or `enc_key`. They now also accept a `dict` or a `cryptography` key directly.
- breaking In v0.12.2, `decrypt_with_password()` was separated from `decrypt()`, which no longer accepts a password. Encryption/decryption methods were moved to `SymmetricJwk`, and the `enc` parameter is now preferred over `alg` for encryption algorithms.
- gotcha For all signature verification methods, you **must** explicitly provide the expected signature algorithm(s) (via `alg` or `algs` parameters). This prevents critical security vulnerabilities like 'none' algorithm attacks, where an attacker could bypass signature checks by setting `alg` to 'none' in the token header. JWSkate will ignore the `alg` header in the token for security reasons if not explicitly provided or inherited from the key.
- gotcha Jwk, Jwt, Jws, and Jwe objects are subclasses of `collections.UserDict` (or `dict` in older versions), making them behave like dictionaries. However, they are not natively JSON serializable using Python's default `json.dumps()`. Attempting to do so will result in a `TypeError`.
- gotcha The `Jwk.kid` property returns the key's thumbprint (RFC7638) if a `kid` attribute is not explicitly present in the JWK. If you need the literal `kid` value as stored in the JWK, access it directly as `jwk['kid']`.
Install
-
pip install jwskate
Imports
- Jwk
from jwskate import Jwk
- Jwt
from jwskate import Jwt
- Jws
from jwskate import Jws
- Jwe
from jwskate import Jwe
- SymmetricJwk
from jwskate import SymmetricJwk
- InvalidSignature
from jwskate import InvalidSignature
Quickstart
from jwskate import Jwk, Jwt, InvalidSignature
# 1. Generate a private RSA key for signing
private_jwk = Jwk.generate(alg="RS256", key_size=2048, kid="my-rsa-key")
public_jwk = private_jwk.public_jwk()
# 2. Define claims for the JWT
claims = {"sub": "user123", "name": "John Doe", "iat": 1678886400, "exp": 1678890000}
# 3. Sign the JWT
try:
signed_jwt = Jwt.sign(claims, private_jwk)
print(f"Signed JWT: {signed_jwt.compact()}")
except Exception as e:
print(f"Error signing JWT: {e}")
exit(1)
# 4. Verify the JWT signature (using the public key)
try:
# The verify_signature method requires the expected algorithm for security
if signed_jwt.verify_signature(public_jwk, alg="RS256"):
print("JWT signature is valid!")
print(f"Decoded claims: {signed_jwt.claims}")
assert signed_jwt.claims == claims
else:
print("JWT signature verification failed.")
except InvalidSignature:
print("Invalid signature detected!")
except Exception as e:
print(f"Error verifying JWT: {e}")