This release is a pre-release and may not be stable for production use.
CrimsonForge Library
A reusable Django library for validating JWT tokens issued by the CrimsonForge Web App backend using Ed25519 public key verification.
Public source for noncommercial use under PolyForm Noncommercial 1.0.0. Commercial use requires a separate written license from Crimson Forge, LLC.
Features
- Ed25519 JWT Verification: Secure asymmetric signature verification using public keys
- Automatic Key Fetching: Public keys are automatically fetched from the WA backend
- Key Caching: Public keys are cached to minimize API calls
- Key Rotation Support: Automatic handling of key rotation via
kidheader - Django Middleware: Automatic authentication on all requests
- View Decorators: Easy authentication and permission enforcement
- Team Isolation: Built-in support for multi-tenant applications
- Proof of Possession: Browser handshake and per-request proofs backed by Redis
Installation
Requires Python 3.10 or newer and Django 5.2.17 or newer. Django REST Framework
integrations use the optional drf extra. PoP requires a Redis service.
From Source
git clone --branch main https://github.com/CrimsonForge-io/crimsonforge-library.git
cd crimsonforge-library
python -m pip install .
From PyPI
python -m pip install crimsonforge==2.5.6
For Django REST Framework integrations, install crimsonforge[drf]==2.5.6.
Stable releases come from main; development releases come from dev and use
versions such as 2.5.7.dev0. Pin the exact version in each deployment. To
enforce the selection at Django startup, configure:
# Production
CRIMSONFORGE_LIBRARY_CHANNEL=main
CRIMSONFORGE_LIBRARY_VERSION=2.5.6
# Development (with crimsonforge==2.5.7.dev0 installed)
CRIMSONFORGE_LIBRARY_CHANNEL=dev
CRIMSONFORGE_LIBRARY_VERSION=2.5.7.dev0
Set one pair for the environment. A wrong channel or version stops Django startup. These settings select the library release; configure the matching CrimsonForge webapp API URL separately. Existing integrations can omit them until they adopt release pinning.
Quick Start
1. Configure Django Settings
Add the middleware and configure the WA backend URL:
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# Authenticate before verifying proof of possession
'crimsonforge.auth.JWTAuthMiddleware',
'crimsonforge.pop.PoPAuthMiddleware',
# ... other middleware
]
# CrimsonForge configuration
CRIMSONFORGE = {
'team_id': 'your-team-uuid', # Required - get from Settings > Backend Configuration
'service_name': 'king_phisher', # Your service name
'exempt_paths': ['/health/', '/status/'], # Paths without auth
'require_auth': True, # Return 401 for missing tokens
'pop_redis_url': 'redis://localhost:6379/0',
# 'wa_backend_url': 'https://api.crimsonforge.io/api', # Default, override if needed
# 'public_key_cache_ttl': 3600, # Cache public key for 1 hour (default)
}
# Or use environment variables:
# CRIMSONFORGE_TEAM_ID=your-team-uuid (Required)
# CRIMSONFORGE_SERVICE_NAME=king_phisher
# CRIMSONFORGE_WA_BACKEND_URL=https://api.crimsonforge.io/api (prod, the default; dev: https://dev-api.crimsonforge.io/api)
# Service credentials are ONLY for backends that validate platform API keys
# through crimsonforge.api_keys (the managed TrashHound deployment). They are
# issued by CrimsonForge operators and cannot be created in the web portal.
# King Phisher and other self-hosted backends do not need them.
# CRIMSONFORGE_SERVICE_CLIENT_ID=credential-uuid
# CRIMSONFORGE_SERVICE_CLIENT_SECRET=show-once-secret
# CRIMSONFORGE_POP_REDIS_URL=redis://localhost:6379/0
Add crimsonforge to INSTALLED_APPS and run python manage.py migrate when
integrating it into an existing Django application. The package includes its
historical migrations, including removal of the retired local team-key cache.
Your application must expose its PoP handshake POST route and protect it with JWT authentication while exempting it from the per-request PoP proof check. See the existing KP integration for application routing. The library supplies handshake helpers; installing it does not add application URL routes.
Machine-initiated calls use the client credential only at the WA backend's token exchange. The library caches the returned 15-minute JWT, renews it up to 60 seconds early, briefly backs off when an early refresh fails, and performs one coordinated forced refresh after a 401. The durable client secret is never sent to application endpoints.
2. Protect Your Views
Use decorators to enforce authentication:
# views.py
from django.http import JsonResponse
from crimsonforge.decorators import require_authenticated, require_admin
@require_authenticated
def list_campaigns(request):
"""List all campaigns for the authenticated team."""
team_id = request.team_id # Automatically set by middleware
user_id = request.user_id
email = request.email
campaigns = Campaign.objects.filter(team_id=team_id)
return JsonResponse({
'campaigns': [c.to_dict() for c in campaigns]
})
@require_admin
def admin_settings(request):
"""Admin-only endpoint."""
# Only users with team_role='admin' can access
return JsonResponse({'settings': {...}})
3. Access Token Data in Views
The middleware attaches token data to every authenticated request:
def my_view(request):
if request.is_authenticated:
user_id = request.user_id
team_id = request.team_id
email = request.email
# Access full token for more details
token = request.token
is_admin = token.is_admin()
mfa_verified = token.mfa_verified
Architecture
Token Flow
- User authenticates via WebAuthn on the WA backend
- WA backend issues JWT signed with Ed25519 private key
- Frontend stores JWT and sends with all API requests
- Your backend validates JWT using public key from WA backend
- Public key is cached for performance (1 hour TTL)
- Key rotation is handled automatically via
kidheader
JWT Token Structure
{
"alg": "EdDSA",
"typ": "JWT",
"kid": "key-id-uuid"
}
{
"sub": "user-uuid",
"email": "user@example.com",
"team_id": "team-uuid",
"team_role": "admin",
"mfa": true,
"exp": 1234567890,
"iat": 1234565090
}
API Reference
Middleware
JWTAuthMiddleware
Validates tokens and attaches authentication data to request:
request.token- AccessToken object (or None)request.team_id- Team ID from token (or None)request.user_id- User ID from token (or None)request.email- Email from token (or None)request.is_authenticated- Boolean
Configuration options:
team_id- Team ID this backend serves (required)wa_backend_url- Web-app API base URL including/api(dev:https://dev-api.crimsonforge.io/api, prod:https://api.crimsonforge.io/api; default is prod)exempt_paths- List of paths to skip auth checkrequire_auth- If True, return 401 for missing tokenspublic_key_cache_ttl- Cache TTL in seconds (default: 3600)jwt_leeway_seconds- JWT clock tolerance foriat,nbf, andexp(default: 60; integer 0–120). This deliberately permits up to 60 seconds after expiration by default. Set through Django'sCRIMSONFORGEsettings orCRIMSONFORGE_JWT_LEEWAY_SECONDS. Signature, identity, permissions, and PoP verification remain required.pop_counter_window- Out-of-order counter window (default: 256; 0–4096). Each counter is accepted once across HTTP and WebSocket requests. Replay tracking uses bounded session storage. Sessions created before replay tracking was introduced require a new handshake after upgrading.
PoP's timestamp freshness window remains 30 seconds. Browser clients can anchor proof timestamps to the backend's handshake server_ts and advance using a monotonic clock. JWT tolerance covers modest differences between the token issuer and backend; it does not synchronize system clocks or allow arbitrary clock drift. JWT failures include reason_code: token_not_yet_valid for future timestamps and token_expired beyond the expiration tolerance, while retaining error: invalid_token for compatibility.
Decorators
@require_authenticated
Requires a valid authentication token.
@require_authenticated
def my_view(request):
...
@require_admin
Requires admin team role.
@require_admin
def admin_view(request):
...
@require_permission(permission)
Requires a specific permission string.
@require_any_permission(permissions)
Requires at least one permission from a list.
@require_all_permissions(permissions)
Requires all permissions from a list.
Token Validation
validate_token(token_string)
Manually validate a JWT token:
from crimsonforge.tokens import validate_token
try:
token = validate_token(jwt_string)
print(f"User: {token.user_id}, Team: {token.team_id}")
except TokenValidationError as e:
print(f"Invalid token: {e}")
Settings Access
settings.fetch_jwt_public_key(force_refresh=False)
Fetch the public key from WA backend:
from crimsonforge.settings import settings
key_data = settings.fetch_jwt_public_key()
# Returns: {'public_key': '-----BEGIN...', 'algorithm': 'EdDSA', 'kid': 'uuid'}
Testing
Run the test suite:
cd crimsonforge-library
python -m pip install -e ".[dev]"
python -m pytest
Or with coverage:
python -m pytest --cov=crimsonforge --cov-report=html
Security Considerations
- Public Key Verification: Tokens are verified using Ed25519 public keys fetched from the WA backend
- No Shared Secrets: Unlike HS256, the private key never leaves the WA backend
- Key Rotation: Keys are rotated automatically; the library handles this via
kidmatching - Team ID Validation: The middleware validates that the JWT's team_id matches the configured team_id
- HTTPS Only: Always use HTTPS in production
- Token Expiration: Tokens expire after 15 minutes (enforced by JWT exp claim)
- Machine Credential Isolation: Durable client secrets are hashed at rest and exchanged only for short-lived, audience-bound access JWTs
- Team Isolation: The middleware enforces team isolation; only users from the configured team can access
About Team ID
The team_id configuration is not a secret. It simply identifies which team this backend instance serves. Think of it as a filter that ensures:
- Users from other teams cannot access your backend (even with valid JWTs)
- Each backend instance is explicitly bound to one team
Get your team ID from the CrimsonForge web app at Settings > Backend Configuration.
License
Copyright (c) 2026 Crimson Forge, LLC. Licensed under PolyForm Noncommercial 1.0.0. Use, modification, and distribution are permitted for the purposes specified by that license. Commercial use requires a separate written license. Preserve NOTICE and the license when distributing copies or modifications.
See the release guide for building packages and the manual TestPyPI/PyPI publishing workflow. Publication requires explicit release action.
Metadata
Release files for crimsonforge 2.5.7.dev1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| crimsonforge-2.5.7.dev1.tar.gz | 93.3 kB | With provenance | Details for crimsonforge-2.5.7.dev1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| crimsonforge-2.5.7.dev1-py3-none-any.whl | Python 3 | none | any | Details for crimsonforge-2.5.7.dev1-py3-none-any.whl |
Total release size: 158.8 kB
Release files / crimsonforge-2.5.7.dev1.tar.gz
| Download URL | crimsonforge-2.5.7.dev1.tar.gz |
|---|---|
| Size | 93.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2ae5ef078d4ac2f02ecb1e0ebb22357b13829af5065dd73d791df12db4819481
|
|
BLAKE2b-256 checksum How to use checksums |
8ef77544519b62dfb3b0fc4c12bf00db75169ee37b5780a016187ace04d79d62
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.
Transparency logRelease files / crimsonforge-2.5.7.dev1-py3-none-any.whl
| Download URL | crimsonforge-2.5.7.dev1-py3-none-any.whl |
|---|---|
| Size | 65.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2e2b404c7f536d6aba9d2505adab82b5672e6ce21bffe03dcb59851d1b9090d9
|
|
BLAKE2b-256 checksum How to use checksums |
facd976ca6975670719a1b71fd2a66707528c7fe5867033b17349938cd511d90
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.
Transparency logSecurity for crimsonforge 2.5.7.dev1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for crimsonforge-2.5.7.dev1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.