betterauth / symfony-bundle
Symfony-native PASETO authentication bundle with application-owned users and persistence
Package info
github.com/MakFly/betterauth-symfony
Type:symfony-bundle
pkg:composer/betterauth/symfony-bundle
Requires
- php: ^8.4
- ext-openssl: *
- paragonie/paseto: ^3.1
- psr/cache: ^3.0
- psr/event-dispatcher: ^1.0
- psr/log: ^3.0
- ramsey/uuid: ^4.7
- symfony/config: ^6.4|^7.0|^8.0
- symfony/dependency-injection: ^6.4|^7.0|^8.0
- symfony/event-dispatcher: ^6.4|^7.0|^8.0
- symfony/framework-bundle: ^6.4|^7.0|^8.0
- symfony/http-foundation: ^6.4|^7.0|^8.0
- symfony/http-kernel: ^6.4|^7.0|^8.0
- symfony/security-bundle: ^6.4|^7.0|^8.0
- symfony/yaml: ^6.4|^7.0|^8.0
Requires (Dev)
- phpstan/extension-installer: ^1.3
- phpstan/phpstan: ^2.1
- phpstan/phpstan-symfony: ^2.0
- phpunit/phpunit: ^10.5
- symfony/browser-kit: ^6.4|^7.0|^8.0
- symfony/phpunit-bridge: ^6.4|^7.0|^8.0
Suggests
- bacon/bacon-qr-code: Required only when rendering a TOTP QR code
- symfony/mailer: Required only by an application email sender implementation
Conflicts
This package is auto-updated.
Last update: 2026-08-14 18:16:47 UTC
README
BetterAuth Symfony is Symfony authentication infrastructure for encrypted PASETO v4.local access tokens, atomic refresh-token rotation, encrypted TOTP, and application-owned security ports. It gives an application safe primitives; it does not generate a User entity, routes, controllers, firewalls, Doctrine mappings, migrations, or persistence adapters.
Install and issue a token
composer require betterauth/symfony-bundle
# config/packages/better_auth.yaml better_auth: secret: '%env(BETTER_AUTH_SECRET)%' user_id_claim: sub access_token: { ttl: 900 } refresh_token: enabled: true ttl: 2592000 store: App\Security\RefreshTokenStore
The refresh store is an application service implementing
RefreshTokenStoreInterface; it receives SHA-256 hashes, never a raw refresh
token. Issue the pair from an application-owned login route:
$pair = $refreshTokens->issue($user->getUserIdentifier()); return new JsonResponse([ 'access_token' => $pair->accessToken, 'refresh_token' => $pair->refreshToken, 'expires_in' => $pair->expiresIn, ]);
Protect a firewall
Your application supplies the user provider and decides which routes require a token. The bundle factory injects that configured provider into the authenticator.
# config/packages/security.yaml security: providers: app_users: { id: App\Security\UserProvider } firewalls: api: stateless: true provider: app_users better_auth: ~
┌──────────────┐ Bearer PASETO ┌─────────────────────┐
│ Application │ ────────────────▶ │ better_auth factory │
│ route/API │ └──────────┬──────────┘
└──────┬───────┘ │ claims: sub
│ token pair ▼
▼ ┌─────────────────────┐
┌──────────────┐ hash/ciphertext │ Application provider │
│ Bundle APIs │ ────────────────▶ │ and storage ports │
└──────────────┘ └─────────────────────┘
The application remains the owner of persistence, authorization rules, HTTP schemas and error policy. The bundle translates malformed, expired, or non-access PASETOs into Symfony authentication failures.
Capabilities
| Capability | Bundle responsibility | Application responsibility |
|---|---|---|
| PASETO access tokens | Create and parse bounded v4.local claims | User provider, firewall and routes |
| Refresh tokens | Issue, typed atomic rotate, targeted/family revoke | Transactional hash-only store |
| TOTP | Domain-separated seed encryption and verification | Ciphertext-only store and enrollment policy |
| Magic link, reset, guest | One-time hash issuance and atomic consume | Delivery, account policy and storage |
| Device and monitoring | Fingerprint/event services | Retention, alerting and storage |
| Multi-tenant | Membership query service | Membership source and authorization |
Optional features are disabled by default and register no HTTP routes. Enable a feature only after wiring its application-owned port; see the configuration reference for each port.
Compatibility and security
- PHP 8.4+; Symfony 6.4, 7.x and 8.x are supported by the package matrix.
- OpenSSL is required for authenticated TOTP seed encryption.
- Use a high-entropy
BETTER_AUTH_SECRET, rotate it through your own secret lifecycle, and keep access tokens short lived. - Perform refresh rotation and one-time consumption with a conditional, unspent/unexpired database update. Treat a replay as a family-revocation event.
- Make bearer API firewalls stateless. Re-authenticate before changing a second factor or password; revoke refresh families after password reset.
Documentation and migration
- English documentation
- Documentation française
- Configuration reference
- Standalone demo
- Upgrade to 1.1
The demo is outside CI and shows Doctrine/SQLite adapters, stateless bearer authentication, Mailpit delivery, Tailwind built with Bun, and the full route matrix. It is a teaching application: adapt its limits, mail sender, secrets, retention and storage transactions before production use.