Skip to content

Latest commit

 

History

History
252 lines (190 loc) · 7.06 KB

File metadata and controls

252 lines (190 loc) · 7.06 KB

Python Explicit Configuration API - Implementation Summary

Overview

Successfully implemented the explicit configuration API for the Python package (flarelette-jwt-py), providing identical functionality to the TypeScript implementation.

Changes Made

1. New Module: flarelette_jwt/explicit.py (611 lines)

Configuration Types:

  • BaseJwtConfig - Shared configuration (iss, aud, ttl_seconds, leeway)
  • HS512Config - Symmetric (shared secret) configuration
  • EdDSASignConfig - Asymmetric signing configuration
  • EdDSAVerifyConfig - Asymmetric verification configuration
  • SignConfig - Union type for signing
  • VerifyConfig - Union type for verification

Core Functions:

  • sign_with_config() - Sign JWT with explicit config
  • verify_with_config() - Verify JWT with explicit config

High-Level Functions:

  • create_token_with_config() - Convenience wrapper for signing
  • create_delegated_token_with_config() - RFC 8693 service delegation
  • check_auth_with_config() - Verify + authorize with policies

Helper Functions:

  • create_hs512_config() - Build HS512 config from base64url secret
  • create_eddsa_sign_config() - Build EdDSA sign config from JWK
  • create_eddsa_verify_config() - Build EdDSA verify config from JWK

2. Updated: flarelette_jwt/__init__.py

Added exports for all new explicit API functions and types:

  • 8 new configuration types
  • 6 new functions for explicit configuration

3. Code Quality

All linting checks passAll type checking passes (mypy) ✅ Follows Python best practices

API Examples

HS512 Example

from flarelette_jwt import sign_with_config, verify_with_config, create_hs512_config

# Create configuration object (no environment variables needed!)
config = create_hs512_config(
    b'your-32-byte-secret-here...',
    iss='https://gateway.example.com',
    aud='api.example.com',
    ttl_seconds=900,
)

# Sign a token
token = await sign_with_config(
    {'sub': 'user123', 'permissions': ['read:data']},
    config
)

# Verify the token
payload = await verify_with_config(token, config)
print('User:', payload.get('sub'))

EdDSA Example

from flarelette_jwt import (
    create_eddsa_sign_config,
    create_eddsa_verify_config,
    sign_with_config,
    verify_with_config,
)

# Producer configuration
sign_config = create_eddsa_sign_config(
    {
        'kty': 'OKP',
        'crv': 'Ed25519',
        'd': 'private-key-d-value',
        'x': 'public-key-x-value',
    },
    iss='https://gateway.example.com',
    aud='api.example.com',
    kid='ed25519-2025-01',
)

# Consumer configuration
verify_config = create_eddsa_verify_config(
    {
        'kty': 'OKP',
        'crv': 'Ed25519',
        'x': 'public-key-x-value',
    },
    iss='https://gateway.example.com',
    aud='api.example.com',
)

# Sign and verify
token = await sign_with_config({'sub': 'user456'}, sign_config)
payload = await verify_with_config(token, verify_config)

Service Delegation Example

from flarelette_jwt import create_delegated_token_with_config

# Gateway creates delegated token for internal service
config = create_hs512_config(
    secret,
    iss='https://gateway.example.com',
    aud='internal-api',
)

auth0_payload = await verify_auth0_token(external_token)
internal_token = await create_delegated_token_with_config(
    auth0_payload,
    'gateway-service',
    config,
)

Authorization Example

from flarelette_jwt import check_auth_with_config

user = await check_auth_with_config(
    token,
    config,
    {
        'require_all_permissions': ['read:data'],
        'require_any_permission': ['admin', 'editor'],
        'predicates': [
            lambda payload: payload.get('email', '').endswith('@example.com')
        ],
    },
)

if user:
    print('Authorized user:', user['sub'])

API Parity with TypeScript

Feature TypeScript Python Status
HS512 signing ✅ Identical
HS512 verification ✅ Identical
EdDSA verification ✅ Identical
EdDSA signing ⚠️ Runtime error (expected)
Service delegation ✅ Identical
Authorization policies ✅ Identical
Helper functions ✅ Identical
Type safety ✅ Identical

Note: EdDSA signing in Python raises RuntimeError as expected - Python Workers should only verify tokens, not sign them. This matches the existing behavior.

Benefits for Python Users

Before (Environment-Based)

# Required JWT_SECRET, JWT_ISS, JWT_AUD environment variables
from flarelette_jwt import sign, verify

token = await sign({'sub': 'user123'})
payload = await verify(token)

After (Explicit Config)

# No environment variables required!
from flarelette_jwt import sign_with_config, create_hs512_config

config = create_hs512_config(
    secret,
    iss='http://localhost:8787',
    aud='http://localhost:8788',
)

token = await sign_with_config({'sub': 'user123'}, config)

Testing Benefits

# Completely isolated from environment
test_config = {
    'alg': 'HS512',
    'secret': b'\\x00' * 32,
    'iss': 'test-issuer',
    'aud': 'test-audience',
}

token = await sign_with_config({'sub': 'test'}, test_config)
payload = await verify_with_config(token, test_config)
assert payload['sub'] == 'test'

Implementation Notes

  1. Type Safety: Uses TypedDict for configuration objects, providing IDE autocomplete and type checking
  2. Runtime Validation: Validates secret length (min 32 bytes) at runtime
  3. Error Handling: Returns None on verification failure (matches existing API)
  4. EdDSA Limitation: EdDSA signing raises RuntimeError (intentional - Python Workers are consumers only)
  5. Compatibility: 100% backward compatible with existing environment-based API

Files Changed

  • Added: packages/flarelette-jwt-py/flarelette_jwt/explicit.py (611 lines)
  • 📝 Updated: packages/flarelette-jwt-py/flarelette_jwt/__init__.py (added exports)

Quality Checks

Ruff linting: All checks pass ✅ Mypy type checking: Success, no issues found
Import sorting: Properly ordered ✅ Code style: Follows PEP 8 and project conventions

Next Steps

  1. ✅ TypeScript implementation complete
  2. ✅ Python implementation complete
  3. ⏭️ Add Python tests (mirror TypeScript test suite)
  4. ⏭️ Update documentation
  5. ⏭️ Publish new version

Cross-Language Consistency

The Python implementation exactly mirrors the TypeScript implementation:

  • Same function names
  • Same parameter names
  • Same behavior
  • Same configuration structure
  • Same error handling

This ensures developers can seamlessly work across both languages with zero cognitive overhead.