Skip to content

Migrate authentication off Auth0 to native Symfony auth #147

Description

@JanMikes

Goal

Migrate authentication fully off Auth0 (free tier) to native Symfony 8 authentication — own login/registration/password-reset/email-verification, no external identity provider, no vendor lock-in on password hashes.

Full research & plan: docs/features/auth-migration/

Key verified facts (2026-07-11)

  • Production: 9,953 players, 100% auth0| email+password — zero social logins (~3,300 active/90d). No social-identity portability problem exists.
  • Password hashes are exportable: one month of Auth0 B2C Essentials (~$35, monthly self-service, cancelable) + support ticket → NDJSON with bcrypt $2b$10$ hashes. Verified password_verify() on PHP 8.5 accepts them; Symfony migrate_from: ['bcrypt'] transparently upgrades to argon2id on first login → users keep their exact passwords.
  • Free fallback: ROPG "trickle" against Auth0's token endpoint inside our login authenticator covers stale hashes / post-export signups during the transition window.
  • Blast radius is contained: Player.userId string is the identity seam (kept as-is), RetrieveLoggedUserProfile is the single read chokepoint, 46 #[CurrentUser] type-hints are a mechanical sweep, tests funnel through 2 helpers. API/PAT/OAuth2-server/admin/Stripe/Mercure untouched.
  • All reset/verification UX is a new build (currently 100% delegated to Auth0 hosted pages). Ship magic login links at launch — main mitigation for password managers having credentials saved under *.auth0.com.

Phase checklist

  • Phase 0 — Preparation & data (free bulk export, reconciliation of 7 dup-email pairs + 3 missing emails, deliverability check, ROPG smoke test)
  • Phase 1 — Paid hash export (~$35 Essentials month + support ticket, validate, downgrade)
  • Phase 2 — Build native auth (UserAccount entity, authenticator with trickle branch, registration/reset/verify/login-link, code sweep, tests)
  • Phase 3 — User communication (T-14d announcement, banner, FAQ)
  • Phase 4 — Cutover (fresh delta export, import, session flush, smoke tests, 48h watch)
  • Phase 5 — Transition window (metrics, straggler nudge, exit criteria)
  • Phase 6 — Decommission (remove trickle + auth0/symfony fork, delete tenant, privacy policy, secure-delete exports)
  • Phase 7 — Optional: passkeys, 2FA, session management

Estimated: ~6–8 weeks calendar (dominated by comms lead time + transition window).

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions