BetterAuth Symfony: Rethinking Authentication for Symfony 7
Authentication in Symfony is powerful but verbose. The Security component is flexible — too much, sometimes. Configuring OAuth, 2FA, magic links, and session management requires dozens of files, nested YAML config, and fine knowledge of the firewall system.
I created BetterAuth Symfony to solve this problem: a bundle that installs a complete authentication system in one command, with all modern patterns ready to use.
The problem with standard Symfony auth
Symfony Security is an excellent component. But for a project that needs complete auth, you need:
- Configure the firewall in
security.yaml(40+ lines) - Create User, Session, RefreshToken entities
- Write login, register, logout, forgot-password controllers
- Integrate an OAuth provider (Google, GitHub, etc.)
- Add 2FA with a third-party bundle
- Manage email verification tokens
- Implement session management
That’s easily 2-3 days of work for an experienced developer. And it’s code you rewrite on every project with minor variations.
The solution: an installation wizard
BetterAuth Symfony offers an interactive wizard that configures everything in 5 minutes:
php bin/console better-auth:install
The wizard asks 3 questions:
- ID Strategy: UUID v7 (recommended) or INT auto-increment
- Auth mode: API (Paseto V4 tokens), Session (stateful), or Hybrid
- OAuth Providers: Google, GitHub, Facebook, etc.
Then it automatically generates:
- Doctrine entities (User, Session, RefreshToken)
- Authentication controllers
- Database migrations
security.yamlconfiguration- Environment variables in
.env
Technical choices
Paseto V4 over JWT
For API mode, I chose Paseto V4 instead of JWT. Why?
- No algorithm confusion: Paseto enforces the algorithm (no
alg: nonepossible) - Security by default: XChaCha20-Poly1305 encryption, no configuration needed
- Shorter tokens: reduced payload, less bandwidth
The trade-off: fewer client libraries available than JWT. But for a PHP API consumed by a JavaScript frontend, existing libraries are mature.
Native multi-tenant
The bundle supports organizations, teams, members, and invitations out of the box:
// Organization, Team, Member entities are generated
// The permission tree is configured automatically
$user->getOrganizations(); // List of orgs
$user->getCurrentTeam(); // Active team
$team->getMembers(); // Team members
$team->invite('new@example.com'); // Invitation
This pattern is inspired by what Laravel does with its auth packages (Jetstream/Breeze), adapted to Symfony conventions.
30+ pre-built endpoints
The bundle generates endpoints covering 6 functional domains:
| Domain | Endpoints | Examples |
|---|---|---|
| Basic auth | 4 | register, login, logout, refresh |
| Sessions | 3 | list, revoke, revoke-all |
| 2FA/TOTP | 3 | enable, verify, disable |
| Magic Links | 2 | request, verify |
| 2 | send-verification, verify | |
| OAuth | 2 | authorize, callback (× n providers) |
Each endpoint follows Symfony conventions and integrates with API Platform for automatic OpenAPI documentation.
Internal architecture
The bundle follows a strict layered architecture:
- Domain Layer: Value Objects (Email, Token), validation rules
- Application Layer: Auth services, token managers, session handlers
- Infrastructure Layer: Doctrine repositories, Symfony Security integration, HTTP controllers
This separation allows unit testing auth logic without a database. E2E tests with Playwright complement by validating complete flows (registration → verification → login → 2FA).
What I learned
Automated installation is critical
A bundle that requires 15 manual steps won’t be adopted. The better-auth:install wizard was the most important feature — much more than any auth functionality.
Security isn’t delegated to AI
I used Claude Code to accelerate development, but every security decision was manually validated. Hashing, token generation, session management — everything was audited line by line. AI in the workflow is an accelerator, not a security auditor.
Naming is an API contract
better-auth:install, better-auth:setup-features, better-auth:add-controller — each command follows a clear convention. Symfony command naming is an API contract with the developer. It must be intuitive, predictable, and consistent.
In summary
BetterAuth Symfony offers a complete modern authentication system for Symfony 6/7:
- 5-minute installation via an interactive wizard
- Paseto V4 tokens for API mode (safer than JWT)
- OAuth, 2FA, magic links ready to use
- Multi-tenant with organizations and teams
- 30+ endpoints generated automatically
The project is open source: github.com/MakFly/betterauth-symfony.
Kevin De Vaubree
Senior Full-Stack Developer