CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-python-jose

JOSE implementation in Python providing JWT, JWS, JWE, and JWK functionality with multiple cryptographic backends.

75

1.44x
Overview
Eval results
Files

jwk-management.mddocs/

JWK Management

JSON Web Key functionality for constructing, managing, and converting between different key formats and representations. JWK provides a standardized way to represent cryptographic keys in JSON format for use with JOSE operations.

Capabilities

Key Construction

Constructs JWK objects from various key formats and representations for use with JOSE operations.

def construct(key_data, algorithm=None):
    """
    Constructs a JWK from key data.
    
    Args:
        key_data (str or bytes or dict): The key material in various formats:
            - String secrets for HMAC algorithms
            - PEM-formatted RSA/EC keys (public or private)
            - SSH-formatted keys
            - JWK dictionaries (JSON Web Key format)
            - Raw key bytes
        algorithm (str, optional): Algorithm hint for key construction.
            Helps determine the appropriate key type when ambiguous
    
    Returns:
        Key: A key object (HMACKey, RSAKey, ECKey, AESKey, or DIRKey)
            that can be used with jwt, jws, and jwe operations
    
    Raises:
        JWKError: If the key cannot be constructed or format is invalid
    """

Usage Examples:

from jose import jwk
from jose.constants import ALGORITHMS

# HMAC key from string secret
key = jwk.construct('my-secret-key', algorithm=ALGORITHMS.HS256)

# HMAC key from bytes
key = jwk.construct(b'binary-secret-key', algorithm=ALGORITHMS.HS256)

# RSA key from PEM format
rsa_pem = """-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
-----END PRIVATE KEY-----"""

rsa_key = jwk.construct(rsa_pem, algorithm=ALGORITHMS.RS256)

