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

interfaces.mddocs/

JSON Serialization Interfaces

Core interfaces and base classes providing JSON serialization and deserialization functionality for all JOSE objects. These interfaces define the contract for converting Python objects to/from JSON representations with proper error handling and type safety.

Capabilities

JSON Serialization Interface

Base interface implemented by all JOSE objects for JSON serialization and deserialization with support for partial and full serialization modes.

class JSONDeSerializable:
    """Interface for JSON serializable/deserializable objects"""
    
    def to_partial_json(self) -> Any:
        """
        Perform partial serialization to JSON-compatible objects.
        
        Partial serialization may include other JSONDeSerializable objects
        that need further processing for full serialization.
        
        Returns:
        Any: Partially serialized object (may contain JSONDeSerializable instances)
        
        Raises:
        josepy.errors.SerializationError: If serialization fails
        """
    
    def to_json(self) -> Any:
        """
        Perform full serialization to basic Python types only.
        
        Recursively serializes all JSONDeSerializable objects to basic types
        suitable for JSON encoding (dict, list, str, int, float, bool, None).
        
        Returns:
        Any: Fully serialized object containing only basic Python types
        
        Raises:
        josepy.errors.SerializationError: If serialization fails
        """
    
    @classmethod
    def from_json(cls, jobj: Any) -> 'JSONDeSerializable':
        """
        Deserialize from JSON-compatible Python object.
        
        Parameters:
        - jobj: Python object from json.loads() or equivalent
        
        Returns:
        JSONDeSerializable: Deserialized object instance
        
        Raises:
        josepy.errors.DeserializationError: If deserialization fails
        """
    
    @classmethod
    def json_loads(cls, json_string: Union[str, bytes]) -> 'JSONDeSerializable':
        """
        Deserialize from JSON document string.
        
        Parameters:
        - json_string: JSON document as string or bytes
        
        Returns:
        JSONDeSerializable: Deserialized object instance
        
        Raises:
        josepy.errors.DeserializationError: If JSON parsing or deserialization fails
        """
    
    def json_dumps(self, **kwargs) -> str:
        """
        Serialize to JSON document string.
        
        Parameters:
        - **kwargs: Additional arguments passed to json.dumps()
        
        Returns:
        str: JSON document string
        """
    
    def json_dumps_pretty(self) -> str:
        """
        Serialize to pretty-formatted JSON string.
        
        Returns:
        str: Pretty-formatted JSON document with indentation and sorting
        """
    
    @classmethod
    def json_dump_default(cls, python_object: 'JSONDeSerializable') -> Any:
        """
        Default serializer function for json.dumps().
        
        This method is used as the 'default' parameter for json.dumps()
        to handle JSONDeSerializable objects.
        
        Parameters:
        - python_object: Object to serialize
        
        Returns:
        Any: Serialized representation
        
        Raises:
        TypeError: If object is not JSONDeSerializable
        """

Usage Examples

Basic Serialization

from josepy import JWK, JWKRSA
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend

# Create a JWK (which implements JSONDeSerializable)
private_key = rsa.generate_private_key(65537, 2048, default_backend())
jwk = JWKRSA(key=private_key)

# Serialize to JSON string
jwk_json = jwk.json_dumps()
print(f"JWK JSON: {jwk_json}")

# Pretty print
pretty_json = jwk.json_dumps_pretty()
print(f"Pretty JWK:\n{pretty_json}")

# Deserialize from JSON
loaded_jwk = JWKRSA.json_loads(jwk_json)
assert jwk.thumbprint() == loaded_jwk.thumbprint()

Custom JSON Encoding

import json
from josepy import JWS, Header, RS256

# Create JWS (JSONDeSerializable object)
payload = b'{"user": "alice", "role": "admin"}'
jws = JWS.sign(payload, key=jwk, alg=RS256)

# Use custom JSON encoder
custom_json = json.dumps(jws, default=JWS.json_dump_default, indent=2)
print(f"Custom encoded JWS:\n{custom_json}")

# Load back
loaded_jws = JWS.from_json(json.loads(custom_json))

Partial vs Full Serialization

# Demonstrate the difference between partial and full serialization
header = Header(alg=RS256, jwk=jwk.public_key())

# Partial serialization may contain JSONDeSerializable objects
partial = header.to_partial_json()
print(f"Partial serialization type of 'jwk': {type(partial.get('jwk'))}")
# Output: <class 'josepy.jwk.JWKRSA'>

# Full serialization contains only basic Python types
full = header.to_json()
print(f"Full serialization type of 'jwk': {type(full.get('jwk'))}")
# Output: <class 'dict'>

Error Handling

from josepy.errors import DeserializationError, SerializationError

try:
    # Invalid JSON structure
    invalid_jwk = JWKRSA.json_loads('{"invalid": "structure"}')
except DeserializationError as e:
    print(f"Deserialization failed: {e}")

try:
    # Malformed JSON string
    malformed_jwk = JWKRSA.json_loads('invalid json')
except DeserializationError as e:
    print(f"JSON parsing failed: {e}")

Integration with Standard JSON Module

import json
from josepy import JWK, JWKRSA, Header, RS256

# List of JOSE objects
jose_objects = [
    JWKRSA(key=private_key),
    Header(alg=RS256, kid="key-1"),
    # ... other JOSE objects
]

# Serialize list of JOSE objects
serialized = json.dumps(
    jose_objects,
    default=JSONDeSerializable.json_dump_default,
    indent=2
)

print(f"Serialized JOSE objects:\n{serialized}")

# The serialized JSON can be loaded back using appropriate from_json methods
data = json.loads(serialized)
# Then reconstruct objects based on their types

Design Principles

Serialization Modes

  1. Partial Serialization (to_partial_json()):

    • May contain other JSONDeSerializable objects
    • Suitable for intermediate processing
    • Used internally by the serialization framework
  2. Full Serialization (to_json()):

    • Contains only basic Python types
    • Suitable for final JSON encoding
    • Recursively processes all nested objects

Error Handling

  • SerializationError: Raised when objects cannot be converted to JSON-compatible format
  • DeserializationError: Raised when JSON data cannot be converted back to Python objects
  • TypeError: Raised by json_dump_default() for non-JSONDeSerializable objects

Integration Pattern

All JOSE objects (JWK, JWS, Header, etc.) implement this interface, providing:

  • Consistent serialization behavior across all objects
  • Automatic handling of nested JOSE objects
  • Proper error reporting and debugging information
  • Integration with standard Python json module

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