CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-josepy

JOSE protocol implementation in Python with support for JSON Web Algorithms, Keys, and Signatures

73

1.15x
Overview
Eval results
Files

errors.mddocs/

Error Handling

Comprehensive error hierarchy for serialization, deserialization, and cryptographic operation failures with detailed error information for debugging and error recovery.

Capabilities

Base Error Class

Root exception class for all JOSE-related errors.

class Error(Exception):
    """
    Generic JOSE Error.
    
    Base class for all JOSE-related exceptions. Inherit from this
    class when creating custom JOSE error types.
    """

Serialization Errors

Errors that occur during JSON serialization operations.

class SerializationError(Error):
    """
    JSON serialization error.
    
    Raised when an object cannot be serialized to JSON format,
    typically due to unsupported data types or circular references.
    """

Deserialization Errors

Errors that occur during JSON deserialization and data validation.

class DeserializationError(Error):
    """
    JSON deserialization error.
    
    Raised when JSON data cannot be parsed or converted to the
    expected object type. Common causes include:
    - Invalid JSON structure
    - Missing required fields
    - Type conversion failures
    - Size validation failures
    """
    
    def __str__(self) -> str:
        """Returns formatted error message with 'Deserialization error:' prefix"""

Type Recognition Errors

Specialized deserialization error for unknown or unsupported object types.

class UnrecognizedTypeError(DeserializationError):
    """
    Unrecognized type error.
    
    Raised when attempting to deserialize a JSON object with an
    unknown or unsupported type identifier.
    """
    
    def __init__(self, typ: str, jobj: Any) -> None:
        """
        Initialize with type information.
        
        Parameters:
        - typ: The unrecognized type identifier
        - jobj: Full JSON object that caused the error
        """
    
    def __str__(self) -> str:
        """Returns detailed error message with type and full object"""
    
    typ: str  # The unrecognized type identifier
    jobj: Any  # Full JSON object

Usage Examples

Basic Error Handling

from josepy import JWS, JWKRSA, RS256
from josepy.errors import Error, DeserializationError, SerializationError

try:
    # Attempt to load invalid JWS
    jws = JWS.json_loads('{"invalid": "jws_structure"}')
except DeserializationError as e:
    print(f"Failed to parse JWS: {e}")
    # Handle invalid input gracefully

try:
    # Attempt signature verification with wrong key
    payload = jws.verify(wrong_key)
except Error as e:
    print(f"Signature verification failed: {e}")
    # Handle authentication failure

Specific Error Type Handling

from josepy import JWK
from josepy.errors import UnrecognizedTypeError, DeserializationError

# Example JSON with unknown key type
unknown_jwk_json = '''
{
    "kty": "unknown_key_type",
    "use": "sig",
    "n": "...",
    "e": "AQAB"
}
'''

try:
    jwk = JWK.json_loads(unknown_jwk_json)
except UnrecognizedTypeError as e:
    print(f"Unknown key type: {e.typ}")
    print(f"Full object: {e.jobj}")
    # Could fall back to a different key handling strategy
    
except DeserializationError as e:
    print(f"General deserialization error: {e}")
    # Handle other parsing issues

Error Context and Debugging

import json
from josepy import JWKRSA
from josepy.errors import DeserializationError

# Detailed error handling with context
def safe_jwk_load(jwk_data: str) -> Optional[JWKRSA]:
    try:
        # First validate JSON structure
        json_obj = json.loads(jwk_data)
        
        # Then attempt JWK deserialization
        return JWKRSA.json_loads(jwk_data)
        
    except json.JSONDecodeError as e:
        print(f"Invalid JSON at line {e.lineno}, column {e.colno}: {e.msg}")
        return None
        
    except DeserializationError as e:
        print(f"JWK deserialization failed: {e}")
        print(f"Input data: {jwk_data[:100]}..." if len(jwk_data) > 100 else jwk_data)
        return None
        
    except Exception as e:
        print(f"Unexpected error: {type(e).__name__}: {e}")
        return None

# Usage
jwk = safe_jwk_load(potentially_invalid_jwk_json)
if jwk is None:
    print("Failed to load JWK, using default key")
    jwk = get_default_key()

Cryptographic Error Integration

import cryptography.exceptions
from josepy import RS256, JWKRSA
from josepy.errors import Error

