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 (After Publication)
Version 2.5.6 is prepared for review; it has not been published yet. Once published:
python -m pip install crimsonforge==2.5.6
For Django REST Framework integrations, install crimsonforge[drf]==2.5.6.
Until publication, the built wheel can also be installed directly with pip.
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 (optional, this is the default)
# CRIMSONFORGE_SERVICE_CLIENT_ID=credential-uuid (for machine-initiated WA calls)
# 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- URL of WA backend (default:https://api.crimsonforge.io/api)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)
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.6
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.6.tar.gz | 90.0 kB | With provenance | Details for crimsonforge-2.5.6.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| crimsonforge-2.5.6-py3-none-any.whl | Python 3 | none | any | Details for crimsonforge-2.5.6-py3-none-any.whl |
Total release size: 154.2 kB
Release files / crimsonforge-2.5.6.tar.gz
| Download URL | crimsonforge-2.5.6.tar.gz |
|---|---|
| Size | 90.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cebb2f4100051df14fc9685647044d5558dfd6c1218c2211bb091afe0df1514a
|
|
BLAKE2b-256 checksum How to use checksums |
fe0963dcfde01a831ae6f94b53a361b25a8a381b5063b25bc2790179dc65df06
|
| 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 6, 2026.
Transparency logRelease files / crimsonforge-2.5.6-py3-none-any.whl
| Download URL | crimsonforge-2.5.6-py3-none-any.whl |
|---|---|
| Size | 64.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
88c7df643020cf1099bfd120120d7d96cd1f2ccc3c3b02bdfdac02b6610f87a5
|
|
BLAKE2b-256 checksum How to use checksums |
315aa66cceb7c8e7e478d02758f552a6f51d41b8ac7bf94338b122c276ef25de
|
| 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 6, 2026.
Transparency logSecurity for crimsonforge 2.5.6
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.6.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 6, 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.