# RSA public key
rsa_public_pem = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----"""

rsa_public_key = jwk.construct(rsa_public_pem)

# EC key from PEM format  
ec_pem = """-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg...
-----END PRIVATE KEY-----"""

ec_key = jwk.construct(ec_pem, algorithm=ALGORITHMS.ES256)

# JWK dictionary format
jwk_dict = {
    'kty': 'oct',  # Key type: octet sequence (symmetric)
    'k': 'GawgguFyGrWKav7AX4VKUg',  # base64url-encoded key value
    'alg': 'HS256',  # Algorithm
    'use': 'sig'     # Usage: signature
}
key = jwk.construct(jwk_dict)

# RSA JWK dictionary
rsa_jwk = {
    'kty': 'RSA',
    'n': 'public-modulus-base64url',
    'd': 'private-exponent-base64url',
    'e': 'AQAB',  # public exponent (65537)
    'alg': 'RS256'
}
rsa_key = jwk.construct(rsa_jwk)

# EC JWK dictionary
ec_jwk = {
    'kty': 'EC',
    'crv': 'P-256',  # Curve
    'x': 'x-coordinate-base64url',
    'y': 'y-coordinate-base64url', 
    'd': 'private-key-base64url',
    'alg': 'ES256'
}
ec_key = jwk.construct(ec_jwk)

# AES key for JWE
aes_key_bytes = b'This is a 32-byte key for AES256!!'
aes_key = jwk.construct(aes_key_bytes, algorithm=ALGORITHMS.A256GCM)

Key Class Retrieval

Gets the appropriate key class for a given algorithm, useful for backend selection and key type determination.

def get_key(algorithm):
    """
    Get key class for algorithm.
    
    Args:
        algorithm (str): The algorithm name (e.g., 'HS256', 'RS256', 'ES256')
    
    Returns:
        type or None: The key class that handles the algorithm, or None if not found
    """

Usage Examples:

from jose import jwk
from jose.constants import ALGORITHMS

# Get key class for HMAC
hmac_key_class = jwk.get_key(ALGORITHMS.HS256)
print(hmac_key_class)  # <class 'jose.backends.cryptography_backend.CryptographyHMACKey'>

# Get key class for RSA
rsa_key_class = jwk.get_key(ALGORITHMS.RS256)
print(rsa_key_class)  # <class 'jose.backends.cryptography_backend.CryptographyRSAKey'>

# Get key class for EC
ec_key_class = jwk.get_key(ALGORITHMS.ES256)
print(ec_key_class)  # <class 'jose.backends.cryptography_backend.CryptographyECKey'>

# Check if algorithm is supported
if jwk.get_key('UNSUPPORTED_ALG') is None:
    print("Algorithm not supported")

# Dynamic key construction
algorithm = ALGORITHMS.HS256
key_class = jwk.get_key(algorithm)
if key_class:
    key = key_class('secret-key', algorithm)

Key Registration

Registers custom key classes for specific algorithms, enabling extensibility for custom cryptographic backends.

def register_key(algorithm, key_class):
    """
    Registers a key class for an algorithm.
    
    Args:
        algorithm (str): The algorithm name to register
        key_class (type): The key class that must inherit from jose.backends.base.Key
    
    Returns:
        bool: True if registration was successful
    
    Raises:
        JWKError: If the key class is invalid or doesn't inherit from Key
    """

Usage Examples:

from jose import jwk
from jose.backends.base import Key

# Custom key implementation
class CustomHMACKey(Key):
    def __init__(self, key_data, algorithm):
        super().__init__(key_data, algorithm)
        # Custom initialization
    
    def sign(self, msg):
        # Custom signing implementation
        pass
    
    def verify(self, msg, sig):
        # Custom verification implementation
        pass

# Register custom key
success = jwk.register_key('CUSTOM_HMAC', CustomHMACKey)
if success:
    print("Custom key registered successfully")

# Use registered key
key = jwk.construct('secret', algorithm='CUSTOM_HMAC')

Key Classes

The JWK module provides access to various key implementation classes through different cryptographic backends.

Base Key Class

class Key:
    """
    Base class for all key implementations.
    
    Args:
        prepared_key: The prepared key material
        algorithm (str): The algorithm this key will be used with
    """
    
    def __init__(self, prepared_key, algorithm):
        """Initialize the key with prepared key material and algorithm."""
    
    def sign(self, msg):
        """
        Sign a message (abstract method).
        
        Args:
            msg (bytes): The message to sign
        
        Returns:
            bytes: The signature
        """
    
    def verify(self, msg, sig):
        """
        Verify a signature (abstract method).
        
        Args:
            msg (bytes): The original message
            sig (bytes): The signature to verify
        
        Returns:
            bool: True if signature is valid
        """
    
    def encrypt(self, plaintext):
        """Encrypt plaintext (abstract method for JWE keys)."""
    
    def decrypt(self, ciphertext, **kwargs):
        """Decrypt ciphertext (abstract method for JWE keys)."""
    
    def wrap_key(self, key_data):
        """Wrap a key (abstract method for key wrapping algorithms)."""
    
    def unwrap_key(self, wrapped_key):
        """Unwrap a key (abstract method for key wrapping algorithms)."""

HMAC Key Class

class HMACKey(Key):
    """
    HMAC key implementation for symmetric signing algorithms.
    
    Supports: HS256, HS384, HS512
    """
    
    def __init__(self, key_data, algorithm):
        """Initialize HMAC key with secret and algorithm."""
    
    def to_dict(self):
        """
        Convert key to JWK dictionary format.
        
        Returns:
            dict: JWK representation of the key
        """
    
    def sign(self, msg):
        """Sign message with HMAC."""
    
    def verify(self, msg, sig):
        """Verify HMAC signature."""

RSA Key Class

class RSAKey(Key):
    """
    RSA key implementation for asymmetric operations.
    
    Supports: RS256, RS384, RS512, PS256, PS384, PS512 (backend dependent)
    Key wrapping: RSA1_5, RSA-OAEP, RSA-OAEP-256
    """
    
    def __init__(self, key_data, algorithm):
        """Initialize RSA key from PEM data or JWK dictionary."""
    
    def to_dict(self):
        """Convert to JWK dictionary format."""
    
    def sign(self, msg):
        """Sign message with RSA private key."""
    
    def verify(self, msg, sig):
        """Verify signature with RSA public key."""
    
    def encrypt(self, plaintext):
        """Encrypt with RSA public key (for JWE)."""
    
    def decrypt(self, ciphertext):
        """Decrypt with RSA private key (for JWE)."""

EC Key Class

class ECKey(Key):
    """
    Elliptic Curve key implementation.
    
    Supports: ES256, ES384, ES512
    Curves: P-256, P-384, P-521
    """
    
    def __init__(self, key_data, algorithm):
        """Initialize EC key from PEM data or JWK dictionary."""
    
    def to_dict(self):
        """Convert to JWK dictionary format."""
    
    def sign(self, msg):
        """Sign message with EC private key."""
    
    def verify(self, msg, sig):
        """Verify signature with EC public key."""

AES Key Class

class AESKey(Key):
    """
    AES key implementation for symmetric encryption.
    
    Supports: A128KW, A192KW, A256KW (key wrapping)
             A128GCM, A192GCM, A256GCM (content encryption)
    """
    
    def __init__(self, key_data, algorithm):
        """Initialize AES key with key bytes."""
    
    def encrypt(self, plaintext):
        """Encrypt with AES (algorithm-dependent mode)."""
    
    def decrypt(self, ciphertext, **kwargs):
        """Decrypt with AES (algorithm-dependent mode)."""
    
    def wrap_key(self, key_data):
        """Wrap key with AES key wrapping."""
    
    def unwrap_key(self, wrapped_key):
        """Unwrap key with AES key wrapping."""

JWK Dictionary Format

JWK (JSON Web Key) provides a standardized JSON representation for cryptographic keys:

Symmetric Keys (HMAC)

# HMAC key JWK format
hmac_jwk = {
    'kty': 'oct',           # Key type: octet sequence
    'k': 'base64url-key',   # Key value (base64url encoded)
    'alg': 'HS256',         # Algorithm (optional)
    'use': 'sig',           # Usage: sig (signature) or enc (encryption)
    'kid': 'key-id'         # Key ID (optional)
}

RSA Keys

# RSA private key JWK format
rsa_private_jwk = {
    'kty': 'RSA',           # Key type: RSA
    'n': 'modulus-b64url',  # Public modulus
    'e': 'AQAB',            # Public exponent (usually 65537)
    'd': 'private-exp-b64url',  # Private exponent
    'p': 'prime1-b64url',   # First prime factor
    'q': 'prime2-b64url',   # Second prime factor
    'dp': 'exp1-b64url',    # First factor exponent
    'dq': 'exp2-b64url',    # Second factor exponent
    'qi': 'coefficient-b64url',  # Coefficient
    'alg': 'RS256',         # Algorithm
    'use': 'sig',           # Usage
    'kid': 'rsa-key-1'      # Key ID
}

# RSA public key JWK format (subset of private)
rsa_public_jwk = {
    'kty': 'RSA',
    'n': 'modulus-b64url',
    'e': 'AQAB',
    'alg': 'RS256',
    'use': 'sig',
    'kid': 'rsa-key-1'
}

Elliptic Curve Keys

# EC private key JWK format
ec_private_jwk = {
    'kty': 'EC',            # Key type: Elliptic Curve
    'crv': 'P-256',         # Curve: P-256, P-384, or P-521
    'x': 'x-coord-b64url',  # X coordinate
    'y': 'y-coord-b64url',  # Y coordinate  
    'd': 'private-key-b64url',  # Private key
    'alg': 'ES256',         # Algorithm
    'use': 'sig',           # Usage
    'kid': 'ec-key-1'       # Key ID
}

# EC public key JWK format (without 'd')
ec_public_jwk = {
    'kty': 'EC',
    'crv': 'P-256',
    'x': 'x-coord-b64url',
    'y': 'y-coord-b64url',
    'alg': 'ES256',
    'use': 'sig',
    'kid': 'ec-key-1'
}

Key Format Support

The JWK module supports various input key formats:

PEM Format

# RSA private key in PEM format
rsa_pem = """-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
-----END PRIVATE KEY-----"""

# RSA public key in PEM format  
rsa_public_pem = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----"""

