KoniKodeKnowledge BaseMy AccountOpen website

KNOWLEDGE BASE

Documentation

DOCUMENTATION
CURRENT APPLICATIONClean Framework
DocumentationClean Framework

Clean Framework · DOCUMENTATION

Authentication and security

Authentication and security

Bounded candidate reference — 2026-10-20: 0.2.0-rc.1 is committed locally through 84f415b3098af5653577b2c65eea31fca21df79c, unpublished and not production-approved; stable PHP >=8.5.11 <8.6.0 is required. This is documentation, not adoption: this knowledge base retains its installed 0.1.0-rc.1 dependency and PHP 8.2.11 local profile. Dated PHP 8.2 evidence is historical; earlier dirty-source reports retain their original test provenance, not retroactive clean-commit proof. Candidate examples are illustrative: API signatures were reviewed, but candidate code was not executed by this editorial update. See current checkpoint, open criteria and adoption boundary.

See audit search for independent record/byte/result ceilings and strict private Linux semantics. Q03 scanner/quarantine adds source identity, state/lock checks, post-inspector/post-audit revalidation and no-replace publication, not same-UID containment.

See the threat model for trust boundaries, dated findings and deployment ownership. Daniel Horowitz is assigned the independent review role; actual independence confirmation and a dated disposition remain absent. An assigned title is not a security signoff. Next-candidate changes reject exact-expiry OAuth proofs, malformed CSRF values, ambiguous/oversized/control-bearing headers, and bounded-log sensitive-key variants. Operational log messages are now stable event codes, not free text; PII/private payloads must never be passed under arbitrary innocent keys.

The framework defines generic boundaries, not identities or business roles. Applications own credential verification, principal lookup, password/reset workflows, permissions, and object-level policy.

Browser sessions

SessionManager depends on the replaceable SessionStore contract. Its default NativePhpSessionStore starts PHP sessions lazily with strict/cookie- only mode, HttpOnly cookies, configurable Secure/SameSite/path/domain policy, and private application-selected storage. Login, privilege changes, namespace version changes, expiration, and logout invalidate or regenerate identifiers. Login and privilege changes also invalidate the old CSRF proof.

Idle and absolute expiry are independent. SessionInventory receives only a SHA-256 fingerprint of the bearer identifier and safe lifecycle metadata; an application can use it to inventory devices or invalidate every session after a permission change. The raw session identifier must never be logged or stored through inventory. Signed webhooks and machine endpoints do not use sessions.

Production applications must use HTTPS, secureCookie=true, a non-default session name, protected/shared session storage where required, and host-level cookie/domain controls. Session records contain only a neutral principal ID, permissions, scalar attributes, authentication method, and timestamp.

CSRF

CsrfTokenManager creates 32 random bytes, stores the hexadecimal token in the session, validates with hash_equals, and can rotate it. CsrfMiddleware checks POST/PUT/PATCH/DELETE tokens from X-CSRF-Token or an application field. A missing/stale token produces status 419 before the handler runs. CsrfExemptionRegistry permits only enumerable named-route exemptions with a documented alternative verification mechanism. It does not accept path-prefix or caller-selected exemptions.

Passwords, recovery, remembered login, and MFA

NativePasswordHasher uses PASSWORD_DEFAULT, password_verify, and rehash-on-success. CredentialVerifier keeps application identifiers, account state, and repositories outside the framework.

PasswordResetTokens issues 32 random bytes and passes only a SHA-256 digest, subject, and expiry to PasswordResetTokenStore. The included single-host file store atomically consumes and removes a token so it is one-time. Public reset controllers must always return the same response regardless of whether the application recognizes the supplied account identifier.

RememberedCredentials uses selector/token separation. Stores retain the selector, token digest, principal identifier, and expiry—never the plaintext token. Consumption is atomic, removes the old selector before verification, and returns a mandatory rotated credential after success. Logout can receive a revocation callback, and applications can revoke all remembered credentials after password, MFA, role, or account-state changes. Staff remembered-login policy remains application-owned.

MfaProvider and RecoveryCodeService are optional ports. Enrollment, disablement, and recovery workflows must apply recent authentication, rate limiting, and append-only audit in application services.

Authorization

