--- 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.