PHPackages                             mrpunyapal/php-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. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. mrpunyapal/php-2fa

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

mrpunyapal/php-2fa
==================

Framework-agnostic Two-Factor Authentication actions for PHP with optional Laravel support

0.1.0(4mo ago)195MITPHPPHP ^8.3CI passing

Since Feb 22Pushed 4mo agoCompare

[ Source](https://github.com/MrPunyapal/php-2fa)[ Packagist](https://packagist.org/packages/mrpunyapal/php-2fa)[ Docs](https://github.com/mrpunyapal/php-2fa)[ RSS](/packages/mrpunyapal-php-2fa/feed)WikiDiscussions main Synced today

READMEChangelog (3)Dependencies (27)Versions (7)Used By (0)

PHP 2FA
=======

[](#php-2fa)

[![Latest Version on Packagist](https://camo.githubusercontent.com/cd4ed0ce5c57d278001d53f0b9a15d1b3ee35778771ff8a92ed674f4e999c8c8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d7270756e796170616c2f7068702d3266612e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mrpunyapal/php-2fa)[![Tests](https://github.com/mrpunyapal/php-2fa/actions/workflows/run-tests.yml/badge.svg?branch=main)](https://github.com/mrpunyapal/php-2fa/actions/workflows/run-tests.yml)[![Total Downloads](https://camo.githubusercontent.com/f8d5cc16933910d6411000ae27205360e0e3ca38e5fa7c87ef9ce4e83aae1222/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d7270756e796170616c2f7068702d3266612e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mrpunyapal/php-2fa)

Framework-agnostic Two-Factor Authentication (TOTP) actions for PHP. Works with any authenticator app (Google Authenticator, Authy, etc.). Optional first-party Laravel support included.

Inspired by [Laravel Fortify](https://github.com/laravel/fortify) and built on top of [`pragmarx/google2fa`](https://github.com/antonioribeiro/google2fa).

Features
--------

[](#features)

- Enable / Disable / Confirm 2FA
- Verify OTP codes
- Recovery code generation, verification, and regeneration
- Enable → Confirm flow (user must verify a code before 2FA is active)
- Framework-agnostic core — use with any PHP application
- Optional Laravel integration with service provider, config, and Eloquent trait
- AES-256-CBC encryption out of the box (`OpenSslEncryptor`)
- Bring your own encryptor via the `Encryptor` contract

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

[](#requirements)

- PHP 8.3+
- OpenSSL extension

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

[](#installation)

```
composer require mrpunyapal/php-2fa
```

### Laravel

[](#laravel)

The service provider is auto-discovered. Publish the config:

```
php artisan vendor:publish --tag="two-factor-config"
```

Quick Start (Vanilla PHP)
-------------------------

[](#quick-start-vanilla-php)

### 1. Implement `TwoFactorUser` on your user entity

[](#1-implement-twofactoruser-on-your-user-entity)

```
use MrPunyapal\Php2fa\Contracts\TwoFactorUser;
use DateTimeImmutable;

class User implements TwoFactorUser
{
    private ?string $twoFactorSecret = null;
    private ?string $twoFactorRecoveryCodes = null;
    private ?DateTimeImmutable $twoFactorConfirmedAt = null;

    public function getTwoFactorSecret(): ?string { return $this->twoFactorSecret; }
    public function setTwoFactorSecret(?string $secret): void { $this->twoFactorSecret = $secret; }
    public function getTwoFactorRecoveryCodes(): ?string { return $this->twoFactorRecoveryCodes; }
    public function setTwoFactorRecoveryCodes(?string $codes): void { $this->twoFactorRecoveryCodes = $codes; }
    public function getTwoFactorConfirmedAt(): ?DateTimeImmutable { return $this->twoFactorConfirmedAt; }
    public function setTwoFactorConfirmedAt(?DateTimeImmutable $confirmedAt): void { $this->twoFactorConfirmedAt = $confirmedAt; }
}
```

> See [docs/examples/php/setup-two-factor.php](docs/examples/php/setup-two-factor.php) for a full PDO-backed implementation.

### 2. Use `TwoFactorManager`

[](#2-use-twofactormanager)

```
use MrPunyapal\Php2fa\TwoFactorManager;

$manager = TwoFactorManager::create(
    issuer: 'My App',
    encryptionKey: 'your-secret-encryption-key',
);

// Enable 2FA
$setup = $manager->enable($user, 'user@example.com');
// $setup->secret      — plain text secret (show once)
// $setup->qrCodeUrl   — otpauth:// URL (render as QR code)
// $setup->recoveryCodes — array of recovery codes (show once)

// Confirm 2FA (user enters code from authenticator app)
$manager->confirm($user, $otpCode);

// Verify OTP or recovery code during login
$valid = $manager->verify($user, $code);

// Regenerate recovery codes
$newCodes = $manager->regenerateRecoveryCodes($user);

// Disable 2FA
$manager->disable($user);
```

Using Individual Actions
------------------------

[](#using-individual-actions)

If you prefer dependency injection or want granular control:

```
use MrPunyapal\Php2fa\Actions\EnableTwoFactorAuthentication;
use MrPunyapal\Php2fa\Actions\ConfirmTwoFactorAuthentication;
use MrPunyapal\Php2fa\Actions\VerifyTwoFactorCode;
use MrPunyapal\Php2fa\Actions\DisableTwoFactorAuthentication;
use MrPunyapal\Php2fa\Actions\GenerateRecoveryCodes;
use MrPunyapal\Php2fa\Services\TwoFactorService;
use MrPunyapal\Php2fa\Support\OpenSslEncryptor;

$service = new TwoFactorService(issuer: 'My App');
$encryptor = new OpenSslEncryptor('your-secret-key');

$enable = new EnableTwoFactorAuthentication($service, $encryptor);
$setup = $enable($user, 'user@example.com');

$confirm = new ConfirmTwoFactorAuthentication($service, $encryptor);
$confirm($user, $otpCode);

$verify = new VerifyTwoFactorCode($service, $encryptor);
$isValid = $verify($user, $code);

$regenerate = new GenerateRecoveryCodes($encryptor);
$codes = $regenerate($user);

$disable = new DisableTwoFactorAuthentication();
$disable($user);
```

Laravel Usage
-------------

[](#laravel-usage)

### Add the trait to your User model

[](#add-the-trait-to-your-user-model)

```
use MrPunyapal\Php2fa\Contracts\TwoFactorUser;
use MrPunyapal\Php2fa\Laravel\Concerns\HasTwoFactorAuthentication;

class User extends Authenticatable implements TwoFactorUser
{
    use HasTwoFactorAuthentication;
}
```

### Add the required columns

[](#add-the-required-columns)

```
Schema::table('users', function (Blueprint $table) {
    $table->text('two_factor_secret')->nullable();
    $table->text('two_factor_recovery_codes')->nullable();
    $table->timestamp('two_factor_confirmed_at')->nullable();
});
```

### Inject actions or manager

[](#inject-actions-or-manager)

```
use MrPunyapal\Php2fa\Actions\EnableTwoFactorAuthentication;

class TwoFactorController extends Controller
{
    public function store(
        Request $request,
        EnableTwoFactorAuthentication $enable,
    ) {
        $setup = $enable($request->user(), $request->user()->email);

        return response()->json([
            'qr_code_url' => $setup->qrCodeUrl,
            'recovery_codes' => $setup->recoveryCodes,
        ]);
    }
}
```

### Batch saves with `withoutSaving()`

[](#batch-saves-with-withoutsaving)

By default, each setter on the `HasTwoFactorAuthentication` trait persists immediately. To batch multiple field changes into a single DB write:

```
$user->withoutSaving(function ($user) {
    $user->setTwoFactorSecret($encrypted);
    $user->setTwoFactorRecoveryCodes($codes);
    $user->setTwoFactorConfirmedAt(null);
});
// One save() call instead of three
```

Examples
--------

[](#examples)

Full working examples are available in the [`docs/examples/`](docs/examples/) directory.

### Laravel Examples

[](#laravel-examples)

FileDescription[TwoFactorController.php](docs/examples/laravel/TwoFactorController.php)Controller with enable, confirm, verify, disable, and regenerate actions[EnsureTwoFactorVerified.php](docs/examples/laravel/EnsureTwoFactorVerified.php)Middleware that requires 2FA verification before accessing protected routes[routes.php](docs/examples/laravel/routes.php)Route definitions with proper middleware stacking[two-factor-verify.blade.php](docs/examples/laravel/two-factor-verify.blade.php)Blade view for OTP / recovery code input[migration.php](docs/examples/laravel/migration.php)Migration to add 2FA columns to users table### PHP Examples

[](#php-examples)

FileDescription[setup-two-factor.php](docs/examples/php/setup-two-factor.php)Full setup flow with PDO-backed `TwoFactorUser` implementation[login-with-two-factor.php](docs/examples/php/login-with-two-factor.php)Session-based login flow with 2FA challenge[manage-recovery-codes.php](docs/examples/php/manage-recovery-codes.php)Regenerate, display, and verify recovery codes[qr-code-display.php](docs/examples/php/qr-code-display.php)Render QR codes using Google Charts, chillerlan/php-qrcode, or endroid/qr-code[custom-encryptor.php](docs/examples/php/custom-encryptor.php)Custom `Encryptor` implementation using Sodium (libsodium)Configuration
-------------

[](#configuration)

```
// config/two-factor.php
return [
    'issuer' => env('TWO_FACTOR_ISSUER', config('app.name', 'My App')),
    'secret_length' => (int) env('TWO_FACTOR_SECRET_LENGTH', 32),
    'window' => (int) env('TWO_FACTOR_WINDOW', 1),
    'algorithm' => env('TWO_FACTOR_ALGORITHM', 'sha1'), // sha1, sha256, sha512
    'recovery_code_count' => (int) env('TWO_FACTOR_RECOVERY_CODE_COUNT', 8),
];
```

Custom Encryptor
----------------

[](#custom-encryptor)

Implement the `Encryptor` contract to use your own encryption strategy:

```
use MrPunyapal\Php2fa\Contracts\Encryptor;

class MyEncryptor implements Encryptor
{
    public function encrypt(string $value): string
    {
        // your encryption logic
    }

    public function decrypt(string $value): string
    {
        // your decryption logic
    }
}
```

Then pass it to the actions or bind it in Laravel's container. See [docs/examples/php/custom-encryptor.php](docs/examples/php/custom-encryptor.php) for a complete Sodium-based implementation.

API Reference
-------------

[](#api-reference)

### Actions

[](#actions)

ActionPurpose`EnableTwoFactorAuthentication`Generates secret + recovery codes, stores encrypted on user`DisableTwoFactorAuthentication`Clears all 2FA fields on user`ConfirmTwoFactorAuthentication`Verifies OTP code and sets confirmed timestamp`VerifyTwoFactorCode`Verifies OTP or recovery code, replaces used recovery codes`GenerateRecoveryCodes`Generates new set of recovery codes### Exceptions

[](#exceptions)

ExceptionWhen`InvalidOtpException`OTP code verification fails during confirmation`TwoFactorNotEnabledException`Action requires 2FA to be enabled but it isn't`EncryptionException`Encryption or decryption operation failsTesting
-------

[](#testing)

```
composer test
```

Credits
-------

[](#credits)

- [Mr Punyapal](https://github.com/mrpunyapal)
- [All Contributors](../../contributors)

License
-------

[](#license)

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

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance77

Regular maintenance activity

Popularity12

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity43

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 ~2 days

Total

3

Last Release

126d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/230c58a4f918ca3e3f2988b38721230698bce88f76ae9087e4377ba0b3a074d5?d=identicon)[MrPunyapal](/maintainers/MrPunyapal)

---

Top Contributors

[![MrPunyapal](https://avatars.githubusercontent.com/u/53343069?v=4)](https://github.com/MrPunyapal "MrPunyapal (24 commits)")

---

Tags

phplaravelgoogle authenticatorotptotpAuthentication2fatwo-factorauthy

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/mrpunyapal-php-2fa/health.svg)

```
[![Health](https://phpackages.com/badges/mrpunyapal-php-2fa/health.svg)](https://phpackages.com/packages/mrpunyapal-php-2fa)
```

###  Alternatives

[stephenjude/filament-two-factor-authentication

Filament Two Factor Authentication: Google 2FA + Passkey Authentication

84215.9k9](/packages/stephenjude-filament-two-factor-authentication)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.6k](/packages/rawilk-profile-filament-plugin)[remotemerge/totp-php

Lightweight, fast, and secure TOTP (2FA) authentication library for PHP — battle tested, dependency free, and ready for enterprise integration.

2118.5k](/packages/remotemerge-totp-php)[thecodework/two-factor-authentication

Two Factor Authentication (2FA) for Laravel

225.6k](/packages/thecodework-two-factor-authentication)

PHPackages © 2026

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