Adding Two‑Factor Authentication (2FA) to a Laravel API (Laragear + Sanctum)

I recently wired up Two‑Factor Authentication (2FA) for the DayWright API. There are a few ways to do 2FA in Laravel, but I chose the Laragear 2FA package because it’s simple, well‑documented, and plays nicely with Sanctum.

2 min read


We’ll add 2FA to a Laravel Sanctum API in 3 steps

  1. Enable 2FA (generate secret + QR, confirm with OTP)

  2. Return recovery codes & allow disabling

  3. Enforce 2FA at login with a secure flow


I used the Laragear 2FA package (v2 for Laravel 11) with Sanctum. Full code is in my repo: DayWright GitHub.

Who this is for
  • You’re building a JSON API with Laravel 10+ Sanctum.

  • You’re comfortable with basic auth flows and Form Requests.

  • You want a clean, minimal 2FA setup without writing your own logic

Step 1: Enable 2FA

When a user opts-in, we generate a secret, return a QR code, and mark the setup as “in progress.”



What happens:
  • Creates a pending secret

  • Returns QR (base64) URI and raw string,

  • Mark status as in_progress.

  • Make sure this route is protected for Laravel confirmation so auth user password confirms correctly -> See related form request file


Step 2: Confirm & Recovery Codes

The user confirms setup with a 6-digit code from their authenticator app.






What happens:

Step 3: Regenerate Codes or Disable 2FA (optional)
  • Disable: Gives user option to disable 2FA









  • Recovery codes endpoint: - Generates a fresh set of recovery codes on demand



Step 4: Enforce 2FA at login

Here’s the secure API login flow:

  • User submits email/password.

  • If 2FA is disabled return a Sanctum token like normal.

  • If 2FA is enabled create a short‑lived, encrypted cache and session marker and return 2fa required.

  • User submits the 6‑digit code to a dedicated endpoint.

  • If the code is valid clear the marker and issue the Sanctum token.

Controller: confirm login















What happens here:
  • If 2FA is enabled, no token is returned yet — only a two_fa_required response.

  • If 2FA is not enabled, we proceed as normal and issue the token.

  • Set session in LoginUserService class



Confirming the login:

Once the user enters their OTP, the second endpoint kicks in:
















What this does:

  • Validates the 6-digit code via the TwoFactorLoginRequest.

  • If valid, it clears the short-lived 2fa_login marker from the session.

  • Finally, it issues a first-class Sanctum token, just like a normal login.


Wrapping Up

And that’s it. You now have a full 2FA setup running in your Laravel API.
This approach keeps your login flow clean, secure, and simple enough to extend later.

If you want to take it a step further, check out articles on advanced MFA authentication they cover some great extra security layers.

You can also look at the frontend side of this feature and explore the full implementation in my open-source project DayWright.

If you hit any issues or have questions, feel free to reach out.
Thanks for reading. I hope this helps you make your next Laravel app a bit more secure!