def safe_sign_and_verify(message: bytes, jwk: JWKRSA) -> bool:
    try:
        # Sign message
        signature = RS256.sign(jwk.key, message)
        
        # Verify signature
        is_valid = RS256.verify(jwk.public_key().key, message, signature)
        return is_valid
        
    except cryptography.exceptions.InvalidSignature:
        print("Cryptographic signature operation failed")
        return False
        
    except Error as e:
        print(f"JOSE operation failed: {e}")
        return False
        
    except Exception as e:
        print(f"Unexpected error: {e}")
        return False

# Usage
success = safe_sign_and_verify(b"test message", my_jwk)
print(f"Signature test: {'PASSED' if success else 'FAILED'}")

Error Recovery Strategies

from josepy import JWK, JWKRSA, JWKEC, JWKOct
from josepy.errors import UnrecognizedTypeError, DeserializationError

def robust_jwk_loader(jwk_json: str) -> Optional[JWK]:
    """
    Attempt to load JWK with multiple fallback strategies.
    """
    try:
        # First try generic JWK loading
        return JWK.from_json(json.loads(jwk_json))
        
    except UnrecognizedTypeError as e:
        print(f"Unknown key type '{e.typ}', trying specific loaders...")
        
        # Try specific key types as fallbacks
        json_obj = e.jobj
        
        if json_obj.get('kty') == 'RSA':
            try:
                return JWKRSA.from_json(json_obj)
            except DeserializationError:
                pass
                
        elif json_obj.get('kty') == 'EC':
            try:
                return JWKEC.from_json(json_obj)
            except DeserializationError:
                pass
                
        elif json_obj.get('kty') == 'oct':
            try:
                return JWKOct.from_json(json_obj)
            except DeserializationError:
                pass
        
        print("All fallback strategies failed")
        return None
        
    except DeserializationError as e:
        print(f"Deserialization failed: {e}")
        return None

# Usage with graceful degradation
jwk = robust_jwk_loader(received_jwk_json)
if jwk is None:
    print("Using fallback authentication method")
    # Implement alternative authentication

Logging and Monitoring

import logging
from josepy.errors import Error, DeserializationError, SerializationError

# Configure logging for JOSE operations
logger = logging.getLogger('josepy_operations')

def logged_jws_operation(operation_name: str, operation_func, *args, **kwargs):
    """Wrapper for JWS operations with comprehensive logging."""
    try:
        logger.info(f"Starting {operation_name}")
        result = operation_func(*args, **kwargs)
        logger.info(f"Successfully completed {operation_name}")
        return result
        
    except DeserializationError as e:
        logger.error(f"{operation_name} deserialization failed: {e}")
        raise
        
    except SerializationError as e:
        logger.error(f"{operation_name} serialization failed: {e}")
        raise
        
    except Error as e:
        logger.error(f"{operation_name} JOSE error: {e}")
        raise
        
    except Exception as e:
        logger.critical(f"{operation_name} unexpected error: {type(e).__name__}: {e}")
        raise

# Usage
try:
    jws = logged_jws_operation("JWS creation", JWS.sign, payload, key=jwk, alg=RS256)
    verified = logged_jws_operation("JWS verification", jws.verify, public_jwk)
except Error:
    # Handle JOSE-specific errors
    handle_jose_error()

Error Classification

By Origin

  • Input Validation: DeserializationError, UnrecognizedTypeError
  • Output Generation: SerializationError
  • Cryptographic Operations: Error (with underlying cryptography exceptions)
  • Generic JOSE: Error (base class)

By Severity

  • Critical: Cryptographic signature failures (security implications)
  • High: Type recognition failures (compatibility issues)
  • Medium: General deserialization failures (data quality issues)
  • Low: Serialization failures (output formatting issues)

By Recovery Strategy

  • Retryable: Temporary network or resource issues
  • Fallback: Alternative algorithms or key types available
  • Abort: Security violations or critical data corruption
  • Graceful: Continue with reduced functionality

Best Practices

  1. Catch Specific Exceptions: Handle UnrecognizedTypeError differently from general DeserializationError
  2. Preserve Error Context: Log full error messages and relevant data for debugging
  3. Implement Fallbacks: Design systems to gracefully handle unknown key types or algorithms
  4. Security First: Treat cryptographic errors as security events requiring careful handling
  5. User-Friendly Messages: Convert technical error messages to user-appropriate language
  6. Monitoring: Track error patterns to identify systemic issues or attack attempts

Install with Tessl CLI

npx tessl i tessl/pypi-josepy

docs

errors.md

index.md

interfaces.md

jwa.md

jwk.md

jws.md

utilities.md

tile.json