PHPackages                             andrej-griniuk/cakephp-two-factor-auth - 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. andrej-griniuk/cakephp-two-factor-auth

ActiveCakephp-plugin[Authentication &amp; Authorization](/categories/authentication)

andrej-griniuk/cakephp-two-factor-auth
======================================

CakePHP auth component and provider fot two-factor authentication

4.0.0(1y ago)38102.9k↑14.7%15[2 issues](https://github.com/andrej-griniuk/cakephp-two-factor-auth/issues)[3 PRs](https://github.com/andrej-griniuk/cakephp-two-factor-auth/pulls)MITPHPPHP &gt;=8.1

Since Jan 27Pushed 6mo ago6 watchersCompare

[ Source](https://github.com/andrej-griniuk/cakephp-two-factor-auth)[ Packagist](https://packagist.org/packages/andrej-griniuk/cakephp-two-factor-auth)[ Docs](http://github.com/andrej-griniuk/cakephp-two-factor-auth)[ RSS](/packages/andrej-griniuk-cakephp-two-factor-auth/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (8)Dependencies (4)Versions (12)Used By (0)

[![Build Status](https://camo.githubusercontent.com/72c82e5e8e4862dbaddcded3c3675a3924b14e217711fcf867c3490ebad3f6c4/68747470733a2f2f6170702e7472617669732d63692e636f6d2f616e6472656a2d6772696e69756b2f63616b657068702d74776f2d666163746f722d617574682e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/andrej-griniuk/cakephp-two-factor-auth)[![codecov](https://camo.githubusercontent.com/b8c119bb1998ce22e1b2c7f4a5e2df639a5cc68d51c78f1f4097d491f3a1c705/68747470733a2f2f636f6465636f762e696f2f67682f616e6472656a2d6772696e69756b2f63616b657068702d74776f2d666163746f722d617574682f6272616e63682f6d61737465722f67726170682f62616467652e737667)](https://codecov.io/gh/andrej-griniuk/cakephp-two-factor-auth)[![License](https://camo.githubusercontent.com/942e017bf0672002dd32a857c95d66f28c5900ab541838c6c664442516309c8a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e7376673f7374796c653d666c61742d737175617265)](LICENSE)

TwoFactorAuth plugin for CakePHP
================================

[](#twofactorauth-plugin-for-cakephp)

This plugin provides two factor authentication functionality using [RobThree/TwoFactorAuth](https://github.com/RobThree/TwoFactorAuth) library. Basically, it works similar way CakePHP `FormAuthenticate` does. After submitting correct username/password, if the user has `secret` field set, he will be asked to enter a one-time code. **Attention:** it only provides authenticate provider and component and does not take care of users signup, management etc.

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

[](#requirements)

- CakePHP 5.0+ (use ***^1.3*** version for CakePHP &lt;3.7, ***^2.0*** version for CakePHP 3.x, ***^3.0*** version for CakePHP 4.x)

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

[](#installation)

You can install this plugin into your CakePHP application using [Composer](http://getcomposer.org).

```
composer require andrej-griniuk/cakephp-two-factor-auth
```

Usage
-----

[](#usage)

First of all you need to add `secret` field to your users table (field name can be changed to `TwoFactorAuth.Form` authenticator configuration).

```
ALTER TABLE `users` ADD `secret` VARCHAR(255) NULL;
```

Second, you need to load the plugin in your Application.php

```
$this->addPlugin('TwoFactorAuth');
```

Alternatively, execute the following line:

```
bin/cake plugin load TwoFactorAuth
```

You can see the default config values [here](https://github.com/andrej-griniuk/cakephp-two-factor-auth/blob/master/src/Authenticator/TwoFactorFormAuthenticator.php) and find out what do they mean [here](https://github.com/RobThree/TwoFactorAuth#usage). To overwrite them, pass them as `TwoFactorForm` authenticator values.

Then you need to set up authentication in your Application.php as you would [normally do it](https://book.cakephp.org/authentication/2/en/index.html#getting-started), but using `TwoFactorForm` authenticator instead of `Form`, e.g.:

```
class Application extends BaseApplication implements AuthenticationServiceProviderInterface
{
    public function bootstrap(): void
    {
        // Call parent to load bootstrap from files.
        parent::bootstrap();

        $this->addPlugin('TwoFactorAuth');
        $this->addPlugin('Authentication');
    }

    public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
    {
        // Various other middlewares for error handling, routing etc. added here.

        // Create an authentication middleware object
        $authentication = new AuthenticationMiddleware($this);

        // Add the middleware to the middleware queue.
        // Authentication should be added *after* RoutingMiddleware.
        // So that subdirectory information and routes are loaded.
        $middlewareQueue->add($authentication);

        return $middlewareQueue;
    }

    public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
    {
        $fields = [
            'username' => 'username',
            'password' => 'password'
        ];

        // Load identifiers
        $passwordIdentifier = [
           'Authentication.Password' => [
              'fields' => $fields,
           ],
        ];

        $service = new AuthenticationService();
        $service->setConfig([
            'unauthenticatedRedirect' => '/users/login',
            'queryParam' => 'redirect',
        ]);

        // Load the authenticators, you want session first
        $service->loadAuthenticator('Authentication.Session', [
           'identifier' => $passwordIdentifier,
        ]);
        $service->loadAuthenticator('TwoFactorAuth.TwoFactorForm', [
           'identifier' => $passwordIdentifier,
           'fields' => $fields,
           'loginUrl' => '/users/login',
        ]);

        return $service;
    }
}
```

Next, in your AppController load the `Authentication` and `TwoFactorAuth` components:

```
// in src/Controller/AppController.php
public function initialize()
{
    parent::initialize();

    $this->loadComponent('Authentication.Authentication');
    $this->loadComponent('TwoFactorAuth.TwoFactorAuth');
}
```

Once you have the middleware applied to your application you’ll need a way for users to login. A simplistic `UsersController` would look like:

```
class UsersController extends AppController
{
    public function beforeFilter(\Cake\Event\EventInterface $event)
    {
        parent::beforeFilter($event);

        $this->Authentication->allowUnauthenticated(['login', 'verify']);
    }

    public function login()
    {
        $result = $this->Authentication->getResult();
        if ($result->isValid()) {
            // If the user is logged in send them away.
            $target = $this->Authentication->getLoginRedirect() ?? '/home';

            return $this->redirect($target);
        }

        if ($this->request->is('post') && !$result->isValid()) {
            if ($result->getStatus() == \TwoFactorAuth\Authenticator\Result::TWO_FACTOR_AUTH_FAILED) {
                // One time code was entered and it's invalid
                $this->Flash->error('Invalid 2FA code');

                return $this->redirect(['action' => 'verify']);
            } elseif ($result->getStatus() == \TwoFactorAuth\Authenticator\Result::TWO_FACTOR_AUTH_REQUIRED) {
                // One time code is required and wasn't yet entered - redirect to the verify action
                return $this->redirect(['action' => 'verify']);
            } else {
                $this->Flash->error('Invalid username or password');
            }
        }
    }

    public function logout()
    {
        $this->Authentication->logout();

        return $this->redirect(['action' => 'login']);
    }

    public function verify()
    {
        // This action is only needed to render a vew with one time code form
    }
}
```

And `verify.php` would look like:

```

    Form->create(null, ['url' => ['action' => 'login']]) ?>

        Form->control('code') ?>

    Form->button(__('Continue')); ?>
    Form->end() ?>

```

Basically, it works same way CakePHP `Authentication.Form` authenticator does. After entering correct username/password combination, if the user has `secret` field (can be overwritten via `TwoFactorAuth.TwoFactorForm` configuration) set he will be redirected to the `verify` action where he is asked to enter a one-time code. There is no logic behind this action, it only renders the form that has to be submitted to the `loginAction` again with `code` field set.

You can access the [RobThree\\Auth\\TwoFactorAuth](https://github.com/RobThree/TwoFactorAuth) instance from your controller via `$this->TwoFactorAuth->getTfa()` or call some of the methods directly on `TwoFactorAuth` component. For example, you can generate user's secret and get QR code data URI for it this way:

```
$secret = $this->TwoFactorAuth->createSecret();
$secretDataUri = $this->TwoFactorAuth->getQRCodeImageAsDataUri('CakePHP:user@email.com', $secret);
```

Then display it in your view:

```
