DjangoPlay — Security Architecture
DjangoPlay treats security as a cross-cutting concern enforced across the request lifecycle, identity boundary, authorization policies, application services, data protection, and audit infrastructure.
On this page ▾
- Architecture
- Security Flow
- Security Boundaries
- Authentication
- AuthX JWT Authority
- Authentication Boundary
- Authorization
- RBAC and Policy Enforcement
- Request Boundary
- Input and Request Protection
- CSRF and CORS
- CSRF
- CORS
- Bot Protection
- Abuse Protection
- Flow Throttling
- Application Validation
- Service-Layer Security
- Secret Protection
- Credential Separation
- AuthX Service Authentication
- Data Protection
- Auditability
- Security and Background Tasks
- Security Across Web and API Interfaces
- Security and GenericIssueTracker
- Fail-Closed Authorization
- Security Configuration
- Security Responsibility Matrix
- Security Layers
- Architectural Principles
- Architectural Principle
The security architecture separates:
- Authentication and identity
- Authorization and RBAC
- Request and input protection
- Abuse prevention and throttling
- Secret and credential protection
- Data and database protection
- Auditability and security logging
Security controls are applied at the appropriate boundary rather than being implemented independently inside individual views or applications.
Architecture
flowchart TD
CLIENT["Client<br/>Browser / REST Client"]
AUTHX["AuthX<br/>Identity Authority"]
REQUEST["DjangoPlay Request Boundary<br/>Middleware / Request Context"]
WEB["Django Web Views"]
API["DRF APIs"]
POLICY["Authorization & Policy Layer<br/>RBAC / Permissions / Visibility"]
SERVICE["Application Services<br/>Business Logic / Validation"]
THROTTLE["Abuse Protection<br/>Throttling / Flow Limits"]
TURNSTILE["Cloudflare Turnstile<br/>Bot Protection"]
ABUSE["AbuseIPDB<br/>IP Reputation<br/><small>Optional integration</small>"]
DATA["Application Data Boundary"]
POSTGRES["PostgreSQL"]
SECRETS["Secret Protection<br/>Encrypted Environment / Credentials"]
AUDIT["Audit / Security Logging"]
CLIENT --> REQUEST
CLIENT --> AUTHX
AUTHX --> REQUEST
REQUEST --> WEB
REQUEST --> API
REQUEST --> THROTTLE
REQUEST --> TURNSTILE
THROTTLE --> ABUSE
WEB --> POLICY
API --> POLICY
POLICY --> SERVICE
SERVICE --> DATA
DATA --> POSTGRES
SECRETS --> REQUEST
SECRETS --> SERVICE
POLICY --> AUDIT
SERVICE --> AUDIT
DATA --> AUDIT
classDef client fill:#e6f1fb,stroke:#2474b5,stroke-width:2px,color:#174d7a
classDef identity fill:#eeeaff,stroke:#7655c7,stroke-width:2px,color:#4a3485
classDef security fill:#e5f6f1,stroke:#159a7a,stroke-width:2px,color:#075d4b
classDef policy fill:#fff2d9,stroke:#d89b18,stroke-width:2px,color:#76520b
classDef data fill:#f5f3ed,stroke:#777777,stroke-width:1px,color:#444444
classDef external fill:#eeeeff,stroke:#5a55c9,stroke-width:2px,color:#403b91
class CLIENT client
class AUTHX identity
class REQUEST,THROTTLE,TURNSTILE security
class WEB,API,POLICY,SERVICE policy
class DATA,POSTGRES,SECRETS,AUDIT data
class ABUSE external
`Security Flow
CLIENT
│
▼
DJANGOPLAY SECURITY
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
Authentication Authorization Input / Request
(AuthX) RBAC / Policies Protection
│ │ │
└────────────────────┼────────────────────┘
│
▼
┌────────────────────────┐
│ DjangoPlay Request │
│ Boundary │
└───────────┬────────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
Web Views DRF APIs Background
| Tasks
│ │ │
└──────────────┼──────────────┘
▼
┌────────────────────────┐
│ Policy Enforcement │
│ │
│ • Access Control │
│ • Validation │
│ • Throttling │
│ • CSRF / CORS │
│ • Security Headers │
└───────────┬────────────┘
│
▼
┌────────────────────────┐
│ Data Protection │
│ │
│ • Encrypted Secrets │
│ • Protected Credentials│
│ • Database Security │
└───────────┬────────────┘
│
▼
Audit / LoggingSecurity Boundaries
DjangoPlay uses several distinct security boundaries.
| Boundary | Responsibility |
|---|---|
| Identity Boundary | Establishes authenticated identity through AuthX |
| Request Boundary | Applies middleware, request context, and request-level protection |
| Authorization Boundary | Applies permissions, RBAC, and resource visibility policies |
| Application Boundary | Validates and executes business workflows through services |
| Data Boundary | Controls access to persistent application data |
| Secret Boundary | Protects encryption keys, passwords, API credentials, and service credentials |
| Audit Boundary | Records meaningful security and application state changes |
These boundaries are complementary rather than interchangeable.
Authentication establishes who the caller is.
Authorization determines what that identity may do.
Validation and request protection determine whether the request is acceptable to process.
Authentication
AuthX is the external identity authority for DjangoPlay.
Client
│
▼
AuthX
│
│ authenticated identity / JWT
▼
DjangoPlayDjangoPlay does not treat authentication and authorization as the same concern.
The authentication boundary establishes the identity context that downstream authorization policies consume.
AuthX JWT Authority
AuthX is the sole JWT signing authority for AuthX identity JWTs.
signs
DjangoPlay ───────────► AuthX
│
│ JWT
▼
DjangoPlay
│
│ verifies
▼
AuthX public keyAuthX owns the RSA private signing key.
DjangoPlay uses the corresponding public verification material rather than possessing AuthX's private signing key.
This creates a clear trust boundary:
AuthX
└── JWT signing authority
DjangoPlay
└── JWT consumer / verifierDjangoPlay's own JWT_SIGNING_KEY is a separate credential and must not be
confused with AuthX's RSA signing keys.
Authentication Boundary
The authentication context flows into the DjangoPlay request pipeline.
AuthX
│
▼
Authenticated Identity
│
▼
DjangoPlay Request Context
│
▼
Authorization PoliciesDownstream application code should consume the established identity context rather than implementing independent authentication mechanisms.
Authorization
Authentication alone does not grant access to application resources.
DjangoPlay applies authorization through permissions, roles, and resource-specific policies.
Authenticated Identity
│
▼
Authorization Policy
│
┌────┴────┐
│ │
Allow Deny
│ │
▼ ▼
Application RequestThe authorization layer is responsible for decisions such as:
- Whether the caller has the required permission
- Whether a resource is visible to the caller
- Whether an operation is allowed for the caller's role
- Whether an internal resource should remain restricted
RBAC and Policy Enforcement
DjangoPlay uses role-aware policies rather than assuming that authentication implies unrestricted access.
The IssueTracker integration is an example of this boundary.
Authenticated User
│
▼
Identity Resolver
│
▼
Issue Visibility / RBAC Policy
│
├── Public / permitted resource
│
└── Internal / restricted resourceFor GenericIssueTracker, DjangoPlay owns application-specific visibility and RBAC policy while the reusable package remains independent of DjangoPlay's role model.
This follows the broader platform principle that application-specific policy belongs in DjangoPlay rather than being embedded into reusable infrastructure.
Request Boundary
All incoming application requests pass through the Django request boundary before reaching application behavior.
Client
│
▼
Middleware / Request Context
│
▼
URL Routing
│
├── Django Web Views
│
└── DRF APIsThe request boundary is responsible for establishing the context in which authentication, authorization, validation, and application services operate.
The application architecture explicitly places authentication, security, permissions, and request context in this boundary.
Input and Request Protection
Request protection is applied before untrusted input reaches sensitive application workflows.
The security boundary includes:
- Request validation
- Authentication checks
- Authorization checks
- CSRF protection for applicable browser flows
- CORS policy for browser/API interaction
- Security headers
- Request throttling
- Bot protection where enabled
These controls complement application-level validation.
Incoming Request
│
▼
Request Protection
│
▼
Authentication
│
▼
Authorization
│
▼
Application Validation
│
▼
Business WorkflowCSRF and CORS
DjangoPlay distinguishes browser request protection from cross-origin API policy.
CSRF
CSRF protection applies to browser-based state-changing request flows where Django's CSRF mechanism is applicable.
Browser
│
▼
Django CSRF Protection
│
▼
State-changing RequestCORS
CORS controls which browser origins may interact with API endpoints across origins.
Browser Origin
│
▼
CORS Policy
│
┌────┴────┐
│ │
Allow DenyCORS configuration is environment-specific. The development configuration uses local origins while production uses the actual production browser origins.
Bot Protection
DjangoPlay supports Cloudflare Turnstile as an optional request-protection integration.
Client
│
▼
Turnstile Challenge
│
▼
DjangoPlay Verification
│
├── Valid
│ │
│ ▼
│ Continue
│
└── Invalid
│
▼
RejectTurnstile credentials are environment-specific and are only required when Turnstile protection is enabled.
The supported configuration includes development, staging, and production Turnstile key pairs.
Abuse Protection
DjangoPlay supports application-level flow throttling and optional IP reputation checks.
Request
│
▼
Flow Throttling
│
├── Within limit ──────► Continue
│
└── Limit exceeded ────► Reject / throttleAbuseIPDB is an optional integration.
Request / IP
│
▼
Abuse Detection
│
▼
AbuseIPDBAn AbuseIPDB API key is not required for a normal installation. It is only required when AbuseIPDB-backed abuse/IP reputation functionality is enabled.
Flow Throttling
DjangoPlay uses flow-oriented throttling for sensitive application workflows.
The purpose is to limit repeated requests rather than relying exclusively on global API rate limiting.
Examples include flows such as:
Signup
Password Reset
Verification
Authentication-related RequestsThe throttling layer can enforce limits based on configured dimensions such as email or IP.
Request
│
▼
Flow Identifier
│
▼
Throttle Policy
│
├── Allowed ──────► Execute Flow
│
└── Limited ──────► Reject / DelayThis provides a security control against automated abuse of high-value application workflows.
Application Validation
Validation is performed before business operations are executed.
Request
│
▼
Serializer / Form / Input Validation
│
▼
Application Service
│
▼
Domain OperationValidation is not treated as a replacement for authorization.
A valid request from an unauthorized identity must still be rejected.
Valid Input
+
Authorized Identity
│
▼
Allowed OperationBoth conditions are required.
Service-Layer Security
DjangoPlay follows a service-first architecture.
Views and DRF endpoints should delegate meaningful application behavior to services rather than implementing complete workflows themselves.
Web View / DRF API
│
▼
Application Service
│
┌────┼────┐
│ │ │
Auth Policy Validation
│ │ │
└────┼────┘
▼
Domain OperationThis provides a consistent location for enforcing business-level policy, validation, and integration orchestration.
Secret Protection
Sensitive DjangoPlay configuration is separated from non-secret structured configuration.
~/.dplay/
├── .secrets
├── .authx
├── config.yaml
└── .appdata.secrets contains DjangoPlay secrets, credentials, passwords, API keys, and
other sensitive integration configuration.
The encryption workflow uses:
~/.dplay/.secrets
│
▼
paystream/security/encrypt_env.py
│
▼
Encrypted DjangoPlay EnvironmentThe configuration reference explicitly identifies ENCRYPTION_KEY as the
master key used by DjangoPlay's environment encryption workflow.
Credential Separation
DjangoPlay deliberately separates credentials belonging to different security domains.
DjangoPlay
│
├── DB_PASSWORD
├── JWT_SIGNING_KEY
└── AUTHX_SERVICE_TOKEN
AuthX
│
├── POSTGRES_PASSWORD
├── JWT_PRIVATE_KEY
└── JWT_PUBLIC_KEYThese values have different owners and purposes.
In particular:
DB_PASSWORD
!=
POSTGRES_PASSWORD
JWT_SIGNING_KEY
!=
JWT_PRIVATE_KEY
AUTHX_SERVICE_TOKEN
!=
database passwordThe configuration reference explicitly documents these boundaries.
AuthX Service Authentication
DjangoPlay communicates with AuthX using a dedicated service credential.
DjangoPlay
│
│ AUTHX_SERVICE_TOKEN
▼
AuthXThe service credential is distinct from:
- DjangoPlay's database password
- AuthX's database password
- AuthX's JWT private key
- DjangoPlay's own JWT signing secret
This prevents one credential from implicitly becoming a credential for another security domain.
Data Protection
Persistent application data is protected behind the application data boundary.
Application Service
│
▼
Data Access
│
▼
PostgreSQLThe application should not expose raw persistence operations directly to untrusted request handlers.
Application services and policies determine which domain operations are permitted before persistent state is changed.
Auditability
Security-relevant and meaningful application state changes are observable through DjangoPlay's audit infrastructure.
Authorization
│
▼
Application Service
│
▼
State Change
│
▼
AuditAuditability provides attribution and traceability for meaningful state changes.
The platform's design principle is Auditability by Default: meaningful state changes should be observable and attributable.
Security and Background Tasks
Celery tasks execute outside the HTTP request lifecycle, but they remain part of the trusted application runtime.
Django Request
│
▼
Application Service
│
▼
Celery Task
│
▼
Background OperationBackground tasks must not be treated as implicitly authorized merely because they execute outside an HTTP request.
Task-level workflows should operate using trusted application context and explicitly defined service boundaries.
Security Across Web and API Interfaces
DjangoPlay exposes both server-rendered Django views and DRF APIs.
Both interfaces ultimately converge on application services and security policies.
Request
│
┌──────┴──────┐
▼ ▼
Django Web DRF API
│ │
└──────┬──────┘
▼
Security / Policy
│
▼
Application ServiceThis prevents the API and web interfaces from developing completely separate authorization rules for the same application operation.
Security and GenericIssueTracker
GenericIssueTracker is integrated through DjangoPlay's dedicated integration layer.
Security responsibilities are split between the reusable package and DjangoPlay.
DjangoPlay Identity
│
▼
IssueTracker Identity Resolver
│
▼
Issue Visibility / RBAC Policy
│
▼
IssueTracker Services
│
▼
GenericIssueTrackerDjangoPlay owns:
- Identity adaptation
- Application-specific RBAC
- Visibility rules
- Integration services
- UI/API access policy
GenericIssueTracker owns its reusable issue domain.
This prevents DjangoPlay-specific authorization assumptions from leaking into the reusable package.
Fail-Closed Authorization
DjangoPlay follows a fail-closed security principle.
Authorization Decision
│
┌────┴────┐
│ │
Allow Unknown
│ │
▼ ▼
Execute RejectAn operation should not become permitted merely because a permission check is missing, ambiguous, or unable to establish the required authorization context.
This principle is particularly important for internal resources and administrative operations.
Security Configuration
Security-sensitive configuration is environment-aware.
Typical differences include:
| Security Area | Development | Production |
|---|---|---|
| Django settings | paystream.settings.dev |
paystream.settings.prod |
| JWT keys | Development key pair | Fresh production key pair |
| Service credentials | Development values | Unique production values |
| CORS | Local development origins | Production browser origins |
| Google OAuth | Only when tested/enabled | Only when enabled |
| Turnstile | Only when enabled | Only when enabled |
| AbuseIPDB | Only when used | Only when used |
| R2 | Only when used | When CDN/R2 publishing is used |
| AI credentials | Selected development provider | Selected production provider |
Development credentials and private keys must not be reused in production.
Security Responsibility Matrix
| Security Area | Primary Responsibility |
|---|---|
| Identity | AuthX |
| JWT signing for AuthX identity tokens | AuthX |
| JWT verification in DjangoPlay | DjangoPlay |
| Application authentication context | DjangoPlay |
| RBAC | DjangoPlay |
| Resource visibility | DjangoPlay |
| Request context | Django middleware / application boundary |
| Input validation | Django forms / DRF serializers / application services |
| CSRF | Django/browser request protection |
| CORS | DjangoPlay API configuration |
| Flow throttling | DjangoPlay application/security services |
| Bot protection | Cloudflare Turnstile integration |
| IP reputation | Optional AbuseIPDB integration |
| Secret encryption | DjangoPlay encryption workflow |
| Persistent application data | PostgreSQL |
| Auditability | DjangoPlay audit infrastructure |
Security Layers
The complete security model can be summarized as layered controls:
CLIENT
│
▼
┌─────────────────┐
│ Request Boundary │
└────────┬────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
Authentication Request Abuse
/ AuthX Protection Protection
│ │ │
└────────────┼────────────┘
▼
┌─────────────────┐
│ Authorization │
│ RBAC / Policies │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Validation │
│ / Services │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Data Boundary │
│ PostgreSQL │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Audit / Logging │
└─────────────────┘Architectural Principles
The security architecture follows these principles:
- Identity is a protected boundary.
- AuthX is the identity authority for DjangoPlay authentication.
- AuthX is the sole signing authority for AuthX identity JWTs.
- Authentication and authorization remain separate concerns.
- Authorization is enforced through explicit permissions and policies.
- Application-specific RBAC does not belong inside reusable packages.
- Request protection occurs before sensitive application workflows execute.
- Input validation does not replace authorization.
- Sensitive workflows are protected by flow-level throttling.
- Bot protection and IP reputation are optional, feature-specific controls.
- Secrets and service credentials are separated by ownership and purpose.
- DjangoPlay and AuthX database credentials are independent.
- DjangoPlay's own JWT secret is separate from AuthX's RSA signing keys.
- Meaningful state changes remain attributable through audit infrastructure.
- Security controls should fail closed when authorization cannot be established.
- Development and production security credentials must remain separate.
Architectural Principle
DjangoPlay does not depend on a single security mechanism.
Security is implemented as a chain of independent controls:
Identity
│
▼
Request Protection
│
▼
Authorization
│
▼
Validation
│
▼
Business Policy
│
▼
Data Protection
│
▼
AuditabilityEach layer has a specific responsibility.
A valid identity does not automatically grant access.
Valid input does not automatically authorize an operation.
An authenticated request still passes through application policy.
A successful operation remains observable through the audit boundary.
This layered model allows DjangoPlay to maintain a consistent security posture across its web UI, DRF APIs, background processing, reusable integrations, and external service boundaries.