How to Add License Key Validation to Your Django Application
If you're building a Django-powered SaaS product, plugin marketplace, or any application that requires paid access, license key validation is essential. This guide walks you through integrating Traffic Orchestrator into a Django project — from installation to production-ready middleware.
Why License Keys in Django?
Django powers thousands of commercial applications. Whether you're distributing a self-hosted analytics dashboard, a CMS plugin, or a B2B tool, license keys let you:
- Control access to premium features
- Enforce seat limits across installations
- Track usage with real-time analytics
- Prevent unauthorized distribution with domain binding
Step 1: Install the Python SDK
Traffic Orchestrator provides a Python SDK on PyPI that works with Django, Flask, FastAPI, and any Python application.
pip install traffic-orchestrator
Step 2: Configure Your Settings
Add your Traffic Orchestrator configuration to settings.py:
# settings.py
TRAFFIC_ORCHESTRATOR = {
"base_url": "https://api.trafficorchestrator.com/api/v1",
"api_key": os.environ.get("TO_API_KEY"),
"grace_period": True,
"grace_period_ttl": 86400, # 24 hours
}
Step 3: Create a License Validation Middleware
Django middleware is the cleanest way to enforce licensing across your entire application:
# middleware/license.py
from traffic_orchestrator import Client
from django.conf import settings
from django.http import JsonResponse
class LicenseMiddleware: def __init__(self, get_response): self.get_response = get_response config = settings.TRAFFIC_ORCHESTRATOR self.client = Client( base_url=config["base_url"], api_key=config.get("api_key"), grace_period=config.get("grace_period", False), grace_period_ttl=config.get("grace_period_ttl", 86400), )
def __call__(self, request): license_key = request.META.get("HTTP_X_LICENSE_KEY") or request.GET.get("license_key")
if not license_key: return JsonResponse({"error": "License key required"}, status=401)
result = self.client.validate_license( key=license_key, domain=request.get_host() )
if not result["valid"]: return JsonResponse({"error": "Invalid license", "reason": result.get("error")}, status=403)
request.license = result return self.get_response(request) ```
Register the middleware in settings.py:
MIDDLEWARE = [
# ... existing middleware
"myapp.middleware.license.LicenseMiddleware",
]
Step 4: Use a Decorator for Granular Control
For more fine-grained control, create a decorator that validates licenses per-view:
# decorators.py
from functools import wraps
from traffic_orchestrator import Client
from django.http import JsonResponse
from django.conf import settings
client = Client(base_url=settings.TRAFFIC_ORCHESTRATOR["base_url"])
def require_license(feature=None): def decorator(view_func): @wraps(view_func) def wrapper(request, args, *kwargs): key = request.META.get("HTTP_X_LICENSE_KEY") if not key: return JsonResponse({"error": "License required"}, status=401)
result = client.validate_license(key=key, domain=request.get_host())
if not result["valid"]: return JsonResponse({"error": "Invalid license"}, status=403)
if feature and feature not in result.get("features", []): return JsonResponse({"error": f"Feature '{feature}' not included in your plan"}, status=403)
request.license = result return view_func(request, args, *kwargs) return wrapper return decorator ```
Use it in views:
# views.py
from .decorators import require_license
@require_license(feature="analytics") def analytics_dashboard(request): return render(request, "dashboard.html", {"features": request.license["features"]}) ```
Step 5: Handle Offline Verification
For self-hosted Django applications that may not always have internet access:
# offline.py
from traffic_orchestrator import Client
client = Client(base_url="https://api.trafficorchestrator.com/api/v1")
def verify_offline(license_key, cached_signature, public_key): """Verify a license using Ed25519 cryptographic signatures — no network required.""" return client.verify_offline(license_key, cached_signature, public_key) ```
Step 6: Add Webhook Handling
Create a Django view to receive real-time license events:
# views.py
import hmac, hashlib, time, json
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
@csrf_exempt def license_webhook(request): if request.method != "POST": return JsonResponse({"error": "Method not allowed"}, status=405)
signature = request.headers.get("X-TO-Signature", "") timestamp = request.headers.get("X-TO-Timestamp", "0")
Reject stale webhooks (>5 min) if time.time() - int(timestamp) > 300: return JsonResponse({"error": "Expired"}, status=401)
Verify HMAC signature body = request.body.decode("utf-8") expected = hmac.new( settings.WEBHOOK_SECRET.encode(), f"{timestamp}.{body}".encode(), hashlib.sha256 ).hexdigest()
if not hmac.compare_digest(signature, expected): return JsonResponse({"error": "Invalid signature"}, status=401)
event = json.loads(body)
if event["event"] == "license.activated": # Handle new activation pass elif event["event"] == "license.expired": # Handle expiration pass
return JsonResponse({"received": True}) ```
Next Steps
- Read the full Python SDK documentation for advanced features
- Set up domain binding for web application protection
- Configure webhook integration for real-time event handling
- Explore offline verification for air-gapped deployments
Traffic Orchestrator validates licenses at the edge in under 10ms, making it the fastest option for Django applications that need real-time license checks without impacting user experience.
Ship licensing in your next release
5 licenses, 500 validations/month, full API access. Set up in under 5 minutes — no credit card required.