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:

  1. Configure the firewall in security.yaml (40+ lines)
  2. Create User, Session, RefreshToken entities
  3. Write login, register, logout, forgot-password controllers
  4. Integrate an OAuth provider (Google, GitHub, etc.)
  5. Add 2FA with a third-party bundle
  6. Manage email verification tokens
  7. 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:

  1. ID Strategy: UUID v7 (recommended) or INT auto-increment
  2. Auth mode: API (Paseto V4 tokens), Session (stateful), or Hybrid
  3. OAuth Providers: Google, GitHub, Facebook, etc.

Then it automatically generates:

  • Doctrine entities (User, Session, RefreshToken)
  • Authentication controllers
  • Database migrations
  • security.yaml configuration
  • 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: none possible)
  • 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:

DomainEndpointsExamples
Basic auth4register, login, logout, refresh
Sessions3list, revoke, revoke-all
2FA/TOTP3enable, verify, disable
Magic Links2request, verify
Email2send-verification, verify
OAuth2authorize, 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.

KD

Kevin De Vaubree

Senior Full-Stack Developer