Skip to Content

CORS Configuration

Django-CFG provides automatic CORS handling for public API endpoints via middleware, plus decorators for custom configurations.

Architecture

Request → PublicAPICORSMiddleware → CorsMiddleware → View ↓ ↓ /cfg/leads/* Other paths (open CORS) (security_domains)

Key components:

  • PublicAPICORSMiddleware - Handles CORS for public API paths (e.g., /cfg/leads/)
  • CorsMiddleware (django-cors-headers) - Handles CORS for other paths based on security_domains
  • PublicAPIMixin - Removes authentication for public endpoints
  • Decorators - For custom CORS on function-based views

Quick Start

Public endpoints like lead submission work automatically:

from django_cfg.mixins import PublicAPIMixin from rest_framework import viewsets class LeadViewSet(PublicAPIMixin, viewsets.ModelViewSet): """Public API - no auth required, CORS handled by middleware.""" queryset = Lead.objects.all() serializer_class = LeadSerializer

CORS is handled automatically by PublicAPICORSMiddleware for paths matching PUBLIC_API_CORS_PATHS.

Function-Based Views

from django_cfg.core.decorators import cors_allow_all from django.http import JsonResponse @cors_allow_all def webhook_handler(request): return JsonResponse({'received': True})

Middleware Configuration

PUBLIC_API_CORS_PATHS

Configure which paths have open CORS in settings.py:

# Default: ['/cfg/leads/'] PUBLIC_API_CORS_PATHS = [ '/cfg/leads/', # Lead submission API '/api/webhooks/', # Webhook handlers '/api/public/', # Other public endpoints ]

PUBLIC_API_CORS_REGEX

For complex path matching:

PUBLIC_API_CORS_REGEX = r'^/(cfg/leads|api/webhooks|api/public)/'

CORS Headers Added

For matching paths, middleware adds:

Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With, Accept, Origin Access-Control-Max-Age: 86400

PublicAPIMixin

Mixin for public API endpoints without authentication.

from django_cfg.mixins import PublicAPIMixin from rest_framework import viewsets from rest_framework.decorators import action from rest_framework.response import Response class ContactFormViewSet(PublicAPIMixin, viewsets.GenericViewSet): """ Public contact form API. - No authentication required (AllowAny) - CORS handled by PublicAPICORSMiddleware """ @action(detail=False, methods=['post']) def submit(self, request): serializer = ContactSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response({'success': True}, status=201) return Response({'errors': serializer.errors}, status=400)

What PublicAPIMixin provides:

  • permission_classes = [AllowAny]
  • authentication_classes = []

What it does NOT provide:

  • CORS headers (handled by middleware)

Decorators Reference

@cors_allow_all

Decorator for open CORS on function-based views.

from django_cfg.core.decorators import cors_allow_all from rest_framework.decorators import api_view from rest_framework.response import Response @cors_allow_all @api_view(['POST']) def submit_lead(request): """Lead submission endpoint with open CORS.""" return Response({'success': True})

Features:

  • Adds CORS headers to response
  • Handles OPTIONS preflight automatically
  • Disables CSRF protection

@cors_origins

Decorator for restricted CORS origins.

from django_cfg.core.decorators import cors_origins @cors_origins([ "https://myapp.com", "https://admin.myapp.com", ]) def restricted_api(request): """Only accessible from whitelisted origins.""" return JsonResponse({'data': 'restricted'})

With credentials:

@cors_origins( allowed_origins=["https://myapp.com"], credentials=True, ) def authenticated_api(request): return JsonResponse({'user': request.user.username})

Parameters:

ParameterTypeDefaultDescription
allowed_originsList[str]requiredAllowed origin URLs
methodsstr"GET, POST, ..."Allowed HTTP methods
headersstr"Content-Type, ..."Allowed headers
max_ageint86400Preflight cache (seconds)
credentialsboolTrueAllow credentials

@cors_exempt

Alias for @cors_allow_all:

from django_cfg.core.decorators import cors_exempt @cors_exempt def webhook_handler(request): return JsonResponse({'received': True})

Usage Patterns

Lead Submission (Built-in)

Django-CFG’s lead system works out of the box:

# Already configured in django_cfg.apps.business.leads class LeadViewSet(PublicAPIMixin, viewsets.ModelViewSet): queryset = Lead.objects.all() serializer_class = LeadSubmissionSerializer @action(detail=False, methods=['post']) def submit(self, request): # ... submission logic

Frontend usage:

await fetch('https://api.example.com/cfg/leads/submit/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'John Doe', email: '[email protected]', message: 'Hello!' }) });

Webhook Handler

from django_cfg.core.decorators import cors_allow_all from django.http import JsonResponse import json @cors_allow_all def stripe_webhook(request): payload = json.loads(request.body) # Process webhook... return JsonResponse({'status': 'ok'})

Mixed Authentication

from django_cfg.mixins import AdminAPIMixin from rest_framework import viewsets from rest_framework.permissions import AllowAny class ProductViewSet(AdminAPIMixin, viewsets.ModelViewSet): """ - List/Retrieve: Public - Create/Update/Delete: Admin only """ queryset = Product.objects.all() def get_permissions(self): if self.action in ['list', 'retrieve']: return [AllowAny()] return super().get_permissions()

Frontend Integration

ContactPage Component

import { ContactPage } from '@djangocfg/layouts'; function Contact() { return <ContactPage />; // Uses default API URL }

Custom API URL

import { ContactPage } from '@djangocfg/layouts'; function Contact() { return ( <ContactPage apiUrl="https://api.myapp.com/cfg/leads/submit/" /> ); }

Security Best Practices

1. Use middleware for public endpoints

# settings.py PUBLIC_API_CORS_PATHS = ['/cfg/leads/'] # Only truly public paths

2. Never expose sensitive data without auth

# WRONG class UserViewSet(PublicAPIMixin, viewsets.ModelViewSet): queryset = User.objects.all() # Exposes all users! # CORRECT class UserViewSet(AdminAPIMixin, viewsets.ModelViewSet): queryset = User.objects.all()

3. Use security_domains for authenticated APIs

# config.py config = DjangoConfig( security_domains=[ "myapp.com", "admin.myapp.com", ], # ... )

Middleware Order

PublicAPICORSMiddleware must be before CorsMiddleware:

MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', 'django_cfg.core.middleware.PublicAPICORSMiddleware', # Before CorsMiddleware 'corsheaders.middleware.CorsMiddleware', # ... ]

This is configured automatically by Django-CFG.

TAGS: cors, api, middleware, public-api, security DEPENDS_ON: [rest-framework, django-views] USED_BY: [leads, contact-forms, webhooks]