AuthenticationMiddleware attaches a Principal or returns 401. The original request-oriented AuthorizationMiddleware remains available for concise route policy. AuthorizationGate is the richer deny-by-default boundary for use cases: its rules receive the principal, ability, exact resource, and an AuthorizationContext containing explicit scopes, approvals, amount/risk, and correlation metadata. PolicyAuthorizationGate audits every denial through an append-only sink.

ApprovalPolicy enforces distinct approvers, separation from the requester and actor, and amount thresholds. RecoveryAuthorityPolicy demonstrates the application-configurable final-holder invariant. Neither class hard-codes role names. Sensitive operations can add RecentAuthenticationMiddleware or use RecentAuthenticationPolicy directly.

Always enforce object ownership and tenant boundaries in an application policy or use case; possession of a broad role is not sufficient by itself.

Administrative and public-form controls

AdministrativeCredentialMiddleware requires HTTPS by default, accepts a Bearer credential from the Authorization header only, can enforce a scope and rate limiter, emits private/no-store responses, and records structured grant/denial metadata. RotatingMachineCredentialSet adds an identifier, digest-at-rest secret, explicit scopes, environment isolation, activation, expiry, revocation, and overlap through multiple active records. It exposes only safe identity/scope metadata to the downstream request.

RateLimiter and AntiBotVerifier are provider-neutral ports. FileRateLimiter is atomic on one host. DatabaseRateLimiter uses a locked row and application-owned cf_rate_limits-compatible migration for shared fixed-window limits. Real multi-connection concurrency remains TO VERIFY on an isolated MySQL/MariaDB service. AntiBotMiddleware fails closed, while provider network adapters remain application-owned.

OAuth authorization, S256 PKCE, environment-bound encrypted provider credentials, rotation, and refresh locking are documented separately in PROVIDERS_AND_WEBHOOKS.md; they do not replace application user sessions or the authenticator/authorization contracts in this document.

Audit, privacy, retention, and protected uploads

AuditEvent accepts bounded scalar metadata and before/after fields and rejects keys associated with passwords, secrets, tokens, cookies, authorization, sessions, CSRF, OAuth, private media, and request bodies. FileAuditSink is an append-only locked single-host adapter with bounded search and no historical update/delete API. Critical database mutation plus audit must commit in one transaction or through a transactional outbox.

See file audit search for the independent result/work limits, 100,000-record/64 MiB batches, million-record/640 MiB total ceiling, opaque exhaustion, writer opportunities and trusted append-only boundary assumptions. The optional file adapter also enforces the approved private Linux/single-owner profile, with explicit compatibility limits and local-only qualification. This is not a requirement for every framework logger, an atomic-nofollow guarantee, independent security review or deployment approval.

Missing audit files retain the owner-approved compatible [] response; this does not establish that no history was lost. The deferred audit capability ledger tracks strict initialized-history review, cryptographic chaining, fsync/power- loss durability, multi-node audit and file-plus-SQL atomicity separately. None is established by valid JSON framing, checked file modes or a green SQL fixture.

The Privacy namespace defines the required data classifications and a retention coordinator for purge, anonymize, and detach policy. Dry runs never mutate. Holds always win. Live runs require approval and checkpoint references, and RetentionRepository::applyWithAudit() makes the application adapter own mutation plus audit atomically.

Private uploads use FileinfoUploadInspector, an application-supplied MalwareScanner, and InspectedUploadService before PrivateStorage publication. Client filenames/media types remain display hints. Protected reads continue through object-level PrivateObjectPolicy, contained file resolution, private/no-store responses, and optional ranges.

Not included

The package does not include an account schema, login/reset controller, user or password repository, role names, email/SMS delivery, provider challenge adapter, malware engine, retention schedule, or object policy. The framework supplies mechanisms and secure contracts; each application composes its own identity, lawful-purpose, resource, and operational policy.

Editorial provenance

Source: docs/AUTHENTICATION_AND_SECURITY.md. Source SHA-256: f73830b2c9876abfc7a2d020ae1408ee4281d988fb09ea919ea8db48d429bf16.

Framework candidate reference; editorial checkpoint 2026-10-20. See candidate status and adoption boundary.

EXPLORE FURTHER

Drag a divider or use Left and Right Arrow keys to resize. Hold Shift for larger steps. Enter hides or restores the sidebar; Home and End select its minimum or maximum width. Double-click resets the width.