PHPackages                             chillerlan/2fa-qrcode-bundle - 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. chillerlan/2fa-qrcode-bundle

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

chillerlan/2fa-qrcode-bundle
============================

An authenticator and a QR Code generator bundled together for MFA in frameworks and applications.

2.0.0(3mo ago)40MITPHPPHP ^8.2CI passing

Since Mar 20Pushed 3mo agoCompare

[ Source](https://github.com/chillerlan/2fa-qrcode-bundle)[ Packagist](https://packagist.org/packages/chillerlan/2fa-qrcode-bundle)[ Docs](https://github.com/chillerlan/2fa-qrcode-bundle)[ Fund](https://ko-fi.com/codemasher)[ RSS](/packages/chillerlan-2fa-qrcode-bundle/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (2)Dependencies (8)Versions (5)Used By (0)

chillerlan/2fa-qrcode-bundle
============================

[](#chillerlan2fa-qrcode-bundle)

An authenticator ([chillerlan/php-authenticator](https://github.com/chillerlan/php-authenticator)) and a QR Code generator ([chillerlan/php-qrcode](https://github.com/chillerlan/php-qrcode)) bundled together for MFA in frameworks and applications.

[![PHP Version Support](https://camo.githubusercontent.com/59312875f4456419f71aa9d694288f77f2acbd134dac29541c61b3b9c01d194f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6368696c6c65726c616e2f3266612d7172636f64652d62756e646c653f6c6f676f3d70687026636f6c6f723d383839324246266c6f676f436f6c6f723d666666)](https://www.php.net/supported-versions.php)[![Packagist version](https://camo.githubusercontent.com/df50e6cd0fa8f55f239c1dc14b800180fdce58b68618be5452634030e98716af/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6368696c6c65726c616e2f3266612d7172636f64652d62756e646c652e7376673f6c6f676f3d7061636b6167697374266c6f676f436f6c6f723d666666)](https://packagist.org/packages/chillerlan/2fa-qrcode-bundle)[![License](https://camo.githubusercontent.com/bbb44ee9944c5225a0ac784b0b818c071ab64ce554cf79d84ef107515665c4e0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6368696c6c65726c616e2f3266612d7172636f64652d62756e646c65)](https://github.com/chillerlan/2fa-qrcode-bundle/blob/main/LICENSE)[![Continuous Integration](https://camo.githubusercontent.com/c27144fe35280976e234af2686cd4a27d52c8cc67681ed88fd6b44972ca0218f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6368696c6c65726c616e2f3266612d7172636f64652d62756e646c652f63692e796d6c3f6272616e63683d6d61696e266c6f676f3d676974687562266c6f676f436f6c6f723d666666)](https://github.com/chillerlan/2fa-qrcode-bundle/actions/workflows/ci.yml?query=branch%3Amain)[![Packagist downloads](https://camo.githubusercontent.com/06eb3b1431b7644ba0ffe7f434f36f41e30552fc01ffb3eccd8795f3b28519f0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6368696c6c65726c616e2f3266612d7172636f64652d62756e646c652e7376673f6c6f676f3d7061636b6167697374266c6f676f436f6c6f723d666666)](https://packagist.org/packages/chillerlan/2fa-qrcode-bundle/stats)

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

[](#requirements)

- PHP 8.4+
    - [`ext-mbstring`](https://www.php.net/manual/book.mbstring.php)
    - optional:
        - [`ext-gd`](https://www.php.net/manual/book.image) for `QRGdImage` based output
        - [`ext-imagick`](https://github.com/Imagick/imagick) with [ImageMagick](https://imagemagick.org) installed
        - [`ext-fileinfo`](https://www.php.net/manual/book.fileinfo.php) required by `QRImagick` output
        - optional libraries, see the [php-qrcode requirements](https://github.com/chillerlan/php-qrcode)

Documentation
-------------

[](#documentation)

You can find the documentation of the bundled libraries in their respective repositories:

- [chillerlan/php-authenticator](https://github.com/chillerlan/php-authenticator)
- [chillerlan/php-qrcode](https://github.com/chillerlan/php-qrcode)
    - User manual:
    - API documentation:
- [chillerlan/php-settings-container](https://github.com/chillerlan/php-settings-container)

### User Guide

[](#user-guide)

#### Invocation

[](#invocation)

Fetch the settings from e.g. a framework config and [invoke the `TwoFactorQRCodeOptions` instance](https://php-qrcode.readthedocs.io/en/v6.0.x/Usage/Advanced-usage.html#configuration-via-qroptions) with it. Please note that this object combines the settings for [`AuthenticatorOptions`](https://github.com/chillerlan/php-authenticator?tab=readme-ov-file#authenticatoroptions) and [`QROptions`](https://php-qrcode.readthedocs.io/en/v6.0.x/Usage/Configuration-settings.html). Alternatively, you can just pass an `iterable` of options to the `TwoFactorQRCode` constructor.

```
use chillerlan\TwoFactorQRCode\TwoFactorQRCode;

$options = [
	'secret_length' => 128,
	'adjacent'      => 2,
];

$twoFactorQRCode = new TwoFactorQRCode($options);
```

#### User registration

[](#user-registration)

- Create a secret, present it to the user as text.
- Create a QR Code and present it to the user.
- Generate a backup code and present it as well, save the counter value.
- Let the user create a fresh OTP with the new credentials.
- Save the data on successful verification and let the user triple check if they saved their backup code.

```
$newSecret = $twoFactorQRCode->createSecret();
$qrcode    = $twoFactorQRCode->getQRCode('label', 'issuer');
$backup    = $twoFactorQRCode->createBackupCode($counterValue);

if($twoFactorQRCode->verifyOTP($newOTP)){
	echo 'yay! do not forget to save your backup code!';
}
```

#### Normal usage: log-ins, reverification etc.

[](#normal-usage-log-ins-reverification-etc)

- Set the secret from the user's data.
- Present the user with a form field for the OTP and verify it.
- Verify the log-in and redirect to wherever the user was headed.

```
$twoFactorQRCode->setSecret($userSecret);

if($twoFactorQRCode->verifyOTP($OTP)){
	// do stuff...

	// redirect
	header('Location: ...');
}
```

#### Using a backup code

[](#using-a-backup-code)

The user has lost access to their authenticator, send them to a form separate from the usual OTP input:

- Verify the given backup OTP against the stored counter value.
- After verification, increase the counter, create a new backup code and save the new counter value.
- Present the new backup code to the user and make them triple check that they have carefully saved it.

```
$twoFactorQRCode->setSecret($userSecret);

if($twoFactorQRCode->verifyBackupCode($backupOTP, $counterValue)){
	$counterValue++;

	$newBackup = $twoFactorQRCode->createBackupCode($counterValue);

	// redirect
}
```

Redirect the user to wherever they can manage their 2FA settings and retrieve their secret once again:

```
$twoFactorQRCode->setSecret($userSecret);

$currentBackup = $twoFactorQRCode->createBackupCode($currentCounterValue);
$qrcode        = $twoFactorQRCode->getQRCode('label', 'issuer');
```

#### Validating an e-mail address

[](#validating-an-e-mail-address)

The previous flow can also be used for other tasks, such as e-mail verification:

- Create a temporary secret and random counter value.
- Create a verification code from the above data.
- Store the temporary secret and counter together with the email address and the current timestamp.
- Send an e-mail with the code to the given e-mail address.

```
$tempSecret       = $twoFactorQRCode->createSecret();
$tempCounter      = random_int(1, 999999);
$verificationCode = $twoFactorQRCode->createBackupCode($counterValue);
```

Now present the user with a form where they can enter the received code:

- Fetch the temporary counter and secret from the storage.
- Verify the code.
- Delete the temporary data after successful verification (or after a defined duration).

```
$twoFactorQRCode->setSecret($tempSecret);

if($twoFactorQRCode->verifyBackupCode($verificationCode, $tempCounter)){
	// success!
}
```

### A note on the secret length

[](#a-note-on-the-secret-length)

The secret length as per the specifications (RFCs [4226](https://tools.ietf.org/html/rfc4226) and [6238](https://tools.ietf.org/html/rfc6238)) is the length of the binary string that is given to the HMAC hash function - there is no encoding involved at all. Google's "[Key URI format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format)" specification uses base32 encoding in order to make the binary secret string portable (URI safe). The base32 encoding naturally results in longer strings than the original, about 60%, so a secret of 20 bytes length results in a 32 byte long base32 encoded string.

However, some of [the top used libraries on packagist](https://packagist.org/search/?tags=totp) use some kind of pseudo base32 encoding, with a shorter secret string than requested as a result (secret length = base32 encoded length), which can compromise the security of the algorithm.

**This library refers to the secret length always as the length of the raw binary string.**

### API

[](#api)

#### `TwoFactorQRCode`

[](#twofactorqrcode)

The class is not final and you're free to extend it to add/change functionality to your liking.

methodreturndescription`__construct(SettingsContainerInterface|TwoFactorQRCodeOptions |iterable $options = new TwoFactorQRCodeOptions)`-`createSecret(int|null $length = null)``string`Creates a cryptograpically secure random secret and returns it as Base32 encoded string`setSecret(string $encodedSecret)``static`Sets a secret phrase from an encoded representation`getSecret()``string`Returns an encoded representation of the current secret phrase`setRawSecret(string $rawSecret)``static`Sets a secret phrase from a raw binary representation`getRawSecret()``string`Returns the raw representation of the current secret phrase`verifyOTP(string $otp, int|null $timestamp = null)``bool`Verifies a one-time password (TOTP) with an optional unix timestamp`createBackupCode(int $counter)``string`Creates a counter-based one-time password (HOTP) from the given counter value`verifyBackupCode(string $otp, int $counter)``bool`Verifies a counter-based backup code (HOTP) against the given counter value`getQRCode(string $label, string $issuer)``string`Creates a QR Code for use with a mobile authenticator application (TOTP) with the given label and issuer nameAnti clanker policy
-------------------

[](#anti-clanker-policy)

No fascist plagiarism machines were - or will ever be - used in creating of this and any of the bundled libraries. Clanker created pull requests will not be accepted. However, I have no control over 3rd-party libraries, but will avoid clankers wherever I can.

Disclaimer
----------

[](#disclaimer)

Use at your own risk!

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance82

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

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

Total

4

Last Release

95d ago

Major Versions

v1.x-dev → 2.0.02026-03-20

PHP version history (2 changes)1.0.0PHP ^7.4 || ^8.0

2.0.0PHP ^8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/592497?v=4)[smiley](/maintainers/codemasher)[@codemasher](https://github.com/codemasher)

---

Top Contributors

[![codemasher](https://avatars.githubusercontent.com/u/592497?v=4)](https://github.com/codemasher "codemasher (8 commits)")

---

Tags

2faauthenticatorqr-codeqrcodeotphotptotp2fagoogle2fatwo-factorMFAauthenticatortfarfc4226rfc6238

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/chillerlan-2fa-qrcode-bundle/health.svg)

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

###  Alternatives

[chillerlan/php-authenticator

A generator for counter- and time based 2-factor authentication codes (Google Authenticator). PHP 8.2+

56127.6k3](/packages/chillerlan-php-authenticator)[paragonie/multi-factor

Vendor-agnostic two-factor authentication library

142197.5k2](/packages/paragonie-multi-factor)[christian-riesen/otp

One Time Passwords, hotp and totp according to RFC4226 and RFC6238

885.4M6](/packages/christian-riesen-otp)[2amigos/2fa-library

2 Factor Authentication (2FA) library

34386.3k7](/packages/2amigos-2fa-library)[infocyph/otp

Simple &amp; Secure Generic OTP, OCRA (RFC6287), TOTP (RFC6238) &amp; HOTP (RFC4226) solution!

137.0k](/packages/infocyph-otp)[remotemerge/totp-php

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

2115.4k](/packages/remotemerge-totp-php)

PHPackages © 2026

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