PHPackages                             adesin-fr/laravel-mail-2fa - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Mail &amp; Notifications](/categories/mail)
4. /
5. adesin-fr/laravel-mail-2fa

ActiveLibrary[Mail &amp; Notifications](/categories/mail)

adesin-fr/laravel-mail-2fa
==========================

Laravel 2FA package using email OTP codes with InertiaJS support

2026.24.1(3w ago)030MITPHPPHP ^8.2

Since Jan 6Pushed 3w agoCompare

[ Source](https://github.com/LemarinelNet/laravel-mail-2fa)[ Packagist](https://packagist.org/packages/adesin-fr/laravel-mail-2fa)[ RSS](/packages/adesin-fr-laravel-mail-2fa/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (14)Versions (3)Used By (0)

Laravel Mail 2FA
================

[](#laravel-mail-2fa)

A simple Laravel package for two-factor authentication via email OTP codes with InertiaJS support.

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 11.0+
- InertiaJS with Vue 3

Installation
------------

[](#installation)

Install the package via Composer:

```
composer require adesin-fr/laravel-mail-2fa
```

Publishing Assets
-----------------

[](#publishing-assets)

### Publish all assets at once:

[](#publish-all-assets-at-once)

```
php artisan vendor:publish --tag=mail2fa
```

### Or publish individually:

[](#or-publish-individually)

**Configuration file:**

```
php artisan vendor:publish --tag=mail2fa-config
```

**Database migrations:**

```
php artisan vendor:publish --tag=mail2fa-migrations
```

**Email views (Blade templates):**

```
php artisan vendor:publish --tag=mail2fa-views
```

**Inertia Vue components:**

```
php artisan vendor:publish --tag=mail2fa-inertia
```

Run Migrations
--------------

[](#run-migrations)

The package adds `mfa_code` and `mfa_expires_at` columns to your `users` table:

```
php artisan migrate
```

Configuration
-------------

[](#configuration)

After publishing, edit `config/mail2fa.php`:

```
return [
    // Enable/disable 2FA globally
    'enabled' => env('MAIL2FA_ENABLED', true),

    // Length of the verification code (default: 6)
    'code_length' => env('MAIL2FA_CODE_LENGTH', 6),

    // Code expiration in minutes (default: 10)
    'code_expiration' => env('MAIL2FA_CODE_EXPIRATION', 10),

    // Cooldown between resend requests in seconds (default: 60)
    'resend_cooldown' => env('MAIL2FA_RESEND_COOLDOWN', 60),

    // Verification session lifetime in minutes (null = entire session)
    'verification_lifetime' => env('MAIL2FA_VERIFICATION_LIFETIME', null),

    // Route configuration
    'routes' => [
        'prefix' => '2fa',
        'middleware' => ['web', 'auth'],
        'names' => [
            'verify' => 'mail2fa.verify',
            'verify.post' => 'mail2fa.verify.post',
            'resend' => 'mail2fa.resend',
        ],
    ],

    // Inertia component path
    'inertia' => [
        'verify_component' => 'Mail2FA/Verify',
    ],
];
```

User Model Setup
----------------

[](#user-model-setup)

Make sure your User model has the `mfa_code` and `mfa_expires_at` fields in the `$fillable` array:

```
// app/Models/User.php

protected $fillable = [
    'name',
    'email',
    'password',
    'mfa_code',      // Add this
    'mfa_expires_at', // Add this
];

protected $casts = [
    // ... other casts
    'mfa_expires_at' => 'datetime',
];
```

Usage
-----

[](#usage)

### Protecting Routes

[](#protecting-routes)

Add the `mail2fa` middleware to any routes you want to protect:

```
// Single route
Route::get('/dashboard', DashboardController::class)
    ->middleware(['auth', 'mail2fa']);

// Route group
Route::middleware(['auth', 'mail2fa'])->group(function () {
    Route::get('/dashboard', DashboardController::class);
    Route::get('/settings', SettingsController::class);
});
```

### How It Works

[](#how-it-works)

1. User attempts to access a protected route
2. Middleware checks if user has verified 2FA in current session
3. If not verified, user is redirected to `/2fa/verify`
4. A 6-digit code is sent to the user's email
5. User enters the code
6. If correct, user is redirected to their intended destination
7. Session is marked as verified for the configured lifetime

### Environment Variables

[](#environment-variables)

```
MAIL2FA_ENABLED=true
MAIL2FA_CODE_LENGTH=6
MAIL2FA_CODE_EXPIRATION=10
MAIL2FA_RESEND_COOLDOWN=60
MAIL2FA_VERIFICATION_LIFETIME=
```

Customization
-------------

[](#customization)

### Custom Email Template

[](#custom-email-template)

After publishing views, edit `resources/views/vendor/mail2fa/emails/verification-code.blade.php`.

### Custom Inertia Components

[](#custom-inertia-components)

After publishing Inertia components, edit the Vue files in `resources/js/Pages/Mail2FA/`:

- `Verify.vue` - Main verification page

### Custom Inertia Component Path

[](#custom-inertia-component-path)

If you want to use different component paths:

```
// config/mail2fa.php
'inertia' => [
    'verify_component' => 'Auth/TwoFactorVerify',
],
```

API
---

[](#api)

### Routes

[](#routes)

MethodURINameDescriptionGET/2fa/verifymail2fa.verifyShow verification formPOST/2fa/verifymail2fa.verify.postSubmit verification codePOST/2fa/resendmail2fa.resendResend verification code### Clear Verification

[](#clear-verification)

To programmatically clear a user's verification status (e.g., on logout):

```
use AdesinFr\Mail2FA\Traits\Mail2FATrait;

class AuthController
{
    use Mail2FATrait;

    public function logout(Request $request)
    {
        $this->clearVerification($request);
        // ... rest of logout logic
    }
}
```

Testing
-------

[](#testing)

Run tests with Pest:

```
composer test
```

Or run Pest directly:

```
./vendor/bin/pest
```

Security Considerations
-----------------------

[](#security-considerations)

- Codes are stored hashed (bcrypt) in the database
- Configurable code expiration
- Rate limiting on code resend via cooldown
- Codes are cleared after successful verification
- Session-based verification status

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

42

↑

FairBetter than 88% of packages

Maintenance94

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~152 days

Total

2

Last Release

26d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/f7caa80ffede6a2b3888071d496741ce6a215a6cefe798465e7ba7e7ad1841c3?d=identicon)[Adesin-fr](/maintainers/Adesin-fr)

---

Top Contributors

[![LemarinelNet](https://avatars.githubusercontent.com/u/10656218?v=4)](https://github.com/LemarinelNet "LemarinelNet (3 commits)")

---

Tags

laravelotpsecurityemail2faTwo Factor Authenticationinertia

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/adesin-fr-laravel-mail-2fa/health.svg)

```
[![Health](https://phpackages.com/badges/adesin-fr-laravel-mail-2fa/health.svg)](https://phpackages.com/packages/adesin-fr-laravel-mail-2fa)
```

###  Alternatives

[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.6k29.9M146](/packages/laravel-cashier)[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[spatie/laravel-health

Monitor the health of a Laravel application

87512.0M165](/packages/spatie-laravel-health)[erag/laravel-lang-sync-inertia

A powerful Laravel package for syncing and managing language translations across backend and Inertia.js (Vue/React/Svelte) frontends, offering effortless localization, auto-sync features, and smooth multi-language support for modern Laravel applications.

4925.3k](/packages/erag-laravel-lang-sync-inertia)[emargareten/inertia-modal

Inertia Modal is a Laravel package that lets you implement backend-driven modal dialogs for Inertia apps.

90142.9k](/packages/emargareten-inertia-modal)[api-platform/laravel

API Platform support for Laravel

58171.6k14](/packages/api-platform-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
