⭐ Found this useful? Install it from Packagist and give it a star on GitHub: it helps us maintain and improve the project.
Personal API tokens for Symfony: hashed lookup tokens with per-module grants, a tenant reach, mandatory expiry, revocation, rate limits and audit events, one Bearer authenticator for every API and a UiKit account and operator UI.
Standard Symfony by default, DDD / hexagonal opt-in: zero configuration in a standard project; public ports are interfaces and value objects, bundle-owned tables are mapped in XML and referenced by id, the bundle never flushes your EntityManager.
🚧 Status: S1 core, first tag 0.1.0 pending its security audit. The package is built slice by slice from its design contract (docs/CONTRACT.md, 221-A). S1 ships the token store, format and hash, the issuer, revoker, query and authenticator services, the module registry and the
issue/purge-expiredcommands for standard and DDD hosts; the firewall, pages, bridges and HTTP API land with the next slices in docs/ROADMAP.md.
📋 Compatible with Symfony 7.4, 8.0 and 8.1 · PHP 8.2+ (Symfony 8.x requires PHP 8.4+)
This bundle is FrankenPHP worker mode friendly.
S1 (today) covers the token store, format, issuer, revoker, query and authenticator; the rest follows the roadmap.
-
FrankenPHP worker mode, kernel kept alive and not reset: no request state in services; a worker test (one kernel, 2,000 requests, two owners, revoke mid-run, flat memory) and the owner status read fresh on every request (docs/FRANKENPHP-WORKER-AUDIT.md).
-
Personal tokens issued to an owner (referenced by id): name, per-module grants (level + flags), a tenant reach, mandatory expiry (max 365 days), revoke, revoke all, erasure. Hash at rest (SHA-256), shown once, non-secret lookup id, CRC32 checksum for typo checks and secret scanning (
nwt_<lookup>_<secret><checksum>). -
One Bearer authenticator for Symfony firewalls (stateless), constant-time verification, owner status re-checked on every request, principal stamped on the request only.
-
Module registry: grants as data (
{tasks: read, mcp: on + destructive}), modules from config and bridges; a token only narrows the person's real permissions, never widens them. -
Security controls: one rate-limit bucket per token across every API, write sub-budget, failed tokens per IP, re-authentication before issue (password, or MFA through AuthKit), framing and
no-storeheaders, audit events after commit (ids only). -
UI on UiKit + FormKit: account page (list, New token dialog shown once, revoke, revoke all) and operator page.
-
Public API
GET/DELETE <prefix>/tokens/v1/selfwith OpenAPI; optional leak-report endpoint (off by default). -
Bridges (inside this bundle, active when installed): TaskBoard, Wiki, McpKit principals and rate limiters, HttpLog credential stamp, UserKit eraser / export / sessions listener, AuditKit, AuthKit re-auth.
composer require nowo-tech/api-token-bundleSee docs/INSTALLATION.md. Nothing is registered while nowo_api_token.enabled is false.
# config/packages/nowo_api_token.yaml
nowo_api_token:
enabled: falseEvery key of the contract is already accepted (strict tree): docs/CONFIGURATION.md.
- PHP >= 8.2, < 8.6 (Symfony 8.x needs PHP 8.4+)
- Symfony 7.4, 8.0 or 8.1
- Doctrine DBAL 4 (
doctrine/dbal^4.0) and ORM 3.3+ (doctrine/orm^3.3); DoctrineBundle once the bundle is enabled
demo/symfony8: Symfony 8.1, FrankenPHP worker mode, MySQL, Web Profiler, Twig Inspector and Hot Reload, on
http://localhost:8221 (make -C demo up). See docs/DEMO-FRANKENPHP.md.
- Installation
- Configuration
- Usage
- Contributing
- Code of Conduct
- Changelog
- Upgrading
- Release
- Security
- Engram
- Spec-driven development
- GitHub Spec Kit
- Roadmap
make test # PHPUnit in Docker
make test-coverage-100 # fails below 100 % of src/
make release-check # every gate, demo included- PHP: 100 % of
src/(gate in CI).
MIT. See LICENSE.
Created by Héctor Franco Aceituno at Nowo.tech.
