Middleware

SubscriptionAccessMiddleware

Protects specific URL paths, requiring the authenticated user to have an active subscription. Staff users bypass the check.

Setup

Add to your MIDDLEWARE setting:

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    # Add after AuthenticationMiddleware
    "subscriptions.middleware.SubscriptionAccessMiddleware",
]

Configuration

SUBSCRIPTION_SETTINGS = {
    "PROTECTED_PATHS": [
        "/api/premium/",
        "/dashboard/pro/",
    ],
    "SUBSCRIPTION_REQUIRED_REDIRECT": "/pricing/",
}

How It Works

  1. On every request, checks if the path starts with any entry in PROTECTED_PATHS

  2. If protected and user is unauthenticated → returns 403/redirect

  3. If protected and user is authenticated but has no active subscription → returns 403/redirect

  4. Staff users (is_staff=True) always have access

  5. Users with active or trialing subscriptions have access

Response Behavior

Request Type

No Auth

No Subscription

API (application/json or /api/ prefix)

JSON 403: {"error": "Authentication required.", "code": "subscription_required"}

JSON 403: {"error": "Active subscription required.", "code": "subscription_required"}

HTML (browser)

Redirect to SUBSCRIPTION_REQUIRED_REDIRECT

Redirect to SUBSCRIPTION_REQUIRED_REDIRECT

API requests are detected by:

  • Content-Type: application/json

  • Path starts with /api/

  • Accept header starts with application/json

Example

SUBSCRIPTION_SETTINGS = {
    "PROTECTED_PATHS": ["/api/v2/", "/app/dashboard/"],
    "SUBSCRIPTION_REQUIRED_REDIRECT": "/subscribe/",
}
  • GET /api/v2/data/ → requires subscription (JSON 403 if missing)

  • GET /app/dashboard/ → requires subscription (redirect to /subscribe/ if missing)

  • GET /api/v1/public/ → not protected

  • GET /admin/ → not protected (and staff bypass anyway)