# EC private key in PEM format
ec_pem = """-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg...
-----END PRIVATE KEY-----"""

# Construct keys from PEM
rsa_key = jwk.construct(rsa_pem)
ec_key = jwk.construct(ec_pem)

Raw Key Material

# HMAC secret as string or bytes
hmac_secret = 'my-secret-key'
hmac_bytes = b'binary-secret-key'

# AES key as bytes (specific lengths)
aes_128_key = b'16-byte key here'
aes_256_key = b'This is a 32-byte key for AES256!!'

# Construct from raw material
hmac_key = jwk.construct(hmac_secret, algorithm='HS256')
aes_key = jwk.construct(aes_256_key, algorithm='A256GCM')

Backend Integration

JWK automatically selects the best available cryptographic backend:

# Backend priority (highest to lowest):
# 1. cryptography (pyca/cryptography) - Recommended
# 2. native-python (python-rsa, python-ecdsa)
# 3. pycryptodome (alternative backend)

# Check which backend is being used
key = jwk.construct('secret', algorithm='HS256')
print(type(key))  # Shows the backend class being used

# Examples of backend classes:
# - CryptographyHMACKey (cryptography backend)
# - CryptographyRSAKey (cryptography backend)
# - CryptographyECKey (cryptography backend)
# - RSAKey (native backend)
# - ECDSAECKey (native backend)

Error Handling

JWK operations can raise specific exceptions:

class JWKError(JOSEError):
    """Base exception for JWK-related errors."""

Error Handling Examples:

from jose.exceptions import JWKError

try:
    # Invalid key format
    key = jwk.construct('invalid-key-format')
except JWKError as e:
    print(f"Key construction failed: {e}")

try:
    # Unsupported algorithm
    key_class = jwk.get_key('UNKNOWN_ALGORITHM')
    if key_class is None:
        print("Algorithm not supported")
except JWKError as e:
    print(f"Key retrieval failed: {e}")

try:
    # Invalid JWK dictionary
    invalid_jwk = {'kty': 'INVALID', 'k': 'key'}
    key = jwk.construct(invalid_jwk)
except JWKError as e:
    print(f"Invalid JWK: {e}")

Usage with Other JOSE Operations

JWK objects integrate seamlessly with JWT, JWS, and JWE operations:

from jose import jwt, jws, jwe, jwk

# Construct key once, use everywhere
key = jwk.construct('shared-secret', algorithm='HS256')

# Use with JWT
token = jwt.encode({'user': 'john'}, key)
claims = jwt.decode(token, key, algorithms=['HS256'])

# Use with JWS
signature = jws.sign('message', key)
payload = jws.verify(signature, key, algorithms=['HS256'])

# For JWE (with appropriate key type)
aes_key = jwk.construct(b'32-byte-key-for-aes-256-gcm!!!!', algorithm='A256GCM')
encrypted = jwe.encrypt(b'secret', aes_key, algorithm='dir')
plaintext = jwe.decrypt(encrypted, aes_key)

Best Practices

  1. Key Generation: Use cryptographically secure random sources for key generation
  2. Key Storage: Store keys securely, separate from application code
  3. Key Rotation: Implement regular key rotation with overlapping validity periods
  4. Algorithm Selection: Use strong algorithms (HS256+, RS256+, ES256+)
  5. Key Size: Use appropriate key sizes (256-bit HMAC, 2048+ bit RSA, P-256+ EC)
  6. JWK Format: Use JWK format for key distribution and storage when possible
  7. Backend Selection: Prefer cryptography backend for production environments
  8. Error Handling: Always handle JWKError exceptions in key operations

Install with Tessl CLI

npx tessl i tessl/pypi-python-jose

docs

constants-algorithms.md

index.md

jwe-operations.md

jwk-management.md

jws-operations.md

jwt-operations.md

tile.json