Orchestrata Ultimate / Specs / 099-security-auth-framework
099-security-auth-framework: Security & Auth Framework
This specification defines the security and authentication framework for orchestrata-ultimate. It provides centralized authentication, encryption, session management, and integrates with PAM++ governance for authorization.
At a glance
| Item | Value |
|---|---|
| Spec directory | specs/099-security-auth-framework/ |
| Status line in the spec | Complete |
| Requirement IDs defined | 171 |
With a @traces citation in src/ |
0 (0.0%) |
With a @traces citation in tests/ |
0 (0.0%) |
| Tracked files | 2 |
| RTM page | 099-security-auth-framework |
Reading this spec
This spec defines the security and authentication framework for orchestrata-ultimate. It provides centralized authentication, encryption and session management, and it hands authorization decisions to PAM++ governance. It is the reference for how users and programs prove who they are, how access is limited, and how security events are recorded and answered.
Four user stories set the scope: a CLI user authenticating with an API key (generated with the permissions needed, sent in the Authorization header, expiring after a configurable time, revocable at any time), an administrator enabling multi-factor authentication, a user managing sessions, and security incident response. Data models describe the user, API key, session and MFA setup. The functional requirement groups are authentication, authorization, session management, token security, rate limiting, audit logging, account security and MFA security. Further sections cover thirty named error conditions (ERR-001 to ERR-030), token revocation with a blacklist and revocation API, and MFA with time-based one-time passwords.
The 171 requirement IDs (REQ-099-NNN) state the design decisions. Authentication supports API keys, OAuth and sessions as interchangeable strategies, and encryption uses AES-256-GCM. Authorization enforces role-based access control across all resources, with permissions cached in Redis for 3600 seconds and invalidated on role change. Sessions live in a Redis cluster with TTL-based expiry and distributed invalidation, and all sessions can be invalidated during a security incident. Accounts are blocked after 5 failed login attempts and common passwords are rejected. Secrets management supports HashiCorp Vault and AWS Secrets Manager, with environment variables as a backend for development only. Audit logs are tamper-resistant with hash-chain verification. The PAM++ client has a 5.0 second timeout, and security incidents are classified with response times, for example 1 hour for critical ones. The spec also defines the refresh and session-deletion endpoints.
This is a framework spec, and no code module cites it. The requirements traceability matrix lists every ID. The spec's own status line reads Complete and it tracks 2 files. No src/ symbol cites any of the 171 requirements, so measured trace coverage is 0.0%, and in tests/, 0 requirements are cited by a test-side @traces. All 171 requirements have no citing symbol; untraced means no @traces names the ID, and the behaviour may still exist in code that was never annotated.
Requirements
Checkbox is the state recorded in the requirements checklist; Traced by is the count of src/ symbols whose @traces names the ID.
| ID | Done | Requirement | Traced by |
|---|---|---|---|
REQ-099-001 |
- | The system SHALL allow a CLI user to authenticate with an API key. The key SHALL be generated with the permissions required for its use, SHALL be presented in the Authorization header, SHALL expire after a configurable time, and SHALL be revocable at any time. |
none |
REQ-099-002 |
- | The system SHALL allow a security admin to enable multi-factor authentication. MFA SHALL support TOTP and SMS backup, SHALL generate backup codes, and SHALL be enforceable for all users or for specific roles. | none |
REQ-099-003 |
- | Login SHALL create a session carrying a JWT, the session SHALL expire after 24 hours, the refresh token SHALL be valid for 7 days, and logout SHALL invalidate the session. | none |
REQ-099-004 |
- | A security officer SHALL be able to revoke all active sessions and invalidate all API keys, SHALL be able to block a user account, and every revocation action SHALL be written to the audit log. | none |
REQ-099-005 |
- | The system SHALL represent a User conforming to the schema above: id, email, name and role SHALL be required; id SHALL match ^user_[a-zA-Z0-9]+$; role SHALL be one of admin, auditor, project_admin, developer, viewer or guest; and the record SHALL carry projects, created_at, last_login, mfa_enabled, mfa_secret (base32 TOTP secret), password_hash (bcrypt), account_locked and failed_login_attempts. |
none |
REQ-099-006 |
- | The system SHALL represent an API Key conforming to the schema above: id, user_id, name, prefix and permissions SHALL be required; id SHALL match ^key_[a-zA-Z0-9]+$; prefix SHALL match ^sk_[a-zA-Z0-9]{8}$; each permission SHALL be one of read, write, admin or audit; and the record SHALL carry created_at, expires_at, last_used, revoked and revoked_at. |
none |
REQ-099-007 |
- | The system SHALL represent a Session conforming to the schema above: id, user_id, refresh_token and expires_at SHALL be required; id SHALL match ^sess_[a-zA-Z0-9]+$; the access token SHALL be a JWT that expires in 1 hour; and the record SHALL carry ip_address, user_agent, created_at, revoked and revoked_at. |
none |
REQ-099-008 |
- | The system SHALL represent an MFA setup conforming to the schema above: secret (base32 TOTP secret) and backup_codes SHALL be required; qr_code SHALL be a base64-encoded QR image; each backup code SHALL match ^[0-9]{8}$; and method SHALL be one of totp, sms or u2f. |
none |
REQ-099-009 |
- | The system MUST support API key authentication for CLI and programmatic access. | none |
REQ-099-010 |
- | The system MUST support OAuth 2.0 authentication for web UI access. | none |
REQ-099-011 |
- | The system MUST support session-based authentication with JWT tokens. | none |
REQ-099-012 |
- | The system MUST support MFA using TOTP (Time-based One-Time Password). | none |
REQ-099-013 |
- | The system MUST support MFA using SMS backup codes. | none |
REQ-099-014 |
- | The system MUST validate all authentication tokens before allowing access. | none |
REQ-099-015 |
- | The system MUST expire authentication tokens after configurable duration. | none |
REQ-099-016 |
- | The system MUST query PAM++ for all authorization decisions. | none |
REQ-099-017 |
- | The system MUST enforce RBAC (Role-Based Access Control) across all resources. | none |
REQ-099-018 |
- | The system MUST support permission levels: global, project, resource, and action. | none |
REQ-099-019 |
- | The system MUST deny access by default when no explicit allow policy exists. | none |
REQ-099-020 |
- | The system MUST provide fine-grained permission control at the resource level. | none |
REQ-099-021 |
- | The system MUST create sessions upon successful authentication. | none |
REQ-099-022 |
- | The system MUST invalidate sessions on logout. | none |
REQ-099-023 |
- | The system MUST enforce session expiry (24 hours default). | none |
REQ-099-024 |
- | The system MUST support refresh tokens valid for 7 days. | none |
REQ-099-025 |
- | The system MUST invalidate all sessions during security incidents. | none |
REQ-099-026 |
- | The system MUST hash API keys with bcrypt before storage. | none |
REQ-099-027 |
- | The system MUST support token revocation with immediate effect. | none |
REQ-099-028 |
- | The system MUST maintain token blacklist in Redis. | none |
REQ-099-029 |
- | The system MUST encrypt sensitive data fields with AES-256-GCM. | none |
REQ-099-030 |
- | The system MUST support automatic key rotation (monthly for DEKs). | none |
REQ-099-031 |
- | The system MUST enforce per-user rate limits. | none |
REQ-099-032 |
- | The system MUST implement stricter limits on authentication endpoints. | none |
REQ-099-033 |
- | The system MUST block accounts after 5 failed login attempts. | none |
REQ-099-034 |
- | The system MUST implement progressive login delays. | none |
REQ-099-035 |
- | The system MUST log all authentication events. | none |
REQ-099-036 |
- | The system MUST log all authorization decisions. | none |
REQ-099-037 |
- | The system MUST implement tamper-resistant audit logs using hash chains. | none |
REQ-099-038 |
- | The system MUST maintain audit logs for 7 years. | none |
REQ-099-039 |
- | The system MUST provide audit log verification capabilities. | none |
REQ-099-040 |
- | The system MUST enforce password policies (12+ chars, complexity). | none |
REQ-099-041 |
- | The system MUST detect common passwords and reject them. | none |
REQ-099-042 |
- | The system MUST lock accounts after threshold failed attempts. | none |
REQ-099-043 |
- | The system MUST support emergency token revocation. | none |
REQ-099-044 |
- | The system MUST encrypt password hashes in storage. | none |
REQ-099-045 |
- | The system MUST generate unique TOTP secrets for each user. | none |
REQ-099-046 |
- | The system MUST generate backup codes for MFA recovery. | none |
REQ-099-047 |
- | The system MUST prevent backup code reuse. | none |
REQ-099-048 |
- | The system MUST require MFA verification after sensitive operations. | none |
REQ-099-049 |
- | The system SHALL detect each of the conditions ERR-001 through ERR-030 listed above and SHALL respond with the HTTP status, error code and handling given for that condition. | none |
REQ-099-050 |
- | Revoked tokens SHALL be stored in Redis under the key revoked:{token_hash}, where token_hash is the SHA-256 of the full token, with a TTL equal to the original token expiry; the stored record SHALL carry the revocation reason, the revoking user and the revocation timestamp. |
none |
REQ-099-051 |
- | Invalidating all sessions for a user SHALL delete every session held in that user's session set and SHALL remove each session id from the set. | none |
REQ-099-052 |
- | TOTP setup SHALL generate a random base32 secret, SHALL return a provisioning QR code issued under the name Orchestrata Ultimate, and SHALL store the secret encrypted; TOTP verification SHALL check the submitted code against the stored secret. |
none |
REQ-099-053 |
- | The system SHALL generate 10 backup codes, each of 8 numeric digits, and SHALL accept any given backup code only once. | none |
REQ-099-054 |
- | After 5 failed login attempts the account SHALL be locked for 1800 seconds (30 minutes) and an ACCOUNT_LOCKED security event SHALL be logged. |
none |
REQ-099-055 |
- | Authorization decisions SHALL be requested from PAM++ as can_perform(user, action, resource, context) with the request IP, timestamp and method carried in the context, and the PAM++ response SHALL supply the decision, its reason and the matched policy. |
none |
REQ-099-056 |
- | The system SHALL expose POST /api/v1/auth/login, accepting { email, password } and returning { access_token, refresh_token, expires_in }, and SHALL report ERR-001, ERR-006, ERR-017, ERR-018 and ERR-025 on failure. |
none |
REQ-099-057 |
- | The system SHALL expose POST /api/v1/auth/refresh, accepting { refresh_token } and returning { access_token, expires_in }, and SHALL report ERR-004 and ERR-030 on failure. |
none |
REQ-099-058 |
- | The system SHALL expose POST /api/v1/auth/logout, accepting { token } and returning { success: true }, and SHALL report ERR-005 on failure. |
none |
REQ-099-059 |
- | The system SHALL expose POST /api/v1/auth/api-keys, accepting { name, permissions, expires_in } and returning { id, key, prefix }, and SHALL report ERR-009 on failure. |
none |
REQ-099-060 |
- | The system SHALL expose POST /api/v1/auth/mfa/setup, accepting { method } of totp or sms and returning { secret, qr_code, backup_codes }, and SHALL report ERR-025 on failure. |
none |
REQ-099-061 |
- | The system SHALL expose POST /api/v1/auth/mfa/verify, accepting { code } and returning { verified }, and SHALL report ERR-014, ERR-015 and ERR-016 on failure. |
none |
REQ-099-062 |
- | The system SHALL expose POST /api/v1/auth/mfa/disable, accepting { password } and returning { success }, and SHALL report ERR-001 and ERR-017 on failure. |
none |
REQ-099-063 |
- | The system SHALL expose GET /api/v1/sessions, returning the caller's sessions, and SHALL report ERR-008 and ERR-009 on failure. |
none |
REQ-099-064 |
- | The system SHALL expose DELETE /api/v1/sessions/{session_id}, returning { success }, and SHALL report ERR-008 and ERR-010 on failure. |
none |
REQ-099-065 |
- | The system SHALL expose DELETE /api/v1/sessions, which deletes every session of the caller and returns { success }, and SHALL report ERR-008 and ERR-009 on failure. |
none |
REQ-099-066 |
- | The system SHALL expose POST /api/v1/auth/authorize, accepting { action, resource, context } and returning { allowed, reason, policy }, and SHALL report ERR-008, ERR-009, ERR-019 and ERR-020 on failure. |
none |
REQ-099-201 |
- | Authentication latency MUST be under 50ms for token validation | none |
REQ-099-202 |
- | Authorization queries MUST complete within 100ms (PAM++ timeout: 5s) | none |
REQ-099-203 |
- | Session creation MUST complete within 200ms | none |
REQ-099-204 |
- | Token refresh MUST complete within 100ms | none |
REQ-099-205 |
- | System MUST support 10,000 concurrent authenticated sessions | none |
REQ-099-206 |
- | Authentication service MUST scale horizontally with load balancer | none |
REQ-099-207 |
- | Session store MUST support Redis cluster for high availability | none |
REQ-099-208 |
- | Token blacklist operations MUST complete within 10ms | none |
REQ-099-209 |
- | Rate limiting MUST support distributed counters | none |
REQ-099-210 |
- | Authentication service MUST achieve 99.9% uptime (SLA) | none |
REQ-099-211 |
- | Maximum downtime for deployments MUST NOT exceed 5 minutes | none |
REQ-099-212 |
- | Rate limiting MUST NOT cause false positives during traffic spikes | none |
REQ-099-213 |
- | PAM++ unavailability MUST trigger fail-secure mode | none |
REQ-099-214 |
- | All passwords MUST be hashed with bcrypt (cost factor 12+) | none |
REQ-099-215 |
- | All API keys MUST be hashed with bcrypt before storage | none |
REQ-099-216 |
- | Encryption at rest MUST use AES-256-GCM | none |
REQ-099-217 |
- | TLS 1.3 REQUIRED for all connections | none |
REQ-099-218 |
- | MFA MUST be available for all user roles | none |
REQ-099-219 |
- | Audit logs MUST be tamper-resistant (hash chain) | none |
REQ-099-067 |
- | The Authentication Service SHALL be a stateless REST API that handles API-key, OAuth 2.0 and session-token authentication, manages the JWT access and refresh token lifecycle, integrates with the TOTP and SMS MFA providers, and enforces rate limiting and account-lockout policies. | none |
REQ-099-068 |
- | The Authorization Engine SHALL delegate every authorization decision to PAM++, SHALL cache policy decisions to reduce PAM++ queries, SHALL support RBAC with permission inheritance, and SHALL take request time, IP and user agent into account. | none |
REQ-099-069 |
- | Token Management SHALL issue JWT access tokens valid for 1 hour and refresh tokens valid for 7 days, SHALL maintain a token blacklist for immediate revocation, and SHALL use Redis for distributed token validation. | none |
REQ-099-070 |
- | The Session Store SHALL run on a Redis cluster for high availability, SHALL store active sessions with TTL-based expiry, SHALL support distributed session invalidation, and SHALL encrypt sensitive session data at rest. | none |
REQ-099-071 |
- | Secrets Management SHALL integrate with HashiCorp Vault or AWS Secrets Manager, SHALL rotate data encryption keys automatically every month, SHALL support an HSM for master keys, and SHALL log every key access centrally. | none |
REQ-099-072 |
- | Audit Logging SHALL store entries with hash chains for tamper resistance, SHALL keep 90 days of hot storage in Elasticsearch and 7 years of cold storage in S3 Glacier, and SHALL stream events to SIEM systems in real time. | none |
REQ-099-073 |
- | Every request SHALL pass through the auth middleware, which SHALL validate the token and obtain a PAM++ authorization decision before the handler runs, and SHALL attach the user context to the request when the token is valid. | none |
REQ-099-074 |
- | Login SHALL create a 24-hour session, issue a 1-hour access token and a 7-day refresh token; presenting a refresh token SHALL validate it, issue new tokens and invalidate the old refresh token. | none |
REQ-099-075 |
- | An authorization request SHALL extract the user and the required permission, query PAM++, cache the decision and enforce it; a cached decision SHALL be returned without re-querying PAM++. | none |
REQ-099-076 |
- | The system SHALL implement middleware that validates tokens before request handling, enforces PAM++ authorization policies, enforces per-user rate quotas, and logs all security events for audit. | none |
REQ-099-077 |
- | The system SHALL implement a UserRepository for user database operations, a TokenRepository for token validation and storage, a SessionRepository for session lifecycle management, and an AuditRepository for audit-log writing and retrieval. |
none |
REQ-099-078 |
- | The system SHALL implement interchangeable strategies for authentication (API key, OAuth, session), encryption (AES-256-GCM across backends), secrets management (Vault, AWS, environment) and MFA (TOTP, SMS, U2F). | none |
REQ-099-079 |
- | The system SHALL implement observers for security-event audit logging, token-revocation blacklist updates, failed-login account lockout, and policy-change cache invalidation. | none |
REQ-099-080 |
- | The users table SHALL hold id, email (unique, not null), name, role, password_hash, mfa_enabled, mfa_secret_encrypted, account_locked, failed_login_attempts, created_at and last_login, indexed on email and role. |
none |
REQ-099-081 |
- | The api_keys table SHALL hold id, user_id (foreign key to users), name, key_hash, prefix, permissions, created_at, expires_at, last_used, revoked and revoked_at, indexed on user_id and prefix. |
none |
REQ-099-082 |
- | The sessions table SHALL hold id, user_id (foreign key to users), refresh_token_hash, access_token_hash, ip_address, user_agent, created_at, expires_at, revoked and revoked_at, indexed on user_id, refresh_token_hash and expires_at. |
none |
REQ-099-083 |
- | PAM++ decisions SHALL be cached in Redis under pam:decision:{user_id}:{permission}:{resource} with a 300-second TTL, and SHALL be invalidated on policy change or user role change. |
none |
REQ-099-084 |
- | Token validation results SHALL be cached in per-instance memory under `token:«redacted» for the token's remaining lifetime, so that validation does not require a Redis lookup on every request. | none |
REQ-099-085 |
- | Rate-limit counters SHALL be held in Redis under ratelimit:{user_id}:{endpoint} as a sliding-window counter over a rolling window. |
none |
REQ-099-086 |
- | User permissions SHALL be cached in Redis under perms:{user_id} with a 3600-second TTL, and SHALL be invalidated on role change or on explicit invalidation. |
none |
REQ-099-087 |
- | The system SHALL apply defence in depth: WAF, DDoS protection and VPN requirement at the network layer; input validation, output encoding and CSRF protection at the application layer; encryption at rest and in transit at the data layer; and MFA, password policies and account lockout at the identity layer. | none |
REQ-099-088 |
- | The system SHALL follow a zero-trust architecture: it SHALL authenticate and authorize every request, SHALL assume breach and monitor accordingly, and SHALL grant least-privilege access. | none |
REQ-099-089 |
- | The system SHALL be secure by default: access SHALL be denied unless an explicit allow policy exists, configuration SHALL follow secure baselines, and the attack surface SHALL be kept minimal. | none |
REQ-099-090 |
- | Data at rest SHALL be encrypted with AES-256-GCM under key rotation, data in transit SHALL use TLS 1.3 with perfect forward secrecy, keys SHALL be managed by an HSM or Vault with automatic rotation, and tokens SHALL be stored hashed with bcrypt at cost factor 12 or higher. | none |
REQ-099-220 |
- | The system SHALL emit metrics for authentication success and failure rates, authorization decision latencies, token issuance and validation counts, rate-limit triggers and violations, and session creation and expiry rates. | none |
REQ-099-221 |
- | Logs SHALL be structured JSON, SHALL carry correlation IDs for request tracing, SHALL record security events with an appropriate severity, and SHALL keep audit logs tamper-resistant. | none |
REQ-099-222 |
- | The system SHALL alert on failed-login thresholds being exceeded, unusual authentication patterns, PAM++ service unavailability, token-blacklist failures, and audit-log tampering detection. | none |
REQ-099-223 |
- | Dashboards SHALL present real-time authentication metrics, authorization decision analytics, the security incident timeline, and compliance status indicators. | none |
REQ-099-091 |
- | Governance policies SHALL be defined in Prolog syntax, SHALL be evaluated in order of specificity, SHALL default to denying all access, and every governance decision SHALL be logged for audit. | none |
REQ-099-092 |
- | The policy engine SHALL support Access Control Policies (ACP), Data Governance Policies (DGP) and Compliance Policies (CP). | none |
REQ-099-093 |
- | When a user attempts an action, the auth middleware SHALL validate authentication, the authorization middleware SHALL query PAM++, PAM++ SHALL evaluate its rules against the request context, and the decision SHALL be returned with its policy ID before the action is allowed or denied. | none |
REQ-099-094 |
- | The system SHALL implement the compliance controls listed above: SOC 2 CC6.1, CC6.2 and CC6.6, GDPR Article 32, PCI DSS 8.2, and NIST AC-2 and IA-5. | none |
REQ-099-095 |
- | GitHub OAuth SHALL use the authorization URL https://github.com/login/oauth/authorize, the token URL https://github.com/login/oauth/access_token, the user-info URL https://api.github.com/user, and the scopes read:user and user:email. |
none |
REQ-099-096 |
- | Google OAuth SHALL use the authorization URL https://accounts.google.com/o/oauth2/v2/auth, the token URL https://oauth2.googleapis.com/token, the user-info URL https://www.googleapis.com/oauth2/v3/userinfo, and the scopes openid, email and profile. |
none |
REQ-099-097 |
- | GitLab OAuth SHALL use the authorization URL https://gitlab.com/oauth/authorize, the token URL https://gitlab.com/oauth/token, the user-info URL https://gitlab.com/api/v4/user, and the scopes read_user and api. |
none |
REQ-099-098 |
- | The HashiCorp Vault backend SHALL take its address from VAULT_ADDR, SHALL authenticate with the token in VAULT_TOKEN, SHALL use the KV v2 secrets engine, and SHALL rotate keys automatically every month. |
none |
REQ-099-099 |
- | The AWS Secrets Manager backend SHALL take a configurable region, SHALL authenticate with an IAM role, SHALL store secrets as JSON, and SHALL rotate keys with a Lambda function. | none |
REQ-099-100 |
- | Session storage SHALL run on a Redis cluster of at least 3 master nodes, with AOF persistence every 1 second, TLS 1.3 transport, and Redis AUTH password protection. | none |
REQ-099-101 |
- | Audit records SHALL be written as JSON with a hash chain, held in Elasticsearch hot storage for 90 days, and archived to S3 Glacier cold storage for 7 years. | none |
REQ-099-102 |
- | Authentication SHALL be accepted only when users can authenticate with email and password, with API keys and via OAuth providers, session tokens expire after the configured duration, and refresh tokens allow re-authentication without a fresh login. | none |
REQ-099-103 |
- | Authorization SHALL be accepted only when PAM++ queries return the correct decisions, RBAC enforces role-based permissions, resource-level permissions are enforced, and the default deny policy blocks unauthorized access. | none |
REQ-099-104 |
- | MFA SHALL be accepted only when TOTP setup generates unique secrets, TOTP verification succeeds for valid codes, backup codes can be used for recovery, and account lockout triggers at the threshold. | none |
REQ-099-105 |
- | Security SHALL be accepted only when passwords meet the complexity requirements, API keys are hashed before storage, data at rest is encrypted with AES-256-GCM, all connections use TLS 1.3, and token revocation takes effect immediately. | none |
REQ-099-106 |
- | Audit SHALL be accepted only when all authentication events and authorization decisions are logged, audit logs are tamper-resistant, hash-chain verification works, and logs are retained for 7 years. | none |
REQ-099-107 |
- | Rate limiting SHALL be accepted only when authentication endpoints carry stricter limits, general endpoints carry configurable limits, account lockout triggers after 5 failures, and progressive delays prevent brute-force attempts. | none |
REQ-099-108 |
- | Compliance SHALL be accepted only when the SOC 2 controls, GDPR Article 32, PCI DSS 8.2 and NIST AC-2 and IA-5 requirements are met. | none |
REQ-099-224 |
- | Components SHALL log all major operations at appropriate log levels, SHALL include correlation IDs for request tracing, SHALL log performance metrics for critical operations, and SHALL log errors with full context. | none |
REQ-099-225 |
- | The system SHALL expose operation duration histograms, request and error rate counters, resource utilization gauges, and business metrics relevant to the domain. | none |
REQ-099-226 |
- | The system SHALL propagate traces across component boundaries, SHALL attach domain-specific span attributes, and SHALL sample traces according to operational needs. | none |
REQ-099-227 |
- | The system SHALL raise critical alerts on error-rate spikes, performance degradation, resource exhaustion, and business-metric anomalies. | none |
REQ-099-228 |
- | The operational dashboard SHALL present real-time system health, performance trends, error analysis and resource monitoring. | none |
REQ-099-109 |
- | The PAM++ client SHALL be configured with the PAM++ host, port, API-key authentication and a 5.0-second timeout, and SHALL authenticate a user by posting the user id and credentials to the PAM++ /auth endpoint with the API key as a bearer token. |
none |
REQ-099-110 |
- | On a PAM++ timeout the system SHALL log a PAM_TIMEOUT_ALLOW event and allow access; when PAM++ is unavailable the system SHALL deny access by raising PAMUnavailableError. |
none |
REQ-099-111 |
- | Per-endpoint rate limits SHALL be enforced as 5 requests per 300 seconds on /api/v1/auth/login, 10 per 60 seconds on /api/v1/auth/verify_mfa, 30 per 60 seconds on /api/v1/intent, and 60 per 60 seconds on /api/v1/agents/*. |
none |
REQ-099-112 |
- | Accounts SHALL be locked after 5 failed login attempts for 1800 seconds, and login delays SHALL progress from a 1-second base up to a 64-second maximum. | none |
REQ-099-113 |
- | Each audit entry SHALL carry the previous entry's hash and a timestamp, SHALL be hashed with SHA-256 over its canonically-sorted JSON content, and SHALL be appended to immutable WORM storage. | none |
REQ-099-114 |
- | Audit-chain verification SHALL recompute every entry's hash and SHALL raise a tamper error when an entry's hash does not match its content or its recorded previous hash does not match the preceding entry. | none |
REQ-099-115 |
- | Passwords SHALL be at least 12 and at most 128 characters, SHALL contain uppercase, lowercase, numeric and special characters, and SHALL be rejected when they match a common password or contain the user's personal information. | none |
REQ-099-116 |
- | The system SHALL support API-key authentication for CLI and scripts, OAuth 2.0 for the web UI, session tokens for persistent web-UI login, and service-account authentication for internal services. | none |
REQ-099-117 |
- | An API key SHALL be presented as Authorization: Bearer <key>, SHALL carry the sk_ prefix, SHALL be at least 32 characters drawn from alphanumeric characters and underscore, and SHALL be generated from a cryptographically secure URL-safe random source. |
none |
REQ-099-118 |
- | The OAuth 2.0 flow SHALL redirect the user to the provider, SHALL accept the provider's callback code, SHALL exchange that code for a token, and SHALL then create a session and redirect the user back to the application. | none |
REQ-099-119 |
- | The session token SHALL be a JWT expiring after a configurable 24 hours with a 7-day refresh token, and sessions SHALL be stored in Redis for distributed access and encrypted at rest. | none |
REQ-099-120 |
- | The system SHALL provide the built-in roles admin (full system access), auditor (read-only access to audit logs), project_admin (manage project configuration), developer (read/write code, create tasks), viewer (read-only project access) and guest (minimal access to public projects). |
none |
REQ-099-121 |
- | Data at rest SHALL be encrypted: database fields with AES-256-GCM, file storage on an encrypted filesystem, and backups with a key from the key vault. | none |
REQ-099-122 |
- | Data in transit SHALL be encrypted: all HTTP over TLS 1.3, all WebSocket traffic over WSS, and all internal traffic over mTLS. | none |
REQ-099-123 |
- | The master key SHALL be held in an HSM or secure vault, data encryption keys SHALL be encrypted by the master key, and API keys SHALL be stored hashed with bcrypt. | none |
REQ-099-124 |
- | The master key SHALL be rotated annually by manual action, data encryption keys SHALL be rotated monthly and automatically, and API keys SHALL be rotated on compromise or annually. | none |
REQ-099-125 |
- | Secrets management SHALL support HashiCorp Vault and AWS Secrets Manager as backends, and environment variables SHALL be used as a secrets backend in development only. | none |
REQ-099-126 |
- | The authentication middleware SHALL extract the token from the request header, SHALL validate it, and SHALL attach the resolved user to the request before the handler runs. | none |
REQ-099-127 |
- | The authorization middleware SHALL determine the permission required by the route, SHALL check it against PAM++ for the request user and resource, and SHALL reject the request with the decision's reason when access is not allowed. | none |
REQ-099-128 |
- | The rate-limiting middleware SHALL identify the requesting user, SHALL check that user's rate limit, and SHALL reject the request with a retry-after value when the limit is exceeded. | none |
REQ-099-129 |
- | The audit log SHALL capture, for authentication the user, method, IP and result; for authorization the user, permission, resource and decision; for data access the user, resource and action; for data modification the user, resource, old value and new value; for configuration changes the user, setting, old value and new value; and for security events the event type, details and severity. | none |
REQ-099-130 |
- | Each audit entry SHALL carry event_id, event_type, timestamp, the acting user's id and role, action, resource, decision, the request context (IP, user agent, method) and the governance policy id, rule id and match flag. |
none |
REQ-099-131 |
- | Audit records SHALL be searchable in hot storage for 90 days, archived for 7 years, and SHALL have personally identifiable information redacted after 1 year. | none |
REQ-099-132 |
- | The security configuration SHALL accept the enabled authentication methods, a session expiry of 86400 seconds and refresh expiry of 604800 seconds, the OAuth 2.0 providers and credentials, an authorization block with pam++ as policy engine and deny as default policy, an encryption block with AES-256-GCM and a 30-day key rotation against the configured vault backend, a rate-limiting block with default and burst limits, and an audit block with 2555-day retention and 90-day hot storage. |
none |
REQ-099-133 |
- | The system SHALL read SECRET_KEY for the master encryption key, OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET for the OAuth application credentials, and VAULT_ADDR and VAULT_TOKEN for the HashiCorp Vault address and authentication token. |
none |
REQ-099-134 |
- | Authentication failures SHALL be reported as AUTH-001 invalid API key, AUTH-002 API key expired, AUTH-003 session expired and AUTH-004 OAuth failed, each with HTTP status 401. | none |
REQ-099-135 |
- | Authorization failures SHALL be reported as AUTHZ-001 access denied with HTTP status 403, AUTHZ-002 governance blocked with HTTP status 451, and AUTHZ-003 insufficient permissions with HTTP status 403. | none |
REQ-099-136 |
- | Every error response SHALL carry the error code, the message, the details (reason, resource and policy) and the request id. | none |
REQ-099-229 |
- | The security test suite SHALL prove that authentication succeeds with valid credentials and fails with invalid ones, that authorization blocks unauthorized actions and allows authorized ones, that rate limiting triggers at the threshold, that audit logs capture all security events, that encryption at rest works, and that session expiry works. | none |
REQ-099-230 |
- | The system SHALL prevent SQL injection, cross-site scripting, cross-site request forgery, path traversal and command injection, and penetration testing SHALL cover each of them. | none |
REQ-099-231 |
- | The system SHALL conform to the OWASP Top 10, SOC 2 Type II, the GDPR data-handling requirements and the CCPA data-handling requirements. | none |
REQ-099-137 |
- | Responses SHALL carry the security headers Strict-Transport-Security: max-age=31536000; includeSubDomains, Content-Security-Policy: default-src 'self', X-Content-Type-Options: nosniff, X-Frame-Options: DENY, X-XSS-Protection: 1; mode=block and Referrer-Policy: strict-origin-when-cross-origin. |
none |
REQ-099-138 |
- | Security incidents SHALL be classified and answered within the stated response times: critical (data breach or full system compromise) within 1 hour, high (unauthorized access or privilege escalation) within 4 hours, medium (policy violation or suspicious activity) within 24 hours, and low (minor security concern) within 7 days. | none |
REQ-099-139 |
- | Incident response SHALL follow the steps detect, contain, eradicate, recover, document and review. | none |
REQ-099-140 |
- | The framework SHALL depend on PyJWT >=2.8 for JWT handling, passlib >=1.7 for password hashing, cryptography >=41.0 for encryption, httpx >=0.25 for HTTP requests, and structlog >=24.0 for structured logging. | none |
Code that traces this spec
No src/ symbol cites a requirement of this spec.
Other tracked files
specs/099-security-auth-framework/compliance-audit.md
Full spec text
Verbatim from specs/099-security-auth-framework/spec.md; headings are pushed down two levels.
SPEC-099: Security & Auth Framework
Metadata
- Spec ID: 099-security-auth-framework
- Title: Security & Auth Framework - Centralized Authentication, Encryption, PAM++ Integration
- Author: Mohamed
- Status: Complete
- Created: 2026-04-08
- Last Updated: 2026-04-09
- Priority: P0
- Version: 1.1.0
Overview
This specification defines the security and authentication framework for orchestrata-ultimate. It provides centralized authentication, encryption, session management, and integrates with PAM++ governance for authorization.
User Scenarios
US-001: User Authenticating with API Key
As a CLI user, I want to authenticate with an API key so I can access the system securely.
Acceptance Criteria:
- Generate API key with required permissions
- Use key in Authorization header
- Key expires after configurable time
- Key can be revoked at any time
REQ-099-001: The system SHALL allow a CLI user to authenticate with an API key. The key SHALL be generated with the permissions required for its use, SHALL be presented in the Authorization header, SHALL expire after a configurable time, and SHALL be revocable at any time.
US-002: Admin Enabling MFA
As a security admin, I want to enable MFA so I can require multi-factor authentication for all users.
Acceptance Criteria:
- Support TOTP (Time-based One-Time Password)
- Support SMS backup
- Generate backup codes
- Enforce MFA for all users or specific roles
REQ-099-002: The system SHALL allow a security admin to enable multi-factor authentication. MFA SHALL support TOTP and SMS backup, SHALL generate backup codes, and SHALL be enforceable for all users or for specific roles.
US-003: User Session Management
As a web user, I want session tokens that expire automatically so my account stays secure.
Acceptance Criteria:
- Login creates session with JWT
- Session expires after 24 hours
- Refresh token valid for 7 days
- Session invalidated on logout
REQ-099-003: Login SHALL create a session carrying a JWT, the session SHALL expire after 24 hours, the refresh token SHALL be valid for 7 days, and logout SHALL invalidate the session.
US-004: Security Incident Response
As a security officer, I want to revoke all tokens immediately so I can respond to security incidents.
Acceptance Criteria:
- Revoke all active sessions
- Invalidate all API keys
- Block user account if needed
- Audit log all revocation actions
REQ-099-004: A security officer SHALL be able to revoke all active sessions and invalidate all API keys, SHALL be able to block a user account, and every revocation action SHALL be written to the audit log.
Terminology
| Term | Definition |
|---|---|
| PAM++ | Prolog Authorization Manager - policy engine for authorization decisions |
| JWT | JSON Web Token - compact, URL-safe token format for claims |
| TOTP | Time-based One-Time Password - RFC 6238 compliant MFA method |
| MFA | Multi-Factor Authentication - requiring multiple verification methods |
| API Key | Secret key for programmatic access to the system |
| Session | Server-side user state after successful authentication |
| Refresh Token | Long-lived token for obtaining new access tokens |
| Access Token | Short-lived token for API authorization |
| WORM | Write-Once Read-Many - tamper-resistant storage |
| HSM | Hardware Security Module - physical device for key management |
| DEK | Data Encryption Key - key used to encrypt data |
| RBAC | Role-Based Access Control - authorization model |
Data Models (JSON Schemas)
User
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["id", "email", "name", "role"],
"properties": {
"id": {
"type": "string",
"pattern": "^user_[a-zA-Z0-9]+$"
},
"email": {
"type": "string",
"format": "email"
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"role": {
"type": "string",
"enum": ["admin", "auditor", "project_admin", "developer", "viewer", "guest"]
},
"projects": {
"type": "array",
"items": {
"type": "string"
}
},
"created_at": {
"type": "string",
"format": "date-time"
},
"last_login": {
"type": "string",
"format": "date-time"
},
"mfa_enabled": {
"type": "boolean"
},
"mfa_secret": {
"type": "string",
"description": "TOTP secret (base32 encoded)"
},
"password_hash": {
"type": "string",
"description": "bcrypt hash"
},
"account_locked": {
"type": "boolean"
},
"failed_login_attempts": {
"type": "integer",
"minimum": 0
}
}
}
REQ-099-005: The system SHALL represent a User conforming to the schema above: id, email, name and role SHALL be required; id SHALL match ^user_[a-zA-Z0-9]+$; role SHALL be one of admin, auditor, project_admin, developer, viewer or guest; and the record SHALL carry projects, created_at, last_login, mfa_enabled, mfa_secret (base32 TOTP secret), password_hash (bcrypt), account_locked and failed_login_attempts.
API Key
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["id", "user_id", "name", "prefix", "permissions"],
"properties": {
"id": {
"type": "string",
"pattern": "^key_[a-zA-Z0-9]+$"
},
"user_id": {
"type": "string",
"pattern": "^user_[a-zA-Z0-9]+$"
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"prefix": {
"type": "string",
"pattern": "^sk_[a-zA-Z0-9]{8}$",
"description": "First 12 chars of key for identification"
},
"permissions": {
"type": "array",
"items": {
"type": "string",
"enum": ["read", "write", "admin", "audit"]
}
},
"created_at": {
"type": "string",
"format": "date-time"
},
"expires_at": {
"type": "string",
"format": "date-time"
},
"last_used": {
"type": "string",
"format": "date-time"
},
"revoked": {
"type": "boolean"
},
"revoked_at": {
"type": "string",
"format": "date-time"
}
}
}
REQ-099-006: The system SHALL represent an API Key conforming to the schema above: id, user_id, name, prefix and permissions SHALL be required; id SHALL match ^key_[a-zA-Z0-9]+$; prefix SHALL match ^sk_[a-zA-Z0-9]{8}$; each permission SHALL be one of read, write, admin or audit; and the record SHALL carry created_at, expires_at, last_used, revoked and revoked_at.
Session
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["id", "user_id", "refresh_token", "expires_at"],
"properties": {
"id": {
"type": "string",
"pattern": "^sess_[a-zA-Z0-9]+$"
},
"user_id": {
"type": "string",
"pattern": "^user_[a-zA-Z0-9]+$"
},
"refresh_token": {
"type": "string",
"description": "JWT refresh token"
},
"access_token": {
"type": "string",
"description": "JWT access token (expires in 1 hour)"
},
"expires_at": {
"type": "string",
"format": "date-time"
},
"ip_address": {
"type": "string",
"format": "ipv4"
},
"user_agent": {
"type": "string"
},
"created_at": {
"type": "string",
"format": "date-time"
},
"revoked": {
"type": "boolean"
},
"revoked_at": {
"type": "string",
"format": "date-time"
}
}
}
REQ-099-007: The system SHALL represent a Session conforming to the schema above: id, user_id, refresh_token and expires_at SHALL be required; id SHALL match ^sess_[a-zA-Z0-9]+$; the access token SHALL be a JWT that expires in 1 hour; and the record SHALL carry ip_address, user_agent, created_at, revoked and revoked_at.
MFA Setup
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["secret", "backup_codes"],
"properties": {
"secret": {
"type": "string",
"description": "TOTP secret (base32 encoded)"
},
"qr_code": {
"type": "string",
"description": "Base64 encoded QR code image"
},
"backup_codes": {
"type": "array",
"items": {
"type": "string",
"pattern": "^[0-9]{8}$"
}
},
"method": {
"type": "string",
"enum": ["totp", "sms", "u2f"]
}
}
}
REQ-099-008: The system SHALL represent an MFA setup conforming to the schema above: secret (base32 TOTP secret) and backup_codes SHALL be required; qr_code SHALL be a base64-encoded QR image; each backup code SHALL match ^[0-9]{8}$; and method SHALL be one of totp, sms or u2f.
Functional Requirements
Authentication
FR-001 — REQ-099-009: The system MUST support API key authentication for CLI and programmatic access.
FR-002 — REQ-099-010: The system MUST support OAuth 2.0 authentication for web UI access.
FR-003 — REQ-099-011: The system MUST support session-based authentication with JWT tokens.
FR-004 — REQ-099-012: The system MUST support MFA using TOTP (Time-based One-Time Password).
FR-005 — REQ-099-013: The system MUST support MFA using SMS backup codes.
FR-006 — REQ-099-014: The system MUST validate all authentication tokens before allowing access.
FR-007 — REQ-099-015: The system MUST expire authentication tokens after configurable duration.
Authorization
FR-008 — REQ-099-016: The system MUST query PAM++ for all authorization decisions.
FR-009 — REQ-099-017: The system MUST enforce RBAC (Role-Based Access Control) across all resources.
FR-010 — REQ-099-018: The system MUST support permission levels: global, project, resource, and action.
FR-011 — REQ-099-019: The system MUST deny access by default when no explicit allow policy exists.
FR-012 — REQ-099-020: The system MUST provide fine-grained permission control at the resource level.
Session Management
FR-013 — REQ-099-021: The system MUST create sessions upon successful authentication.
FR-014 — REQ-099-022: The system MUST invalidate sessions on logout.
FR-015 — REQ-099-023: The system MUST enforce session expiry (24 hours default).
FR-016 — REQ-099-024: The system MUST support refresh tokens valid for 7 days.
FR-017 — REQ-099-025: The system MUST invalidate all sessions during security incidents.
Token Security
FR-018 — REQ-099-026: The system MUST hash API keys with bcrypt before storage.
FR-019 — REQ-099-027: The system MUST support token revocation with immediate effect.
FR-020 — REQ-099-028: The system MUST maintain token blacklist in Redis.
FR-021 — REQ-099-029: The system MUST encrypt sensitive data fields with AES-256-GCM.
FR-022 — REQ-099-030: The system MUST support automatic key rotation (monthly for DEKs).
Rate Limiting
FR-023 — REQ-099-031: The system MUST enforce per-user rate limits.
FR-024 — REQ-099-032: The system MUST implement stricter limits on authentication endpoints.
FR-025 — REQ-099-033: The system MUST block accounts after 5 failed login attempts.
FR-026 — REQ-099-034: The system MUST implement progressive login delays.
Audit Logging
FR-027 — REQ-099-035: The system MUST log all authentication events.
FR-028 — REQ-099-036: The system MUST log all authorization decisions.
FR-029 — REQ-099-037: The system MUST implement tamper-resistant audit logs using hash chains.
FR-030 — REQ-099-038: The system MUST maintain audit logs for 7 years.
FR-031 — REQ-099-039: The system MUST provide audit log verification capabilities.
Account Security
FR-032 — REQ-099-040: The system MUST enforce password policies (12+ chars, complexity).
FR-033 — REQ-099-041: The system MUST detect common passwords and reject them.
FR-034 — REQ-099-042: The system MUST lock accounts after threshold failed attempts.
FR-035 — REQ-099-043: The system MUST support emergency token revocation.
FR-036 — REQ-099-044: The system MUST encrypt password hashes in storage.
MFA Security
FR-037 — REQ-099-045: The system MUST generate unique TOTP secrets for each user.
FR-038 — REQ-099-046: The system MUST generate backup codes for MFA recovery.
FR-039 — REQ-099-047: The system MUST prevent backup code reuse.
FR-040 — REQ-099-048: The system MUST require MFA verification after sensitive operations.
Error Conditions
| ERR-ID | Condition | Handling |
|---|---|---|
| ERR-001 | Invalid API key provided | Return 401 with AUTH-001 error, log attempt |
| ERR-002 | API key expired | Return 401 with AUTH-002, prompt for key rotation |
| ERR-003 | API key revoked | Return 401 with AUTH-003, suggest generating new key |
| ERR-004 | Session token expired | Return 401 with AUTH-004, prompt re-authentication |
| ERR-005 | Session token invalid | Return 401 with AUTH-005, require fresh login |
| ERR-006 | OAuth authentication failed | Return 401 with AUTH-006, redirect to OAuth provider |
| ERR-007 | OAuth token exchange failed | Return 401 with AUTH-007, log OAuth error details |
| ERR-008 | Access denied by PAM++ | Return 403 with ERR-008, include policy reason |
| ERR-009 | Insufficient permissions | Return 403 with ERR-009, list required permissions |
| ERR-010 | Resource not found | Return 404 with ERR-010, verify resource identifier |
| ERR-011 | Governance policy blocked action | Return 451 with ERR-011, include governance policy ID |
| ERR-012 | Rate limit exceeded | Return 429 with ERR-012, include retry-after header |
| ERR-013 | Account locked due to failed attempts | Return 403 with ERR-013, show lockout duration |
| ERR-014 | MFA verification failed | Return 401 with ERR-014, allow retry with MFA |
| ERR-015 | MFA code invalid or expired | Return 401 with ERR-015, suggest using backup code |
| ERR-016 | Backup code already used | Return 401 with ERR-016, prompt for new backup code |
| ERR-017 | Password does not meet policy | Return 400 with ERR-017, list policy requirements |
| ERR-018 | Common password detected | Return 400 with ERR-018, suggest stronger password |
| ERR-019 | PAM++ service unavailable | Return 503 with ERR-019, use fallback deny policy |
| ERR-020 | PAM++ query timeout | Return 503 with ERR-020, log security event |
| ERR-021 | Token blacklist check failed | Deny access by default, log error |
| ERR-022 | Encryption key retrieval failed | Return 500 with ERR-022, alert security team |
| ERR-023 | Audit log write failed | Log to secondary, alert operations team |
| ERR-024 | Audit chain tampering detected | Alert security team, preserve logs for forensics |
| ERR-025 | User account does not exist | Return 404 with ERR-025, generic error message |
| ERR-026 | User account disabled | Return 403 with ERR-026, contact admin message |
| ERR-027 | IP address blocked | Return 403 with ERR-027, include block reason |
| ERR-028 | Invalid JWT signature | Return 401 with ERR-028, require re-authentication |
| ERR-029 | JWT claim validation failed | Return 401 with ERR-029, check token payload |
| ERR-030 | Refresh token expired | Return 401 with ERR-030, require fresh login |
REQ-099-049: The system SHALL detect each of the conditions ERR-001 through ERR-030 listed above and SHALL respond with the HTTP status, error code and handling given for that condition.
Token Revocation
Token Blacklist
- Revoked tokens stored in Redis
- Key format:
revoked:{token_hash} - TTL: Original token expiry time
- Hash: SHA-256 of full token
REQ-099-050: Revoked tokens SHALL be stored in Redis under the key revoked:{token_hash}, where token_hash is the SHA-256 of the full token, with a TTL equal to the original token expiry; the stored record SHALL carry the revocation reason, the revoking user and the revocation timestamp.
Revocation API
async def revoke_token(token: str, reason: str, user_id: str):
"""Revoke a token immediately."""
token_hash = hashlib.sha256(token.encode()).hexdigest()
await redis.setex(
f"revoked:{token_hash}",
ttl_seconds,
json.dumps({
"reason": reason,
"revoked_by": user_id,
"revoked_at": datetime.utcnow().isoformat()
})
)
Session Invalidation
async def invalidate_all_sessions(user_id: str):
"""Invalidate all active sessions for user."""
session_ids = await redis.smembers(f"sessions:{user_id}")
for session_id in session_ids:
await redis.delete(f"session:{session_id}")
await redis.srem(f"sessions:{user_id}", session_id)
REQ-099-051: Invalidating all sessions for a user SHALL delete every session held in that user's session set and SHALL remove each session id from the set.
MFA Implementation
TOTP (Time-based One-Time Password)
import pyotp
import qrcode
async def setup_totp(user_id: str):
"""Setup TOTP for user."""
# Generate secret
secret = «redacted»
# Generate QR code
provisioning_uri = pyotp.totp.TOTP(secret).provisioning_uri(
name=user_id,
issuer_name="Orchestrata Ultimate"
)
qr = qrcode.ProvisionQR(provisioning_uri)
# Store secret (encrypted)
await store_secret(user_id, encrypt(secret))
return {
"secret": secret,
"qr_code": qr.to_base64()
}
async def verify_totp(user_id: str, code: str) -> bool:
"""Verify TOTP code."""
secret = await get_secret(user_id)
totp = pyotp.TOTP(secret)
return totp.verify(code)
REQ-099-052: TOTP setup SHALL generate a random base32 secret, SHALL return a provisioning QR code issued under the name Orchestrata Ultimate, and SHALL store the secret encrypted; TOTP verification SHALL check the submitted code against the stored secret.
Backup Codes
async def generate_backup_codes() -> List[str]:
"""Generate 10 backup codes."""
return [str(random.randint(10000000, 99999999)) for _ in range(10)]
async def use_backup_code(user_id: str, code: str) -> bool:
"""Verify and mark backup code as used."""
used = await redis.sismember(f"backup_codes:{user_id}", code)
if not used:
await redis.sadd(f"backup_codes:{user_id}", code)
return True
return False
REQ-099-053: The system SHALL generate 10 backup codes, each of 8 numeric digits, and SHALL accept any given backup code only once.
Account Lockout Policy
FAILED_ATTEMPTS_THRESHOLD = 5
LOCKOUT_DURATION = 1800 # 30 minutes
async def check_failed_login(user_id: str):
"""Check if account should be locked."""
attempts = await redis.incr(f"failed:{user_id}")
if attempts >= FAILED_ATTEMPTS_THRESHOLD:
await redis.setex(f"locked:{user_id}", LOCKOUT_DURATION, "1")
await log_security_event("ACCOUNT_LOCKED", user_id)
REQ-099-054: After 5 failed login attempts the account SHALL be locked for 1800 seconds (30 minutes) and an ACCOUNT_LOCKED security event SHALL be logged.
PAM++ Binding
Prolog Query
async def query_pam(user_id: str, action: str, resource: str, context: dict):
"""Query PAM++ for authorization decision."""
# Build prolog query
query = f"""
can_perform(
user:{user_id},
action:{action},
resource:{resource},
context:{{
ip:{context.get('ip')},
time:{context.get('timestamp')},
method:{context.get('method')}
}}
)
"""
# Send to PAM++ engine
result = await pam_client.query(query)
return {
"allowed": result.allowed,
"reason": result.reason,
"policy": result.policy
}
REQ-099-055: Authorization decisions SHALL be requested from PAM++ as can_perform(user, action, resource, context) with the request IP, timestamp and method carried in the context, and the PAM++ response SHALL supply the decision, its reason and the matched policy.
API Contracts
Authentication Endpoints
POST /api/v1/auth/login
- Request:
{ "email": string, "password": string } - Response:
{ "access_token": string, "refresh_token": string, "expires_in": number } - Errors: ERR-001, ERR-006, ERR-017, ERR-018, ERR-025
REQ-099-056: The system SHALL expose POST /api/v1/auth/login, accepting { email, password } and returning { access_token, refresh_token, expires_in }, and SHALL report ERR-001, ERR-006, ERR-017, ERR-018 and ERR-025 on failure.
POST /api/v1/auth/refresh
- Request:
{ "refresh_token": string } - Response:
{ "access_token": string, "expires_in": number } - Errors: ERR-004, ERR-030
REQ-099-057: The system SHALL expose POST /api/v1/auth/refresh, accepting { refresh_token } and returning { access_token, expires_in }, and SHALL report ERR-004 and ERR-030 on failure.
POST /api/v1/auth/logout
- Request:
{ "token": string } - Response:
{ "success": true } - Errors: ERR-005
REQ-099-058: The system SHALL expose POST /api/v1/auth/logout, accepting { token } and returning { success: true }, and SHALL report ERR-005 on failure.
POST /api/v1/auth/api-keys
- Request:
{ "name": string, "permissions": string[], "expires_in": number } - Response:
{ "id": string, "key": string, "prefix": string } - Errors: ERR-009
REQ-099-059: The system SHALL expose POST /api/v1/auth/api-keys, accepting { name, permissions, expires_in } and returning { id, key, prefix }, and SHALL report ERR-009 on failure.
MFA Endpoints
POST /api/v1/auth/mfa/setup
- Request:
{ "method": "totp" | "sms" } - Response:
{ "secret": string, "qr_code": string, "backup_codes": string[] } - Errors: ERR-025
REQ-099-060: The system SHALL expose POST /api/v1/auth/mfa/setup, accepting { method } of totp or sms and returning { secret, qr_code, backup_codes }, and SHALL report ERR-025 on failure.
POST /api/v1/auth/mfa/verify
- Request:
{ "code": string } - Response:
{ "verified": boolean } - Errors: ERR-014, ERR-015, ERR-016
REQ-099-061: The system SHALL expose POST /api/v1/auth/mfa/verify, accepting { code } and returning { verified }, and SHALL report ERR-014, ERR-015 and ERR-016 on failure.
POST /api/v1/auth/mfa/disable
- Request:
{ "password": string } - Response:
{ "success": boolean } - Errors: ERR-001, ERR-017
REQ-099-062: The system SHALL expose POST /api/v1/auth/mfa/disable, accepting { password } and returning { success }, and SHALL report ERR-001 and ERR-017 on failure.
Session Management Endpoints
GET /api/v1/sessions
- Response:
{ "sessions": Session[] } - Errors: ERR-008, ERR-009
REQ-099-063: The system SHALL expose GET /api/v1/sessions, returning the caller's sessions, and SHALL report ERR-008 and ERR-009 on failure.
DELETE /api/v1/sessions/{session_id}
- Response:
{ "success": boolean } - Errors: ERR-008, ERR-010
REQ-099-064: The system SHALL expose DELETE /api/v1/sessions/{session_id}, returning { success }, and SHALL report ERR-008 and ERR-010 on failure.
DELETE /api/v1/sessions
- Response:
{ "success": boolean } - Errors: ERR-008, ERR-009
REQ-099-065: The system SHALL expose DELETE /api/v1/sessions, which deletes every session of the caller and returns { success }, and SHALL report ERR-008 and ERR-009 on failure.
Authorization Endpoints
POST /api/v1/auth/authorize
- Request:
{ "action": string, "resource": string, "context": object } - Response:
{ "allowed": boolean, "reason": string, "policy": string } - Errors: ERR-008, ERR-009, ERR-019, ERR-020
REQ-099-066: The system SHALL expose POST /api/v1/auth/authorize, accepting { action, resource, context } and returning { allowed, reason, policy }, and SHALL report ERR-008, ERR-009, ERR-019 and ERR-020 on failure.
Non-Functional Requirements
Performance
- REQ-099-201: Authentication latency MUST be under 50ms for token validation
- REQ-099-202: Authorization queries MUST complete within 100ms (PAM++ timeout: 5s)
- REQ-099-203: Session creation MUST complete within 200ms
- REQ-099-204: Token refresh MUST complete within 100ms
- REQ-099-205: System MUST support 10,000 concurrent authenticated sessions
Scalability
- REQ-099-206: Authentication service MUST scale horizontally with load balancer
- REQ-099-207: Session store MUST support Redis cluster for high availability
- REQ-099-208: Token blacklist operations MUST complete within 10ms
- REQ-099-209: Rate limiting MUST support distributed counters
Availability
- REQ-099-210: Authentication service MUST achieve 99.9% uptime (SLA)
- REQ-099-211: Maximum downtime for deployments MUST NOT exceed 5 minutes
- REQ-099-212: Rate limiting MUST NOT cause false positives during traffic spikes
- REQ-099-213: PAM++ unavailability MUST trigger fail-secure mode
Security
- REQ-099-214: All passwords MUST be hashed with bcrypt (cost factor 12+)
- REQ-099-215: All API keys MUST be hashed with bcrypt before storage
- REQ-099-216: Encryption at rest MUST use AES-256-GCM
- REQ-099-217: TLS 1.3 REQUIRED for all connections
- REQ-099-218: MFA MUST be available for all user roles
- REQ-099-219: Audit logs MUST be tamper-resistant (hash chain)
Technical Design
System Architecture
The Security & Auth Framework follows a layered architecture with clear separation of concerns:
┌─────────────────────────────────────────────────────────────┐
│ API Gateway / Load Balancer │
└────────────────────────┬────────────────────────────────────┘
│
┌────────────────────────┴────────────────────────────────────┐
│ Auth Service (FastAPI) │
│ ┌───────────────┐ ┌──────────────┐ ┌─────────────────┐ │
│ │ Auth Handlers │ │ Middleware │ │ Token Service │ │
│ │ - Login │ │ - Auth │ │ - JWT │ │
│ │ - OAuth │ │ - AuthZ │ │ - Refresh │ │
│ │ - MFA │ │ - Rate Limit │ │ - Blacklist │ │
│ └───────────────┘ └──────────────┘ └─────────────────┘ │
└────────────────────────┬────────────────────────────────────┘
│
┌────────────────┴────────────────┐
│ │
┌───────┴────────┐ ┌──────┴──────────┐
│ Data Layer │ │ External │
│ ┌──────────┐ │ │ ┌────────────┐ │
│ │ Redis │ │ │ │ PAM++ │ │
│ │ - Session│ │ │ │ - AuthZ │ │
│ │ - Tokens │ │ │ │ - Policy │ │
│ └──────────┘ │ │ └────────────┘ │
│ ┌──────────┐ │ │ ┌────────────┐ │
│ │ Postgres │ │ │ │ OAuth │ │
│ │ - Users │ │ │ │ Providers │ │
│ │ - Keys │ │ │ └────────────┘ │
│ └──────────┘ │ │ │
└───────────────┘ └──────────────────┘
Core Components
1. Authentication Service
- Stateless REST API built with FastAPI
- Handles user authentication (API key, OAuth 2.0, session tokens)
- Manages JWT token lifecycle (access + refresh tokens)
- Integrates with MFA providers (TOTP, SMS)
- Implements rate limiting and account lockout policies
REQ-099-067: The Authentication Service SHALL be a stateless REST API that handles API-key, OAuth 2.0 and session-token authentication, manages the JWT access and refresh token lifecycle, integrates with the TOTP and SMS MFA providers, and enforces rate limiting and account-lockout policies.
2. Authorization Engine
- Delegates to PAM++ for all authorization decisions
- Caches policy decisions to reduce PAM++ queries
- Supports RBAC with permission inheritance
- Implements context-aware authorization (time, IP, user agent)
REQ-099-068: The Authorization Engine SHALL delegate every authorization decision to PAM++, SHALL cache policy decisions to reduce PAM++ queries, SHALL support RBAC with permission inheritance, and SHALL take request time, IP and user agent into account.
3. Token Management
- Issues short-lived JWT access tokens (1 hour)
- Issues long-lived refresh tokens (7 days)
- Maintains token blacklist for immediate revocation
- Uses Redis for distributed token validation
REQ-099-069: Token Management SHALL issue JWT access tokens valid for 1 hour and refresh tokens valid for 7 days, SHALL maintain a token blacklist for immediate revocation, and SHALL use Redis for distributed token validation.
4. Session Store
- Redis cluster for high availability
- Stores active sessions with TTL-based expiry
- Supports distributed session invalidation
- Encrypts sensitive session data at rest
REQ-099-070: The Session Store SHALL run on a Redis cluster for high availability, SHALL store active sessions with TTL-based expiry, SHALL support distributed session invalidation, and SHALL encrypt sensitive session data at rest.
5. Secrets Management
- HashiCorp Vault or AWS Secrets Manager integration
- Automatic key rotation (monthly for DEKs)
- Hardware Security Module (HSM) support for master keys
- Centralized audit logging for key access
REQ-099-071: Secrets Management SHALL integrate with HashiCorp Vault or AWS Secrets Manager, SHALL rotate data encryption keys automatically every month, SHALL support an HSM for master keys, and SHALL log every key access centrally.
6. Audit Logging
- Tamper-resistant log storage with hash chains
- Hot storage (Elasticsearch) for 90 days
- Cold storage (S3 Glacier) for 7 years
- Real-time streaming to SIEM systems
REQ-099-072: Audit Logging SHALL store entries with hash chains for tamper resistance, SHALL keep 90 days of hot storage in Elasticsearch and 7 years of cold storage in S3 Glacier, and SHALL stream events to SIEM systems in real time.
Data Flow
Authentication Flow:
User Request → Auth Middleware → Validate Token → PAM++ AuthZ → Handler
↓ (if valid)
Attach User Context
REQ-099-073: Every request SHALL pass through the auth middleware, which SHALL validate the token and obtain a PAM++ authorization decision before the handler runs, and SHALL attach the user context to the request when the token is valid.
Token Lifecycle:
Login → Create Session (24h) → Issue Access Token (1h) → Issue Refresh Token (7d)
↓
Refresh Token Used
↓
Validate & Issue New Tokens
↓
Invalidate Old Refresh Token
REQ-099-074: Login SHALL create a 24-hour session, issue a 1-hour access token and a 7-day refresh token; presenting a refresh token SHALL validate it, issue new tokens and invalidate the old refresh token.
Authorization Flow:
Request → Extract User/Permission → Query PAM++ → Cache Decision → Enforce
↓ (cached)
Return Cached Result
REQ-099-075: An authorization request SHALL extract the user and the required permission, query PAM++, cache the decision and enforce it; a cached decision SHALL be returned without re-querying PAM++.
Design Patterns
1. Middleware Pattern
- Authentication middleware validates tokens before request handling
- Authorization middleware enforces PAM++ policies
- Rate limiting middleware enforces per-user quotas
- Audit middleware logs all security events
REQ-099-076: The system SHALL implement middleware that validates tokens before request handling, enforces PAM++ authorization policies, enforces per-user rate quotas, and logs all security events for audit.
2. Repository Pattern
- UserRepository: Database operations for users
- TokenRepository: Token validation and storage
- SessionRepository: Session lifecycle management
- AuditRepository: Audit log writing and retrieval
REQ-099-077: The system SHALL implement a UserRepository for user database operations, a TokenRepository for token validation and storage, a SessionRepository for session lifecycle management, and an AuditRepository for audit-log writing and retrieval.
3. Strategy Pattern
- Authentication strategies (API key, OAuth, session)
- Encryption strategies (AES-256-GCM with various backends)
- Secrets management strategies (Vault, AWS, environment)
- MFA strategies (TOTP, SMS, U2F)
REQ-099-078: The system SHALL implement interchangeable strategies for authentication (API key, OAuth, session), encryption (AES-256-GCM across backends), secrets management (Vault, AWS, environment) and MFA (TOTP, SMS, U2F).
4. Observer Pattern
- Security event observers for audit logging
- Token revocation observers for blacklist updates
- Failed login observers for account lockout
- Policy change observers for cache invalidation
REQ-099-079: The system SHALL implement observers for security-event audit logging, token-revocation blacklist updates, failed-login account lockout, and policy-change cache invalidation.
Database Schema
Users Table:
CREATE TABLE users (
id VARCHAR(32) PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
role VARCHAR(32) NOT NULL,
password_hash VARCHAR(255),
mfa_enabled BOOLEAN DEFAULT FALSE,
mfa_secret_encrypted TEXT,
account_locked BOOLEAN DEFAULT FALSE,
failed_login_attempts INTEGER DEFAULT 0,
created_at TIMESTAMP NOT NULL,
last_login TIMESTAMP,
INDEX idx_email (email),
INDEX idx_role (role)
);
REQ-099-080: The users table SHALL hold id, email (unique, not null), name, role, password_hash, mfa_enabled, mfa_secret_encrypted, account_locked, failed_login_attempts, created_at and last_login, indexed on email and role.
API Keys Table:
CREATE TABLE api_keys (
id VARCHAR(32) PRIMARY KEY,
user_id VARCHAR(32) NOT NULL,
name VARCHAR(100) NOT NULL,
key_hash VARCHAR(255) NOT NULL,
prefix VARCHAR(12) NOT NULL,
permissions JSON NOT NULL,
created_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP,
last_used TIMESTAMP,
revoked BOOLEAN DEFAULT FALSE,
revoked_at TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
INDEX idx_user_id (user_id),
INDEX idx_prefix (prefix)
);
REQ-099-081: The api_keys table SHALL hold id, user_id (foreign key to users), name, key_hash, prefix, permissions, created_at, expires_at, last_used, revoked and revoked_at, indexed on user_id and prefix.
Sessions Table:
CREATE TABLE sessions (
id VARCHAR(32) PRIMARY KEY,
user_id VARCHAR(32) NOT NULL,
refresh_token_hash VARCHAR(255) NOT NULL,
access_token_hash VARCHAR(255),
ip_address INET,
user_agent TEXT,
created_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP NOT NULL,
revoked BOOLEAN DEFAULT FALSE,
revoked_at TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
INDEX idx_user_id (user_id),
INDEX idx_refresh_token (refresh_token_hash),
INDEX idx_expires_at (expires_at)
);
REQ-099-082: The sessions table SHALL hold id, user_id (foreign key to users), refresh_token_hash, access_token_hash, ip_address, user_agent, created_at, expires_at, revoked and revoked_at, indexed on user_id, refresh_token_hash and expires_at.
Caching Strategy
1. PAM++ Decision Cache
- Cache: Redis
- TTL: 300 seconds (5 minutes)
- Key:
pam:decision:{user_id}:{permission}:{resource} - Invalidation: On policy change or user role change
REQ-099-083: PAM++ decisions SHALL be cached in Redis under pam:decision:{user_id}:{permission}:{resource} with a 300-second TTL, and SHALL be invalidated on policy change or user role change.
2. Token Validation Cache
- Cache: In-memory (per instance)
- TTL: Token expiry time
- Key: `token:«redacted»
- Purpose: Avoid Redis lookup on every request
REQ-099-084: Token validation results SHALL be cached in per-instance memory under `token:«redacted» for the token's remaining lifetime, so that validation does not require a Redis lookup on every request.
3. Rate Limit Cache
- Cache: Redis
- TTL: Rolling window (e.g., 60 seconds)
- Key:
ratelimit:{user_id}:{endpoint} - Strategy: Sliding window counter
REQ-099-085: Rate-limit counters SHALL be held in Redis under ratelimit:{user_id}:{endpoint} as a sliding-window counter over a rolling window.
4. User Permission Cache
- Cache: Redis
- TTL: 3600 seconds (1 hour)
- Key:
perms:{user_id} - Invalidation: On role change or explicit invalidation
REQ-099-086: User permissions SHALL be cached in Redis under perms:{user_id} with a 3600-second TTL, and SHALL be invalidated on role change or on explicit invalidation.
Security Controls
1. Defense in Depth
- Network: WAF, DDoS protection, VPN requirement
- Application: Input validation, output encoding, CSRF protection
- Data: Encryption at rest and in transit
- Identity: MFA, password policies, account lockout
REQ-099-087: The system SHALL apply defence in depth: WAF, DDoS protection and VPN requirement at the network layer; input validation, output encoding and CSRF protection at the application layer; encryption at rest and in transit at the data layer; and MFA, password policies and account lockout at the identity layer.
2. Zero Trust Architecture
- Never trust, always verify
- Authenticate and authorize every request
- Assume breach (monitor everything)
- Least privilege access
REQ-099-088: The system SHALL follow a zero-trust architecture: it SHALL authenticate and authorize every request, SHALL assume breach and monitor accordingly, and SHALL grant least-privilege access.
3. Secure by Default
- Deny all access by default
- Explicit allow policies only
- Secure configuration baselines
- Minimal attack surface
REQ-099-089: The system SHALL be secure by default: access SHALL be denied unless an explicit allow policy exists, configuration SHALL follow secure baselines, and the attack surface SHALL be kept minimal.
4. Encryption Strategy
- Data at rest: AES-256-GCM with key rotation
- Data in transit: TLS 1.3 with perfect forward secrecy
- Key management: HSM or Vault with automatic rotation
- Token storage: Hashed with bcrypt (cost factor 12+)
REQ-099-090: Data at rest SHALL be encrypted with AES-256-GCM under key rotation, data in transit SHALL use TLS 1.3 with perfect forward secrecy, keys SHALL be managed by an HSM or Vault with automatic rotation, and tokens SHALL be stored hashed with bcrypt at cost factor 12 or higher.
Monitoring & Observability
1. Metrics
- Authentication success/failure rates
- Authorization decision latencies
- Token issuance and validation counts
- Rate limit triggers and violations
- Session creation and expiry rates
REQ-099-220: The system SHALL emit metrics for authentication success and failure rates, authorization decision latencies, token issuance and validation counts, rate-limit triggers and violations, and session creation and expiry rates.
2. Logging
- Structured logging with JSON format
- Correlation IDs for request tracing
- Security events with appropriate severity
- Audit logs with tamper resistance
REQ-099-221: Logs SHALL be structured JSON, SHALL carry correlation IDs for request tracing, SHALL record security events with an appropriate severity, and SHALL keep audit logs tamper-resistant.
3. Alerting
- Failed login threshold exceeded
- Unusual authentication patterns
- PAM++ service unavailability
- Token blacklist failures
- Audit log tampering detection
REQ-099-222: The system SHALL alert on failed-login thresholds being exceeded, unusual authentication patterns, PAM++ service unavailability, token-blacklist failures, and audit-log tampering detection.
4. Dashboards
- Real-time authentication metrics
- Authorization decision analytics
- Security incident timeline
- Compliance status indicators
REQ-099-223: Dashboards SHALL present real-time authentication metrics, authorization decision analytics, the security incident timeline, and compliance status indicators.
Examples
Example 1: API Key Authentication
import requests
# Authenticate with API key
headers = {
"Authorization": "Bearer sk_test_1234567890abcdef"
}
response = requests.get(
"https://api.orchestrata.local/v1/users/me",
headers=headers
)
print(response.json())
Example 2: JWT Session Token
import jwt
# Decode JWT token
token = «redacted»
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
print(f"User: {payload['sub']}, Expires: {payload['exp']}")
Example 3: MFA TOTP Setup
import pyotp
# Generate TOTP secret
secret = «redacted»
totp = pyotp.TOTP(secret)
# Verify code
code = input("Enter MFA code: ")
print(totp.verify(code)) # True/False
Example 4: Rate Limit Handling
import time
def make_request_with_retry(url, headers, max_retries=3):
for attempt in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code == 429:
wait_time = int(response.headers["Retry-After"])
print(f"Rate limited. Waiting {wait_time}s...")
time.sleep(wait_time)
else:
return response
raise Exception("Max retries exceeded")
Governance
PAM++ Policy Engine
The system integrates with PAM++ (Prolog Authorization Manager) for governance decisions:
Policy Structure:
- Policies defined in Prolog syntax
- Rules evaluated in order of specificity
- Default deny all behavior
- Governance decisions logged for audit
REQ-099-091: Governance policies SHALL be defined in Prolog syntax, SHALL be evaluated in order of specificity, SHALL default to denying all access, and every governance decision SHALL be logged for audit.
Policy Categories:
- Access Control Policies (ACP)
- Data Governance Policies (DGP)
- Compliance Policies (CP)
REQ-099-092: The policy engine SHALL support Access Control Policies (ACP), Data Governance Policies (DGP) and Compliance Policies (CP).
Governance Flow:
- User attempts action
- Auth middleware validates authentication
- Authorization middleware queries PAM++
- PAM++ evaluates rules with context
- Decision returned with policy ID
- Action allowed or denied
REQ-099-093: When a user attempts an action, the auth middleware SHALL validate authentication, the authorization middleware SHALL query PAM++, PAM++ SHALL evaluate its rules against the request context, and the decision SHALL be returned with its policy ID before the action is allowed or denied.
Compliance Controls
| Control ID | Framework | Requirement |
|---|---|---|
| CC6.1 | SOC 2 | Logical and physical access controls |
| CC6.2 | SOC 2 | User provisioning and deprovisioning |
| CC6.6 | SOC 2 | Password management and complexity |
| Art. 32 | GDPR | Security of processing measures |
| 8.2 | PCI DSS | Strong authentication mechanisms |
| AC-2 | NIST | Account management lifecycle |
| IA-5 | NIST | Authenticator management |
REQ-099-094: The system SHALL implement the compliance controls listed above: SOC 2 CC6.1, CC6.2 and CC6.6, GDPR Article 32, PCI DSS 8.2, and NIST AC-2 and IA-5.
Integration Points
External Authentication Providers
GitHub OAuth:
- Authorization URL: https://github.com/login/oauth/authorize
- Token URL: https://github.com/login/oauth/access_token
- User info: https://api.github.com/user
- Scopes: read:user, user:email
REQ-099-095: GitHub OAuth SHALL use the authorization URL https://github.com/login/oauth/authorize, the token URL https://github.com/login/oauth/access_token, the user-info URL https://api.github.com/user, and the scopes read:user and user:email.
Google OAuth:
- Authorization URL: https://accounts.google.com/o/oauth2/v2/auth
- Token URL: https://oauth2.googleapis.com/token
- User info: https://www.googleapis.com/oauth2/v3/userinfo
- Scopes: openid, email, profile
REQ-099-096: Google OAuth SHALL use the authorization URL https://accounts.google.com/o/oauth2/v2/auth, the token URL https://oauth2.googleapis.com/token, the user-info URL https://www.googleapis.com/oauth2/v3/userinfo, and the scopes openid, email and profile.
GitLab OAuth:
- Authorization URL: https://gitlab.com/oauth/authorize
- Token URL: https://gitlab.com/oauth/token
- User info: https://gitlab.com/api/v4/user
- Scopes: read_user, api
REQ-099-097: GitLab OAuth SHALL use the authorization URL https://gitlab.com/oauth/authorize, the token URL https://gitlab.com/oauth/token, the user-info URL https://gitlab.com/api/v4/user, and the scopes read_user and api.
Secrets Management
HashiCorp Vault:
- Address: Configurable via VAULT_ADDR
- Authentication: Token-based (VAULT_TOKEN)
- Secrets engine: KV v2
- Key rotation: Automatic monthly
REQ-099-098: The HashiCorp Vault backend SHALL take its address from VAULT_ADDR, SHALL authenticate with the token in VAULT_TOKEN, SHALL use the KV v2 secrets engine, and SHALL rotate keys automatically every month.
AWS Secrets Manager:
- Region: Configurable
- Authentication: IAM role
- Secrets format: JSON
- Key rotation: Lambda function
REQ-099-099: The AWS Secrets Manager backend SHALL take a configurable region, SHALL authenticate with an IAM role, SHALL store secrets as JSON, and SHALL rotate keys with a Lambda function.
Session Storage
Redis Cluster:
- Nodes: 3+ master nodes
- Persistence: AOF every 1 second
- Encryption: TLS 1.3
- Password: Redis AUTH
REQ-099-100: Session storage SHALL run on a Redis cluster of at least 3 master nodes, with AOF persistence every 1 second, TLS 1.3 transport, and Redis AUTH password protection.
Audit Storage
Primary: Elasticsearch (hot storage - 90 days) Secondary: S3 Glacier (cold storage - 7 years) Format: JSON with hash chain
REQ-099-101: Audit records SHALL be written as JSON with a hash chain, held in Elasticsearch hot storage for 90 days, and archived to S3 Glacier cold storage for 7 years.
Success Criteria
Authentication
- [ ] Users can authenticate with email/password
- [ ] Users can authenticate with API keys
- [ ] Users can authenticate via OAuth providers
- [ ] Session tokens expire after configured duration
- [ ] Refresh tokens allow seamless re-authentication
REQ-099-102: Authentication SHALL be accepted only when users can authenticate with email and password, with API keys and via OAuth providers, session tokens expire after the configured duration, and refresh tokens allow re-authentication without a fresh login.
Authorization
- [ ] PAM++ queries return correct decisions
- [ ] RBAC enforces role-based permissions
- [ ] Resource-level permissions are enforced
- [ ] Default deny policy blocks unauthorized access
REQ-099-103: Authorization SHALL be accepted only when PAM++ queries return the correct decisions, RBAC enforces role-based permissions, resource-level permissions are enforced, and the default deny policy blocks unauthorized access.
MFA
- [ ] TOTP setup generates unique secrets
- [ ] TOTP verification works correctly
- [ ] Backup codes can be used for recovery
- [ ] Account lockout triggers after threshold
REQ-099-104: MFA SHALL be accepted only when TOTP setup generates unique secrets, TOTP verification succeeds for valid codes, backup codes can be used for recovery, and account lockout triggers at the threshold.
Security
- [ ] Passwords meet complexity requirements
- [ ] API keys are hashed before storage
- [ ] Data is encrypted at rest (AES-256-GCM)
- [ ] All connections use TLS 1.3
- [ ] Token revocation works immediately
REQ-099-105: Security SHALL be accepted only when passwords meet the complexity requirements, API keys are hashed before storage, data at rest is encrypted with AES-256-GCM, all connections use TLS 1.3, and token revocation takes effect immediately.
Audit
- [ ] All authentication events are logged
- [ ] All authorization decisions are logged
- [ ] Audit logs are tamper-resistant
- [ ] Hash chain verification works
- [ ] Logs are retained for 7 years
REQ-099-106: Audit SHALL be accepted only when all authentication events and authorization decisions are logged, audit logs are tamper-resistant, hash-chain verification works, and logs are retained for 7 years.
Rate Limiting
- [ ] Authentication endpoints have stricter limits
- [ ] General endpoints have configurable limits
- [ ] Account lockout triggers after 5 failures
- [ ] Progressive delays prevent brute force
REQ-099-107: Rate limiting SHALL be accepted only when authentication endpoints carry stricter limits, general endpoints carry configurable limits, account lockout triggers after 5 failures, and progressive delays prevent brute-force attempts.
Compliance
- [ ] SOC 2 controls are implemented
- [ ] GDPR Article 32 requirements met
- [ ] PCI DSS 8.2 requirements met
- [ ] NIST AC-2 and IA-5 requirements met
REQ-099-108: Compliance SHALL be accepted only when the SOC 2 controls, GDPR Article 32, PCI DSS 8.2 and NIST AC-2 and IA-5 requirements are met.
Observability
Logging Requirements
- Component Logging
- Log all major operations with appropriate log levels
- Include correlation IDs for request tracing
- Log performance metrics for critical operations
- Log errors with full context for debugging
REQ-099-224: Components SHALL log all major operations at appropriate log levels, SHALL include correlation IDs for request tracing, SHALL log performance metrics for critical operations, and SHALL log errors with full context.
Metrics Requirements
- Performance Metrics
- Operation duration histograms
- Request/error rate counters
- Resource utilization gauges
- Business metrics relevant to domain
REQ-099-225: The system SHALL expose operation duration histograms, request and error rate counters, resource utilization gauges, and business metrics relevant to the domain.
Tracing Requirements
- Distributed Tracing
- Trace propagation across component boundaries
- Span attributes for domain-specific context
- Trace sampling based on operational needs
REQ-099-226: The system SHALL propagate traces across component boundaries, SHALL attach domain-specific span attributes, and SHALL sample traces according to operational needs.
Alerting Requirements
- Critical Alerts
- Error rate spikes
- Performance degradation
- Resource exhaustion
- Business metric anomalies
REQ-099-227: The system SHALL raise critical alerts on error-rate spikes, performance degradation, resource exhaustion, and business-metric anomalies.
Dashboard Requirements
- Operational Dashboard
- Real-time system health
- Performance trends
- Error analysis
- Resource monitoring
REQ-099-228: The operational dashboard SHALL present real-time system health, performance trends, error analysis and resource monitoring.
Visual Architecture
Class Diagram
Diagram source shown as text: Mermaid could not parse it (Error: Parse error on line 11:).
classDiagram-direction LR
class GovernanceEngine {
+__init__()
#_load_default_policies(): dict[str, Any]
+async check(action: str, context: dict[str, Any]): bool
#async _check_edit_file(context: dict[str, Any]): bool
#async _check_create_project(context: dict[str, Any]): bool
#async _check_execute_command(context: dict[str, Any]): bool
}
PAM++ Authentication
# PAM++ client configuration
PAM_CONFIG = {
"host": "pam.orchestrata.local",
"port": 8080,
"auth": {
"type": "api_key",
"key": os.environ["PAM_API_KEY"]
},
"timeout": 5.0
}
async def authenticate_with_pam(user_id: str, credentials: dict):
"""Authenticate user with PAM++."""
async with httpx.AsyncClient() as client:
response = await client.post(
f"http://{PAM_CONFIG['host']}:{PAM_CONFIG['port']}/auth",
json={
"user_id": user_id,
"credentials": credentials
},
headers={"Authorization": f"Bearer {PAM_CONFIG['auth']['key']}"}
)
return response.json()
REQ-099-109: The PAM++ client SHALL be configured with the PAM++ host, port, API-key authentication and a 5.0-second timeout, and SHALL authenticate a user by posting the user id and credentials to the PAM++ /auth endpoint with the API key as a bearer token.
Error Handling
# PAM++ unavailable fallback
if pam_error:
if error_type == "timeout":
# Allow access, log event
await log_event("PAM_TIMEOUT_ALLOW", user_id)
elif error_type == "unavailable":
# Deny access
raise PAMUnavailableError("Authorization service unavailable")
REQ-099-110: On a PAM++ timeout the system SHALL log a PAM_TIMEOUT_ALLOW event and allow access; when PAM++ is unavailable the system SHALL deny access by raising PAMUnavailableError.
Rate Limiting Granularity
Per-Endpoint Limits
ENDPOINT_LIMITS = {
"/api/v1/auth/login": {"requests": 5, "window": 300},
"/api/v1/auth/verify_mfa": {"requests": 10, "window": 60},
"/api/v1/intent": {"requests": 30, "window": 60},
"/api/v1/agents/*": {"requests": 60, "window": 60}
}
REQ-099-111: Per-endpoint rate limits SHALL be enforced as 5 requests per 300 seconds on /api/v1/auth/login, 10 per 60 seconds on /api/v1/auth/verify_mfa, 30 per 60 seconds on /api/v1/intent, and 60 per 60 seconds on /api/v1/agents/*.
Account Lockout Policy
LOCKOUT_THRESHOLD = 5 # failed login attempts
LOCKOUT_DURATION = 1800 # 30 minutes
# Progressive delays
LOGIN_DELAY_BASE = 1 # 1 second
LOGIN_DELAY_MAX = 64 # 64 seconds
REQ-099-112: Accounts SHALL be locked after 5 failed login attempts for 1800 seconds, and login delays SHALL progress from a 1-second base up to a 64-second maximum.
Audit Log Tamper Resistance
Write-Once Read-Many (WORM)
import hashlib
async def write_audit_log(entry: dict):
"""Write audit log with tamper resistance."""
# Add hash chain
previous_hash = await get_last_audit_hash()
entry["previous_hash"] = previous_hash
entry["timestamp"] = datetime.utcnow().isoformat()
# Calculate entry hash
entry_content = json.dumps(entry, sort_keys=True)
entry["hash"] = hashlib.sha256(entry_content.encode()).hexdigest()
# Store in WORM storage (immutable)
await storage.append("audit_log", entry)
return entry["hash"]
REQ-099-113: Each audit entry SHALL carry the previous entry's hash and a timestamp, SHALL be hashed with SHA-256 over its canonically-sorted JSON content, and SHALL be appended to immutable WORM storage.
Hash Chain Verification
async def verify_audit_chain():
"""Verify integrity of audit log chain."""
entries = await storage.read("audit_log")
for i in range(1, len(entries)):
current = entries[i]
previous = entries[i - 1]
# Verify hash chain
computed_hash = hashlib.sha256(
json.dumps(current, sort_keys=True).encode()
).hexdigest()
if current["hash"] != computed_hash:
raise AuditLogTamperError(f"Tamper detected at entry {i}")
if current["previous_hash"] != previous["hash"]:
raise AuditLogTamperError(f"Chain broken at entry {i}")
REQ-099-114: Audit-chain verification SHALL recompute every entry's hash and SHALL raise a tamper error when an entry's hash does not match its content or its recorded previous hash does not match the preceding entry.
Password Policy
Requirements
PASSWORD_POLICY = {
"min_length": 12,
"max_length": 128,
"require_uppercase": True,
"require_lowercase": True,
"require_numbers": True,
"require_special": True,
"disallow_common": True,
"disallow_personal": True # Don't use email, name, etc.
}
REQ-099-115: Passwords SHALL be at least 12 and at most 128 characters, SHALL contain uppercase, lowercase, numeric and special characters, and SHALL be rejected when they match a common password or contain the user's personal information.
Validation
def validate_password(password: str, user_info: dict) -> bool:
"""Validate password against policy."""
if len(password) < PASSWORD_POLICY["min_length"]:
return False
if not re.search(r'[A-Z]', password):
return False
if not re.search(r'[a-z]', password):
return False
if not re.search(r'[0-9]', password):
return False
if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
return False
# Check against common passwords
if password.lower() in COMMON_PASSWORDS:
return False
# Check against personal info
for value in user_info.values():
if isinstance(value, str) and value.lower() in password.lower():
return False
return True
Compliance Mapping
| Control | Implementation |
|---|---|
| SOC 2 CC6.1 - Logical Access | PAM++ authorization, MFA |
| SOC 2 CC6.2 - User Provisioning | User lifecycle management |
| SOC 2 CC6.6 - Password Policy | Password validation, hashing |
| GDPR Art. 32 - Security | Encryption at rest and in transit |
| PCI DSS 8.2 - Authentication | Strong authentication, MFA |
| NIST AC-2 - Account Management | Automated provisioning/deprovisioning |
| NIST IA-5 - Authenticator Management | TOTP, backup codes, rotation |
Authentication
Authentication Methods
| Method | Use Case | Security Level |
|---|---|---|
| API Key | CLI, scripts | High |
| OAuth 2.0 | Web UI | High |
| Session Token | Web UI (remember me) | Medium |
| Service Account | Internal services | High |
REQ-099-116: The system SHALL support API-key authentication for CLI and scripts, OAuth 2.0 for the web UI, session tokens for persistent web-UI login, and service-account authentication for internal services.
API Key Authentication
Header Format:
Authorization: Bearer sk_abc123def456
Key Format:
- Prefix:
sk_(secret key) - Length: 32 characters minimum
- Charset: alphanumeric + underscore
Key Generation:
def generate_api_key() -> str:
return "sk_" + secrets.token_urlsafe(32)
REQ-099-117: An API key SHALL be presented as Authorization: Bearer <key>, SHALL carry the sk_ prefix, SHALL be at least 32 characters drawn from alphanumeric characters and underscore, and SHALL be generated from a cryptographically secure URL-safe random source.
OAuth 2.0 Integration
Supported Providers:
- GitHub
- GitLab
OAuth Flow:
- User clicks "Login with GitHub"
- Redirect to GitHub OAuth
- GitHub calls back with code
- Exchange code for token
- Create session, redirect to app
REQ-099-118: The OAuth 2.0 flow SHALL redirect the user to the provider, SHALL accept the provider's callback code, SHALL exchange that code for a token, and SHALL then create a session and redirect the user back to the application.
Session Management
Session Token:
- Format: JWT
- Expiry: 24 hours (configurable)
- Refresh: 7 days with refresh token
Session Storage:
- Redis for distributed sessions
- Encrypted at rest
REQ-099-119: The session token SHALL be a JWT expiring after a configurable 24 hours with a 7-day refresh token, and sessions SHALL be stored in Redis for distributed access and encrypted at rest.
Authorization
PAM++ Integration
The system integrates with PAM++ (Prolog Authorization Manager) for authorization decisions.
Authorization Flow:
Request → Auth Middleware → PAM++ Query → Decision → Handler
PAM++ Query Structure:
can_perform(
User: user_123,
Action: edit_file,
Resource: file:///project/src/main.py,
Context: #{
timestamp: now,
ip: "192.168.1.1",
method: post
}
) -> Decision
Permission Levels
| Level | Scope | Example |
|---|---|---|
| Global | System-wide | admin, auditor |
| Project | Specific project | project_admin, developer |
| Resource | Specific resource | file_owner |
| Action | Specific action | can_deploy |
Roles
Built-in Roles:
admin: Full system accessauditor: Read-only access to audit logsproject_admin: Manage project configurationdeveloper: Read/write code, create tasksviewer: Read-only project accessguest: Minimal access, public projects
REQ-099-120: The system SHALL provide the built-in roles admin (full system access), auditor (read-only access to audit logs), project_admin (manage project configuration), developer (read/write code, create tasks), viewer (read-only project access) and guest (minimal access to public projects).
Encryption
Data Encryption
At Rest:
- Database fields: AES-256-GCM
- File storage: Encrypted filesystem
- Backups: Encrypted with key vault
REQ-099-121: Data at rest SHALL be encrypted: database fields with AES-256-GCM, file storage on an encrypted filesystem, and backups with a key from the key vault.
In Transit:
- All HTTP: TLS 1.3
- WebSocket: WSS
- Internal: mTLS
REQ-099-122: Data in transit SHALL be encrypted: all HTTP over TLS 1.3, all WebSocket traffic over WSS, and all internal traffic over mTLS.
Key Management
Key Types:
- Master Key: Stored in HSM or secure vault
- Data Encryption Keys (DEK): Encrypted by master key
- API Keys: Hashed with bcrypt
REQ-099-123: The master key SHALL be held in an HSM or secure vault, data encryption keys SHALL be encrypted by the master key, and API keys SHALL be stored hashed with bcrypt.
Key Rotation:
- Master key: Annual (manual)
- DEK: Monthly (automatic)
- API keys: On compromise or annual
REQ-099-124: The master key SHALL be rotated annually by manual action, data encryption keys SHALL be rotated monthly and automatically, and API keys SHALL be rotated on compromise or annually.
Secrets Management
Supported Backends:
- HashiCorp Vault
- AWS Secrets Manager
- Environment variables (development only)
REQ-099-125: Secrets management SHALL support HashiCorp Vault and AWS Secrets Manager as backends, and environment variables SHALL be used as a secrets backend in development only.
Security Middleware
Authentication Middleware
class AuthMiddleware:
"""Authenticates requests and attaches user context."""
async def __call__(self, request, handler):
# Extract token from header
token = «redacted»
# Validate token
user = await self.validate_token(token)
# Attach user to request
request.user = user
# Continue to handler
return await handler(request)
REQ-099-126: The authentication middleware SHALL extract the token from the request header, SHALL validate it, and SHALL attach the resolved user to the request before the handler runs.
Authorization Middleware
class AuthorizationMiddleware:
"""Enforces PAM++ authorization."""
async def __call__(self, request, handler):
# Get required permission from route
permission = self.get_required_permission(request)
# Check with PAM++
decision = await self.pam.check(
user=request.user,
permission=permission,
resource=request.path
)
if not decision.allowed:
raise ForbiddenError(decision.reason)
return await handler(request)
REQ-099-127: The authorization middleware SHALL determine the permission required by the route, SHALL check it against PAM++ for the request user and resource, and SHALL reject the request with the decision's reason when access is not allowed.
Rate Limiting Middleware
class RateLimitMiddleware:
"""Enforces per-user rate limits."""
async def __call__(self, request, handler):
# Get user identifier
user_id = self.get_user_id(request)
# Check rate limit
if not await self.ratelimiter.check(user_id):
raise RateLimitError(
retry_after=self.ratelimiter.retry_after(user_id)
)
return await handler(request)
REQ-099-128: The rate-limiting middleware SHALL identify the requesting user, SHALL check that user's rate limit, and SHALL reject the request with a retry-after value when the limit is exceeded.
Audit Logging
Audit Events
| Event Type | Data Captured |
|---|---|
| Authentication | User, method, IP, result |
| Authorization | User, permission, resource, decision |
| Data Access | User, resource, action |
| Data Modification | User, resource, old_value, new_value |
| Configuration | User, setting, old_value, new_value |
| Security | Event type, details, severity |
REQ-099-129: The audit log SHALL capture, for authentication the user, method, IP and result; for authorization the user, permission, resource and decision; for data access the user, resource and action; for data modification the user, resource, old value and new value; for configuration changes the user, setting, old value and new value; and for security events the event type, details and severity.
Audit Log Format
{
"event_id": "evt_123456789",
"event_type": "authorization",
"timestamp": "2026-04-08T14:30:00Z",
"user": {
"id": "user_123",
"role": "developer"
},
"action": "edit_file",
"resource": "file:///project/src/main.py",
"decision": "allow",
"context": {
"ip": "192.168.1.1",
"user_agent": "curl/7.68.0",
"method": "POST"
},
"governance": {
"policy_id": "POL-001",
"rule_id": "RULE-010",
"matched": true
}
}
REQ-099-130: Each audit entry SHALL carry event_id, event_type, timestamp, the acting user's id and role, action, resource, decision, the request context (IP, user agent, method) and the governance policy id, rule id and match flag.
Audit Retention
- Hot Storage: 90 days (searchable)
- Cold Storage: 7 years (archive)
- PII Redaction: After 1 year
REQ-099-131: Audit records SHALL be searchable in hot storage for 90 days, archived for 7 years, and SHALL have personally identifiable information redacted after 1 year.
Security Configuration
Configuration Schema
{
"security": {
"authentication": {
"methods": ["api_key", "oauth2"],
"session": {
"expiry_seconds": 86400,
"refresh_expiry_seconds": 604800
},
"oauth2": {
"providers": ["github", "google"],
"client_id": "${OAUTH_CLIENT_ID}",
"client_secret": "${OAUTH_CLIENT_SECRET}"
}
},
"authorization": {
"enabled": true,
"policy_engine": "pam++",
"default_policy": "deny"
},
"encryption": {
"algorithm": "AES-256-GCM",
"key_rotation_days": 30,
"vault_backend": "hashicorp"
},
"rate_limiting": {
"enabled": true,
"default_limit": 60,
"burst_limit": 10
},
"audit": {
"enabled": true,
"retention_days": 2555,
"hot_storage_days": 90
}
}
}
REQ-099-132: The security configuration SHALL accept the enabled authentication methods, a session expiry of 86400 seconds and refresh expiry of 604800 seconds, the OAuth 2.0 providers and credentials, an authorization block with pam++ as policy engine and deny as default policy, an encryption block with AES-256-GCM and a 30-day key rotation against the configured vault backend, a rate-limiting block with default and burst limits, and an audit block with 2555-day retention and 90-day hot storage.
Environment Variables
| Variable | Description |
|---|---|
SECRET_KEY |
Master encryption key |
OAUTH_CLIENT_ID |
OAuth app client ID |
OAUTH_CLIENT_SECRET |
OAuth app client secret |
VAULT_ADDR |
HashiCorp Vault address |
VAULT_TOKEN |
Vault authentication token |
REQ-099-133: The system SHALL read SECRET_KEY for the master encryption key, OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET for the OAuth application credentials, and VAULT_ADDR and VAULT_TOKEN for the HashiCorp Vault address and authentication token.
Error Handling
Authentication Errors
| Code | Message | HTTP Code |
|---|---|---|
| AUTH-001 | Invalid API key | 401 |
| AUTH-002 | API key expired | 401 |
| AUTH-003 | Session expired | 401 |
| AUTH-004 | OAuth failed | 401 |
REQ-099-134: Authentication failures SHALL be reported as AUTH-001 invalid API key, AUTH-002 API key expired, AUTH-003 session expired and AUTH-004 OAuth failed, each with HTTP status 401.
Authorization Errors
| Code | Message | HTTP Code |
|---|---|---|
| AUTHZ-001 | Access denied | 403 |
| AUTHZ-002 | Governance blocked | 451 |
| AUTHZ-003 | Insufficient permissions | 403 |
REQ-099-135: Authorization failures SHALL be reported as AUTHZ-001 access denied with HTTP status 403, AUTHZ-002 governance blocked with HTTP status 451, and AUTHZ-003 insufficient permissions with HTTP status 403.
Error Response Format
{
"error": {
"code": "AUTHZ-001",
"message": "Access denied",
"details": {
"reason": "User role 'viewer' does not have 'edit' permission",
"resource": "file:///project/src/main.py",
"policy": "POL-001"
},
"request_id": "req_123456789"
}
}
REQ-099-136: Every error response SHALL carry the error code, the message, the details (reason, resource and policy) and the request id.
Testing Requirements
Security Tests
- [ ] Authentication with valid credentials succeeds
- [ ] Authentication with invalid credentials fails
- [ ] Authorization blocks unauthorized actions
- [ ] Authorization allows authorized actions
- [ ] Rate limiting triggers at threshold
- [ ] Audit logs capture all security events
- [ ] Encryption at rest works correctly
- [ ] Session expiry works correctly
REQ-099-229: The security test suite SHALL prove that authentication succeeds with valid credentials and fails with invalid ones, that authorization blocks unauthorized actions and allows authorized ones, that rate limiting triggers at the threshold, that audit logs capture all security events, that encryption at rest works, and that session expiry works.
Penetration Testing
- SQL injection prevention
- XSS prevention
- CSRF prevention
- Path traversal prevention
- Command injection prevention
REQ-099-230: The system SHALL prevent SQL injection, cross-site scripting, cross-site request forgery, path traversal and command injection, and penetration testing SHALL cover each of them.
Compliance
Standards
- OWASP Top 10
- SOC 2 Type II
- GDPR (data handling)
- CCPA (data handling)
REQ-099-231: The system SHALL conform to the OWASP Top 10, SOC 2 Type II, the GDPR data-handling requirements and the CCPA data-handling requirements.
Security Headers
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
REQ-099-137: Responses SHALL carry the security headers Strict-Transport-Security: max-age=31536000; includeSubDomains, Content-Security-Policy: default-src 'self', X-Content-Type-Options: nosniff, X-Frame-Options: DENY, X-XSS-Protection: 1; mode=block and Referrer-Policy: strict-origin-when-cross-origin.
Incident Response
Security Incident Classification
| Severity | Description | Response Time |
|---|---|---|
| Critical | Data breach, full system compromise | 1 hour |
| High | Unauthorized access, privilege escalation | 4 hours |
| Medium | Policy violation, suspicious activity | 24 hours |
| Low | Minor security concern | 7 days |
REQ-099-138: Security incidents SHALL be classified and answered within the stated response times: critical (data breach or full system compromise) within 1 hour, high (unauthorized access or privilege escalation) within 4 hours, medium (policy violation or suspicious activity) within 24 hours, and low (minor security concern) within 7 days.
Incident Response Steps
- Detect: Identify security event
- Contain: Limit damage
- Eradicate: Remove threat
- Recover: Restore normal operation
- Document: Record incident details
- Review: Improve defenses
REQ-099-139: Incident response SHALL follow the steps detect, contain, eradicate, recover, document and review.
Dependencies
| Dependency | Version | Purpose |
|---|---|---|
| PyJWT | >=2.8 | JWT handling |
| passlib | >=1.7 | Password hashing |
| cryptography | >=41.0 | Encryption |
| httpx | >=0.25 | HTTP client |
| structlog | >=24.0 | Structured logging |
REQ-099-140: The framework SHALL depend on PyJWT >=2.8 for JWT handling, passlib >=1.7 for password hashing, cryptography >=41.0 for encryption, httpx >=0.25 for HTTP requests, and structlog >=24.0 for structured logging.
Data Models
User
{
"user": {
"id": "user_123",
"email": "user@example.com",
"name": "John Doe",
"role": "developer",
"projects": ["proj_001", "proj_002"],
"created_at": "2026-01-01T00:00:00Z",
"last_login": "2026-04-08T14:00:00Z",
"mfa_enabled": true
}
}
API Key
{
"api_key": {
"id": "key_abc123",
"user_id": "user_123",
"name": "Development",
"prefix": "sk_abc",
"permissions": ["read", "write"],
"created_at": "2026-04-01T00:00:00Z",
"expires_at": "2027-04-01T00:00:00Z",
"last_used": "2026-04-08T14:00:00Z"
}
}
Session
{
"session": {
"id": "sess_xyz789",
"user_id": "user_123",
"refresh_token": "rt_...",
"expires_at": "2026-04-09T14:00:00Z",
"ip_address": "192.168.1.1",
"user_agent": "Mozilla/5.0...",
"created_at": "2026-04-08T14:00:00Z"
}
}