triopsi / simple-two-factor
A simple two factor auth middleware for CakePHP
Installs: 50
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
Type:cakephp-plugin
Requires
- php: >=8.2
- bacon/bacon-qr-code: ^2.0
- cakephp/authentication: ^2.11
- cakephp/cakephp: ^4.5.8
- cakephp/migrations: @stable
- endroid/qr-code: ^5.0
- robthree/twofactorauth: ^3.0
Requires (Dev)
- phpunit/phpunit: ^8.5 || ^9.3
README
SimpleTwoFactor Plugin for CakePHP 4
This plugin provides a simple two-factor authentication (2FA) mechanism for CakePHP 4 applications. It uses the RobThree/TwoFactorAuth library to handle the generation and verification of 2FA codes.
- SimpleTwoFactor Plugin for CakePHP 4
Features
- Easy Integration: Seamlessly integrates with CakePHP 4's authentication system.
- Configurable: Provides multiple configuration options to customize the 2FA process.
- Middleware Support: Includes middleware to enforce 2FA on specific routes.
- QR Code Generation: Supports QR code generation for easy setup with 2FA apps.
- Customizable Views: Allows customization of the 2FA verification form.
- Session Management: Manages 2FA verification status using session keys.
- Multiple Algorithms: Supports various algorithms for generating 2FA codes (SHA1, SHA256, SHA512, MD5).
- Flexible Providers: Supports different QR code and random number generator providers.
- Security: Enhances security by adding an additional layer of authentication.
Requirements
- CakePHP 4.*
- PHP 8.2
Two-Factor Authentication (2FA) Workflow
Two-Factor Authentication adds an additional layer of security to the authentication process by requiring not only a username and password but also a unique code generated by an authentication app.
Workflow Overview
-
User Registration with 2FA Setup
- After registering or editing their profile, the user is presented with a QR code.
- The QR code contains a secret key.
- The user scans the QR code using an authentication app (e.g., Google Authenticator, Authy).
- This generates a secret pair shared between the server and the user’s device.
-
Subsequent Logins
- After entering the correct username and password, the user is prompted for a Two-Factor Authentication (2FA) code.
- The user opens the authentication app to retrieve the current TOTP (Time-based One-Time Password).
- The TOTP code is submitted to the server.
-
Verification and Access
- The server verifies the TOTP code using the shared secret.
- If the code is correct and matches the expected value, the user is granted access to the application.
- If the code is incorrect, access is denied.
Technical Details
- QR Code Generation: The server generates a QR code containing the secret.
- Secret Storage: The secret is securely stored in the user database.
- TOTP Code Verification: At each login, the server uses the stored secret to verify the TOTP code submitted by the user.
This process ensures that even if a user's primary credentials are compromised, unauthorized access is prevented without the second factor of authentication.
Installation
You can install this plugin into your CakePHP application using composer.
The recommended way to install composer packages is:
composer require triopsi/simple-two-factor
Configuration
1. User Secret Store
To save the secret and to assign the user. The plugin requires a secret field in the user table. This could look as follows:
ALTER TABLE `users` ADD `secret` VARCHAR(255) NULL;
or via migration:
bin/cake bake migration AddSecretToUsers secret:string[255]:null
2. Load the Plugin
Load the plugin in your Application.php
file:
public function bootstrap(): void { parent::bootstrap(); $this->addPlugin('SimpleTwoFactor'); }
Alternatively, execute the following line:
bin/cake plugin load SimpleTwoFactor
3. Add Middleware
Add the TwoFactorMiddleware to your middleware queue in src/Application.php
. Make sure to add it directly under the AuthenticationMiddleware.
use SimpleTwoFactor\Middleware\TwoFactorMiddleware; public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue { $middlewareQueue ->add(new ErrorHandlerMiddleware(Configure::read('Error'))) ->add(new AssetMiddleware()) ->add(new RoutingMiddleware($this)) ->add(new BodyParserMiddleware()) ->add(new AuthenticationMiddleware($this)) ->add(new TwoFactorMiddleware()); // Add TwoFactorMiddleware here return $middlewareQueue; }
Middleware Options
The TwoFactorMiddleware class provides several configuration options that can be customized to fit your application's needs. Below are the available options along with their explanations:
- userSessionKey: The session key to store the user in. Default is 'Auth'.
- codeField: The field name in the request that contains the 2FA code. Default is 'code'.
- redirectUrl: The URL to redirect unauthenticated users to. Default is '/users/verifytfa'.
- sessionKeyVerified: The session key to store the 2FA verified status. Default is '2fa_verified'.
- userKeySecret: The user key to store the 2FA secret. Default is '_2tfa'.
- isEnabled2faProperty: The user key to check if 2FA is enabled. Default is 'secret_2tfa'.
- urlChecker: The URL checker config. Default is 'Authentication.Default'.
- issuer: The issuer name displayed in the 2FA app. Default is null.
- digits: The number of digits in the 2FA code. Default is 6.
- period: The number of seconds a 2FA code is valid. Default is 30.
- algorithm: The algorithm used for generating the 2FA code. Options are 'sha1', 'sha256', 'sha512', 'md5'. Default is 'sha1'.
- qrcodeprovider: The QR code provider. Options are 'BaconQrCodeProvider', 'EndroidQrCodeProvider'. Default is 'BaconQrCodeProvider'.
- rngprovider: The random number generator provider. Default is null.
- timeprovider: The time provider. Default is null.
Example Configuration in Application.php
To configure the TwoFactorMiddleware in your CakePHP application, you need to set the options in the middleware method of your Application.php
file.
use SimpleTwoFactor\Middleware\TwoFactorMiddleware; public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue { $middlewareQueue ->add(new ErrorHandlerMiddleware(Configure::read('Error'))) ->add(new AssetMiddleware()) ->add(new RoutingMiddleware($this)) ->add(new BodyParserMiddleware()) ->add(new AuthenticationMiddleware($this)) ->add(new TwoFactorMiddleware([ 'redirectUrl' => '/users/verifytfa', 'userKeySecret' => 'secret_2tfa', 'isEnabled2faProperty' => 'secret_2tfa', 'issuer' => 'MyApp', 'digits' => 6, 'period' => 30, 'algorithm' => 'sha1', 'qrcodeprovider' => 'BaconQrCodeProvider' ])); return $middlewareQueue; }
! It is important that the TwoFactorMiddleware is placed after the AuthenticationMiddleware. If the order is incorrect, the plugin cannot work properly.
4. Example Controller Action
Create a method in your UsersController to handle the 2FA verification.
Example for UsersController.php
namespace App\Controller; use App\Controller\AppController; use SimpleTwoFactor\Result\Result; class UsersController extends AppController { public function initialize(): void { parent::initialize(); $this->loadComponent('SimpleTwoFactor.SimpleTwoFactor'); } public function verifytfa() { $result = $this->SimpleTwoFactor->getResult(); if ($result->getStatus() == Result::SIMPLE_TWO_FA_AUTH_FAILED) { $this->Flash->error('Invalid 2FA code'); } elseif ($result->getStatus() == Result::SIMPLE_TWO_FA_AUTH_SUCCESS) { $this->Flash->success('Welcome back!'); return $this->redirect($this->Auth->redirectUrl()); } } }
5. Example View
Create a view for the 2FA verification form.
Example for verifytfa.php
<?php $this->assign('title', __('Verify 2FA')); ?> <div class="card"> <div class="card-body"> <p class="text-center"><?php echo __('Please enter your 2FA code'); ?></p> <?php echo $this->Form->create(); ?> <fieldset> <legend><?php echo __('Please enter your 2FA code'); ?></legend> <?php echo $this->Form->control('code', ['label' => '2FA Code']); ?> </fieldset> <?php echo $this->Form->button(__('Verify')); ?> <?php echo $this->Form->end(); ?> </div> </div>
SimpleTwoFactorComponent for CakePHP 4
The SimpleTwoFactorComponent
provides methods to handle Two-Factor Authentication (2FA) in your CakePHP 4 application. This component allows you to generate secrets, verify codes, and create QR codes for easy setup with 2FA apps.
Features
- Generate 2FA Secrets: Create unique secrets for each user.
- Verify 2FA Codes: Verify the one-time codes generated by 2FA apps.
- Generate QR Codes: Generate QR codes for easy setup with 2FA apps.
Load the Component
Load the SimpleTwoFactorComponent
in your controller:
<?php // filepath: src/Controller/UsersController.php namespace App\Controller; use App\Controller\AppController; class UsersController extends AppController { public function initialize(): void { parent::initialize(); $this->loadComponent('SimpleTwoFactor.SimpleTwoFactor'); } }
Generating a QR Code
To generate a QR code for the user to scan with their 2FA app, you need to create a secret and then generate the QR code image.
<?php // filepath: src/Controller/UsersController.php namespace App\Controller; use App\Controller\AppController; class UsersController extends AppController { public function initialize(): void { parent::initialize(); $this->loadComponent('SimpleTwoFactor.SimpleTwoFactor'); } public function setup2fa() { $userIdentity = $this->Authentication->getIdentity(); $user = $this->Users->get($userIdentity->id); $secret = $this->SimpleTwoFactor->createSecret(); $qrCodeUrl = $this->SimpleTwoFactor->getQRCodeImageAsDataUri('MyApp:' . $user->email, $secret); if ($this->request->is('post')) { $data = $this->request->getData(); if ( true === $this->SimpleTwoFactor->verifyCode( $data['secret'], $data['code_app'] ) ) { $user->secret = $data['secret']; if ($this->Users->save($user)) { $this->Flash->success(__('The 2FA secret has been saved.')); return $this->redirect(['action' => 'index']); } else { $this->Flash->error(__('Unable to save the 2FA secret. Please try again.')); } } else { $this->Flash->error( __( 'Unfortunately the code you entered is incorrect. Please try again' ) ); } } $this->set(compact('qrCodeUrl', 'secret')); } }
Example View
Create a view for the 2FA setup form where the user can scan the QR code.
Example for setup2fa.php
<?php // filepath: src/templates/Users/setup2fa.php <?php $this->assign('title', __('Setup Two-Factor Authentication')); ?> <div class="card"> <div class="card-body"> <p class="text-center"><?php echo __('Scan the QR code with your 2FA app'); ?></p> <div class="text-center"> <img src="<?php echo $qrCodeUrl; ?>" alt="QR Code"> </div> <p class="text-center"> <?php echo __('After scanning, enter the code into the field and click the button below to save your 2FA secret.'); ?> </p> <?php echo $this->Form->create(); ?> <?php echo $this->Form->control('secret', array('type' => 'hidden', 'value'=>$secret)); ?> <?php echo $this->Form->control('code_app', array('type' => 'text')); ?> <?php echo $this->Form->button(__('Save 2FA Secret')); ?> <?php echo $this->Form->end(); ?> </div> </div>
Logout
Before the user logs out in the normal way, the session that generated the middleware must be deleted. The component contains the deleteVerfifiedSession()
method for this purpose. This can be called as follows:
<?php // filepath: src/Controller/UsersController.php namespace App\Controller; use App\Controller\AppController; class UsersController extends AppController { public function logout(): void { $result = $this->Authentication->getResult(); // regardless of POST or GET, redirect if user is logged in if ($result && $result->isValid()) { // Delete Session. $this->SimpleTwoFactor->deleteVerfifiedSession(); $this->Authentication->logout(); return $this->redirect(['controller' => 'Users', 'action' => 'login']); } } }
Bugs & Feedback
https://github.com/triopsi/SimpleTwoFactor/issues
License
Copyright (c) 2025, Triopsi and licensed under The MIT License.