Engineering

How to Add License Key Validation to Your Django Application

TOT
Traffic Orchestrator Team
Engineering
April 10, 2026 6 min read 605 words
Share

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

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.

TOT
Traffic Orchestrator Team
Engineering

The engineering team behind Traffic Orchestrator, building enterprise-grade software licensing infrastructure used by developers worldwide.

Was this article helpful?
Get licensing insights delivered

Engineering deep-dives, security advisories, and product updates. Unsubscribe anytime.

Share this article
Free Plan Available

Ship licensing in your next release

5 licenses, 500 validations/month, full API access. Set up in under 5 minutes — no credit card required.

2-minute setup No credit card Cancel anytime