johnnickell / fight-access-control
Framework-neutral identity, credential, session, authorization, and account-lifecycle contracts
Package info
github.com/johnnickell/fight-access-control
pkg:composer/johnnickell/fight-access-control
Requires
- php: >=8.5
- johnnickell/fight-common: ^1.2
Requires (Dev)
- deptrac/deptrac: ^4.7
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^13.0
- rector/rector: ^2.4
- slevomat/coding-standard: ^8.27
- squizlabs/php_codesniffer: ^4.0
- symfony/process: ^7.0
- zircote/swagger-php: ^6.5
Suggests
- zircote/swagger-php: Generate a consumer-owned OpenAPI document from the opt-in openapi/ component catalog.
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-05 16:59:36 UTC
README
Framework-neutral identity, credential, session, authorization, and account-lifecycle contracts for Fight applications.
Only the current pre-v1 API and persisted contract are supported; see ADR 0011. There are no historical readers, legacy modes or migration/backfill routes. Credential delivery is recoverable and provider-neutral for invitation, password reset and email change.
The v0.4.0 release introduces the pre-1.0 Permission tier contract and requires consumer persistence and projection adoption; see the current Permission tier contract. Package publication does not certify a consumer schema or establish consumer adoption.
The 0.2.0 release adds an opt-in, non-autoloaded OpenAPI component catalog
for consumer-owned documents. See OpenAPI composition.
The 0.1.x release line provides the first public-source package milestone while the API remains intentionally
pre-1.0.0. It delivers the framework-neutral Domain and Application behavior described by the repository-local
product specifications; consumer projects continue to own framework and infrastructure adapters. Tagged package
versions intentionally precede full starter implementation so those projects can integrate against immutable
version tags and return compatibility findings through later 0.x releases.
Package boundary
Production code follows Domain <- Application:
Domaincontains framework-independent business concepts and depends on no other package layer.Applicationcoordinates use cases through Domain types and public Fight Common contracts.- Application owns the supported access-JWT/opaque-refresh authentication lifecycle through Fight Common ports, while consumer repositories own clients, framework integration, persistence, HTTP, cookies, signing-key configuration, mail, queues, realtime, hosting, and composition-root adapters. This package has no PHP production Adapter layer.
See CONTEXT.md for the accepted vocabulary and TICKET-00001 for the repository-local behavioral and security authority.
Transaction composition
Transaction-aware Application handlers and security services require Fight Common's supported
TransactionalUnitOfWork contract. Consumer composition roots must supply an implementation whose
commitTransactional() callback encloses the complete package-owned atomic operation and whose isClosed() reports
whether that transaction capability remains available. The deprecated UnitOfWork contract and its standalone
commit() method are not supported by AccessControl constructors.
Only the current transactional contract is supplied; no compatibility adapter is included.
Recoverable credential delivery composition
See the current credential-delivery guide for persistence, explicit claim/outcome contracts, worker composition and executable qualification evidence.
Invitation, password-reset, and email-change credentials use package-owned recoverable delivery state. Consumers
supply the three purpose-specific cipher capabilities, one provider-neutral CredentialDeliveryProvider, the Domain
repositories on the shared transactional connection, and worker scheduling. The package supplies direct
DeliverUserInvitationHandler, DeliverPasswordResetHandler, and DeliverEmailChangeHandler registrations plus
FindDueCredentialDeliveriesHandler and FindCredentialDeliveryStatusHandler query registrations.
An originating handler atomically commits its grant and encrypted delivery generation before publishing its existing
success event. A delivery handler then commits an exact claim, decrypts and invokes the provider only after that
transaction closes, and records the typed delivered, retryable, or permanent outcome in a separate expected-state
transaction. Provider adapters receive a short-lived CredentialDeliveryInvocation; its immutable delivery ID is the
idempotency identity. They must return CredentialDeliveryOutcome and must not embed vendor diagnostics in package
state. Unexpected provider throwables become the package's secret-free retryable classification.
Consumers may use post-commit event subscribers for immediate dispatch, but must schedule
FindDueCredentialDeliveries for restart recovery and dispatch the matching direct command using the returned
purpose, User ID, and delivery ID. Pending work, due retries, and expired leases are returned in deterministic order.
A crash after provider acceptance and before outcome commit can repeat the provider call with the same identity, so
this contract is at-least-once and does not claim exactly-once delivery.
Feature declarations, preparation and availability (unreleased)
The Feature reference guide describes strict FeatureName validation, method-only
FeatureFlag metadata, explicit registration and scoped complete/unavailable discovery.
Atomic provisioning creates only missing candidate references OFF with an existing
Permission, preserving stored choices and retrying from authoritative state. Completion is not activation readiness.
Preparation validation rereads all complete candidate references and their stored
Permission identities without mutation. Feature availability checks current stored
status and Permission ID against an existing User/Agent snapshot or anonymous input on each explicit call; availability
never authorizes the underlying action. Management,
Permission reference guards and
current-reference retirement supply the package lifecycle; the
scenario/evidence inventory distinguishes preceding acceptance from TASK-00067's
pending independent review/QA. Consumer adapters, scanning, UI and runtime enforcement remain consumer-owned and
unqualified. Neither a package pass, preparation nor provisioning grants deployment permission or constitutes a
supported partial Feature release.
Agent credential operations (unreleased)
Start with the current Agent integration guide for composition, readiness, bounded recovery and restoration. The complete scenario/evidence inventory maps all 25 proposal scenarios and ratified outcome/bounds additions to current package tests and explicit consumer gaps. The target is v0.5.0; this checkout is not a release receipt or consumer qualification.
The unreleased provisioning replacement requires a retained scoped operation key, registered destination, and
same-transaction authorization participation. It prepares encrypted delivery and returns only safe issuance metadata;
retry resolves the same outcome after response loss. See the
provisioning contract for composition, finite defaults, failure semantics,
persistence requirements and executable evidence. GetAgentOperation provides an
authorized safe status query, separating original issuance from recorded delivery
and credential disposition without a transaction, material access or events.
Credential retirement atomically revokes authority and cancels original delivery
through both service and direct repository writes without key/sink access.
Protected delivery adds committed claim/admission, outside-transaction fixed-sink
invocation and exact receipt acknowledgement under current authority.
Recoverable rotation commits a correlated successor with atomic predecessor
cancellation and resolves the original request after response loss. Retired raw-return rotation APIs are removed.
Discovery and restart recovery provide a bounded currently delegated scheduler
pass and receipt-first reconciliation through the actual protected delivery path, without caller retry or events.
Discovery excludes obsolete slot reservations before limiting so they cannot starve the current authorized write.
Material maintenance adds authorized rewrapping, global diagnostic key-reference
counts, retention expiry and replay-safe inert-entry cleanup. A zero reference count never authorizes key destruction;
current delivered credentials are excluded from cleanup.
Issuance-recovery conformance exposes consumer-bindable tests and exercises both
issuance paths through scheduler-only restart, status and cleanup using behavioral adapters. It does not qualify a
real database, sink or consumer activation/use path.
Protected-delivery conformance adds consumer-bindable authority/lifecycle,
transaction, key and sink qualification scenarios, running both receipt-lookup and repeated-invocation profiles.
The current Agent model has no legacy mode or recovery marker. Validated hydration
preserves authority; every lifecycle write requires operation correlation and atomic cancellation.
Operation cohorts require persisted version/capability qualification and a shared
transaction-duration cohort fence across every writer. Cohort generations fence delivery/cleanup acknowledgements;
consumers must separately exclude old binaries at storage or a trusted boundary and qualify real writer races.
The canonical operation contract uses one Unicode-aware normalization rule
and persisted marker 2, preserving original keys through restart, delivery, retirement and cleanup. There is no
historical reader, runtime version selection or migration of nonexistent earlier-version operations. Unsupported
markers reject without fallback; current authorization, transaction and ordering fences remain mandatory.
Restoration safety requires independent reconciled-generation evidence at the
existing cohort boundary. Stale restored state remains unavailable until original operation/receipt/tombstone/order
history is reconciled for the exact active storage incarnation at a newer generation. Consumer-bindable scenarios
model restore and forward repair; no backup tool, migration engine or automatic rollback detector is supplied.
Package restoration and TASK-00059's final integration guidance/traceability are independently accepted;
the guidance also passed behavioral QA. These modeled interleavings do not qualify real consumer adapters, restore
procedures or activation/use. The unreleased composition is not a qualified consumer deployment; release,
consumer adoption and deployment remain separate gates. Existing released versions are unchanged.
Current principal composition
Consumers implement AuthenticationContextProvider to expose only the authenticated User ID, refresh-session ID,
and authentication version for the current request. The composition root must create a new
CurrentPrincipalProvider for each request with that context provider and the package
AuthoritativePrincipalResolver. Application handlers use CurrentPrincipalProvider; its first lookup resolves
all principal roles and permissions from authoritative repositories and later lookups in the same request return
that cached result. Consumers cannot inject role or permission snapshots through this boundary.
After a consumer-owned framework adapter selects and resolves the request's authentication path, its composition
root creates one SecurityContext from exactly one AuthenticatedUserPrincipal or
AuthenticatedAgentPrincipal. The context exposes that authority's type and delegates its Permission and Role
checks. Agents retain only their direct Permissions and have no package-level Roles; framework wrappers, endpoint
policy, and response handling remain consumer-owned.
Local development
PHP 8.5 and Docker are required. Tooling follows the Fight Common conventions and runs in the isolated
fight-access-control container through repository-owned scripts:
./bin/phpunit ./bin/phpcs ./bin/phpstan ./bin/deptrac ./bin/rector process src/ ./bin/planning-check
./bin/build is the canonical completion command. It installs the tracked Composer resolution and runs the
single ordered ./bin/quality gate. ./bin/build --latest checks the latest dependency versions compatible
with composer.json; hosted CI performs that same latest-compatible resolution before invoking
./bin/quality directly.
For a clean, dated release candidate, ./bin/release certify <version> records its exact HEAD and the
OpenAPI consumer-composition, planning, and package-quality evidence under ignored .runs/. It is
verification-only and does not create a commit, merge, tag, push, or publication.
Keep scratch in purpose-named, gitignored .runs/ subdirectories following the
project profile. Linked worktrees use
.runs/worktree/<task-slug>/; notes, logs, handoffs and reviews remain separate. Never stage scratch. Run commands
from the assigned checkout and remove resources only with separate cleanup authorization. See
CONTRIBUTING.md for Git Flow, isolation, and review expectations.
Security
Do not disclose suspected vulnerabilities in public issues or pull requests. Follow the private reporting process in SECURITY.md.
Visibility and release effects
These are independent operational effects. Approval for one is not approval for another; each requires a separate approval:
- Public repository visibility exposes the source and history under the repository license.
- Commit creation records reviewed work in Git history.
- Version tag creation gives a selected commit a version identifier.
- Packagist publication makes package metadata discoverable and installable through Packagist.
- Release publication creates a hosted release and its release notes or artifacts.
The repository is public under the MIT License. v0.1.0 is its first public package release; later 0.x
versions may refine public contracts before the separate 1.0.0 stability review. A commit hash may still be
used for reproducible integration testing, but it is not a version tag or release.
License
Fight AccessControl is available under the MIT License.