---
since: 1.2.1
---
# 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.
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
```mermaid
flowchart TD
CLIENT["Client
Browser / REST Client"]
AUTHX["AuthX
Identity Authority"]
REQUEST["DjangoPlay Request Boundary
Middleware / Request Context"]
WEB["Django Web Views"]
API["DRF APIs"]
POLICY["Authorization & Policy Layer
RBAC / Permissions / Visibility"]
SERVICE["Application Services
Business Logic / Validation"]
THROTTLE["Abuse Protection
Throttling / Flow Limits"]
TURNSTILE["Cloudflare Turnstile
Bot Protection"]
ABUSE["AbuseIPDB
IP Reputation
Optional integration"]
DATA["Application Data Boundary"]
POSTGRES["PostgreSQL"]
SECRETS["Secret Protection
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
```text
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 / Logging
```
## Security 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.
```text
Client
│
▼
AuthX
│
│ authenticated identity / JWT
▼
DjangoPlay
```
DjangoPlay 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.
```text
signs
DjangoPlay ───────────► AuthX
│
│ JWT
▼
DjangoPlay
│
│ verifies
▼
AuthX public key
```
AuthX 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:
```text
AuthX
└── JWT signing authority
DjangoPlay
└── JWT consumer / verifier
```
DjangoPlay'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.
```text
AuthX
│
▼
Authenticated Identity
│
▼
DjangoPlay Request Context
│
▼
Authorization Policies
```
Downstream 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.
```text
Authenticated Identity
│
▼
Authorization Policy
│
┌────┴────┐
│ │
Allow Deny
│ │
▼ ▼
Application Request
```
The 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.
```text
Authenticated User
│
▼
Identity Resolver
│
▼
Issue Visibility / RBAC Policy
│
├── Public / permitted resource
│
└── Internal / restricted resource
```
For 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.
```text
Client
│
▼
Middleware / Request Context
│
▼
URL Routing
│
├── Django Web Views
│
└── DRF APIs
```
The 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.
```text
Incoming Request
│
▼
Request Protection
│
▼
Authentication
│
▼
Authorization
│
▼
Application Validation
│
▼
Business Workflow
```
## CSRF 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.
```text
Browser
│
▼
Django CSRF Protection
│
▼
State-changing Request
```
### CORS
CORS controls which browser origins may interact with API endpoints across
origins.
```text
Browser Origin
│
▼
CORS Policy
│
┌────┴────┐
│ │
Allow Deny
```
CORS 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.
```text
Client
│
▼
Turnstile Challenge
│
▼
DjangoPlay Verification
│
├── Valid
│ │
│ ▼
│ Continue
│
└── Invalid
│
▼
Reject
```
Turnstile 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.
```text
Request
│
▼
Flow Throttling
│
├── Within limit ──────► Continue
│
└── Limit exceeded ────► Reject / throttle
```
AbuseIPDB is an optional integration.
```text
Request / IP
│
▼
Abuse Detection
│
▼
AbuseIPDB
```
An 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:
```text
Signup
Password Reset
Verification
Authentication-related Requests
```
The throttling layer can enforce limits based on configured dimensions such as
email or IP.
```text
Request
│
▼
Flow Identifier
│
▼
Throttle Policy
│
├── Allowed ──────► Execute Flow
│
└── Limited ──────► Reject / Delay
```
This provides a security control against automated abuse of high-value
application workflows.
## Application Validation
Validation is performed before business operations are executed.
```text
Request
│
▼
Serializer / Form / Input Validation
│
▼
Application Service
│
▼
Domain Operation
```
Validation is not treated as a replacement for authorization.
A valid request from an unauthorized identity must still be rejected.
```text
Valid Input
+
Authorized Identity
│
▼
Allowed Operation
```
Both 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.
```text
Web View / DRF API
│
▼
Application Service
│
┌────┼────┐
│ │ │
Auth Policy Validation
│ │ │
└────┼────┘
▼
Domain Operation
```
This 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.
```text
~/.dplay/
├── .secrets
├── .authx
├── config.yaml
└── .appdata
```
`.secrets` contains DjangoPlay secrets, credentials, passwords, API keys, and
other sensitive integration configuration.
The encryption workflow uses:
```text
~/.dplay/.secrets
│
▼
paystream/security/encrypt_env.py
│
▼
Encrypted DjangoPlay Environment
```
The 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.
```text
DjangoPlay
│
├── DB_PASSWORD
├── JWT_SIGNING_KEY
└── AUTHX_SERVICE_TOKEN
AuthX
│
├── POSTGRES_PASSWORD
├── JWT_PRIVATE_KEY
└── JWT_PUBLIC_KEY
```
These values have different owners and purposes.
In particular:
```text
DB_PASSWORD
!=
POSTGRES_PASSWORD
JWT_SIGNING_KEY
!=
JWT_PRIVATE_KEY
AUTHX_SERVICE_TOKEN
!=
database password
```
The configuration reference explicitly documents these boundaries.
## AuthX Service Authentication
DjangoPlay communicates with AuthX using a dedicated service credential.
```text
DjangoPlay
│
│ AUTHX_SERVICE_TOKEN
▼
AuthX
```
The 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.
```text
Application Service
│
▼
Data Access
│
▼
PostgreSQL
```
The 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.
```text
Authorization
│
▼
Application Service
│
▼
State Change
│
▼
Audit
```
Auditability 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.
```text
Django Request
│
▼
Application Service
│
▼
Celery Task
│
▼
Background Operation
```
Background 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.
```text
Request
│
┌──────┴──────┐
▼ ▼
Django Web DRF API
│ │
└──────┬──────┘
▼
Security / Policy
│
▼
Application Service
```
This 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.
```text
DjangoPlay Identity
│
▼
IssueTracker Identity Resolver
│
▼
Issue Visibility / RBAC Policy
│
▼
IssueTracker Services
│
▼
GenericIssueTracker
```
DjangoPlay 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.
```text
Authorization Decision
│
┌────┴────┐
│ │
Allow Unknown
│ │
▼ ▼
Execute Reject
```
An 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:
```text
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:
1. **Identity is a protected boundary.**
2. **AuthX is the identity authority for DjangoPlay authentication.**
3. **AuthX is the sole signing authority for AuthX identity JWTs.**
4. **Authentication and authorization remain separate concerns.**
5. **Authorization is enforced through explicit permissions and policies.**
6. **Application-specific RBAC does not belong inside reusable packages.**
7. **Request protection occurs before sensitive application workflows execute.**
8. **Input validation does not replace authorization.**
9. **Sensitive workflows are protected by flow-level throttling.**
10. **Bot protection and IP reputation are optional, feature-specific controls.**
11. **Secrets and service credentials are separated by ownership and purpose.**
12. **DjangoPlay and AuthX database credentials are independent.**
13. **DjangoPlay's own JWT secret is separate from AuthX's RSA signing keys.**
14. **Meaningful state changes remain attributable through audit infrastructure.**
15. **Security controls should fail closed when authorization cannot be
established.**
16. **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:
```text
Identity
│
▼
Request Protection
│
▼
Authorization
│
▼
Validation
│
▼
Business Policy
│
▼
Data Protection
│
▼
Auditability
```
Each 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.