Install the Multi-Factor Authentication feature

Edit on GitHub

This document describes how to install the Multi-Factor Authentication (MFA) feature.

Prerequisites

FEATURE VERSION INSTALLATION GUIDE
Spryker Core 202410.0 Install the Spryker Core feature
Customer Account Management 202410.0 Install the Customer Account Management feature

1) Install the required modules

Install the required modules using Composer:

composer require spryker/multi-factor-auth:"^0.1.0" spryker/multi-factor-auth-extension:"^1.0.0" --update-with-dependencies
Verification

Make sure the following modules have been installed:

MODULE EXPECTED DIRECTORY
MultiFactorAuth vendor/spryker/multi-factor-auth
MultiFactorAuthExtension vendor/spryker/multi-factor-auth-extension

2) Set up configuration

Set up the following configuration.

2.1) Configure code length

To configure the length of the authentication code, extend the MultiFactorAuthConfig class:

src/Pyz/Zed/MultiFactorAuth/MultiFactorAuthConfig.php
namespace Pyz\Zed\MultiFactorAuth;

use Spryker\Zed\MultiFactorAuth\MultiFactorAuthConfig as SprykerMultiFactorAuthConfig;

class MultiFactorAuthConfig extends SprykerMultiFactorAuthConfig
{
    /**
     * Specifications:
     * - Defines the length of the authentication code.
     * 
     * @api
     *
     * @return int
     */
    public function getCustomerCodeLength(): int
    {
        return 6;
    }
}

2.2) Configure code validity time

To configure the time interval in minutes during which an authentication code is valid, extend the MultiFactorAuthConfig class:

src/Pyz/Zed/MultiFactorAuth/MultiFactorAuthConfig.php
namespace Pyz\Zed\MultiFactorAuth;

use Spryker\Zed\MultiFactorAuth\MultiFactorAuthConfig as SprykerMultiFactorAuthConfig;

class MultiFactorAuthConfig extends SprykerMultiFactorAuthConfig
{
    /**
     * Specifications:
     * - Defines the time interval in minutes during which the authentication code is valid.
     * 
     * @api
     *
     * @return int
     */
    public function getCustomerCodeValidityTtl(): int
    {
        return 30;
    }
}

2.3) Configure brute-force protection limit

To configure the maximum number of failed MFA attempts a customer can make before brute force protection is triggered, extend the MultiFactorAuthConfig class:

src/Pyz/Zed/MultiFactorAuth/MultiFactorAuthConfig.php
namespace Pyz\Zed\MultiFactorAuth;

use Spryker\Zed\MultiFactorAuth\MultiFactorAuthConfig as SprykerMultiFactorAuthConfig;

class MultiFactorAuthConfig extends SprykerMultiFactorAuthConfig
{
    /**
     * Specifications:
     * - Defines the number of failed attempts a customer can make to enter the authentication code in order to prevent brute force attacks.
     * 
     * @api
     *
     * @return int
     */
    public function getCustomerAttemptLimit(): int
    {
        return 3;
    }
}

2.4) Configure protected routes and forms

Extend the MultiFactorAuthConfig class and configure the needed routes and forms to require MFA:

src/Pyz/Yves/MultiFactorAuth/MultiFactorAuthConfig.php
namespace Pyz\Yves\MultiFactorAuth;

use Spryker\Yves\MultiFactorAuth\MultiFactorAuthConfig as SprykerMultiFactorAuthConfig;

class MultiFactorAuthConfig extends SprykerMultiFactorAuthConfig
{
    /**
     * Specifications:
     * - Defines the routes and forms that require MFA authentication.
     * 
     * @api
     *
     * @return array<string, array<string>>
     */
    public function getEnabledRoutesAndForms(): array
    {
        return [
            'YOUR_ROUTE_NAME' => ['YOUR_FORM_NAME'],
        ];
    }
}

You can configure multiple forms on the same page to require MFA authentication.

3) Set up the database schema and transfer objects

Apply database changes and generate entity and transfer changes:

console propel:install
console transfer:generate
Verification

Make sure that the following changes have been applied in the database:

DATABASE ENTITY TYPE EVENT
spy_customer_multi_factor_auth table added
spy_customer_multi_factor_auth_codes table added
spy_customer_multi_factor_auth_codes_attempts table added
Verification

Make sure the following changes have been applied in transfer objects:

TRANSFER TYPE EVENT PATH
MultiFactorAuth class created src/Generated/Shared/Transfer/MultiFactorAuthTransfer
MultiFactorAuthCode class created src/Generated/Shared/Transfer/MultiFactorAuthCodeTransfer
MultiFactorAuthTypesCollection class created src/Generated/Shared/Transfer/MultiFactorAuthTypesCollectionTransfer
MultiFactorAuthValidationRequest class created src/Generated/Shared/Transfer/MultiFactorAuthValidationRequestTransfer
MultiFactorAuthValidationResponse class created src/Generated/Shared/Transfer/MultiFactorAuthValidationResponseTransfer

4) Add translations

  1. Append glossary according to your configuration:
data/import/common/common/glossary.csv
>multi_factor_auth.multi_factor_auth.list.title,"Set up Multi-Factor Authentication",en_US
multi_factor_auth.multi_factor_auth.list.title,"Multi-Faktor-Authentifizierung einrichten",de_DE
multi_factor_auth.error.invalid_code,"Invalid multi-factor authentication code. You have %remainingAttempts% attempt(s) left.",en_US
multi_factor_auth.error.invalid_code,"Ungültiger Multi-Faktor-Authentifizierungscode. Sie haben %remainingAttempts% Versuch(e) verbleiben.",de_DE
multi_factor_auth.error.attempts_exceeded,"You have exceeded the number of allowed attempts. Please try again after the page has been refreshed.",en_US
multi_factor_auth.error.attempts_exceeded,"Sie haben die Anzahl der zulässigen Versuche überschritten. Bitte versuchen Sie es erneut, nachdem die Seite aktualisiert wurde.",de_DE
multi_factor_auth.error.expired_code,"The multi-factor authentication code has expired. Please try again.",en_US
multi_factor_auth.error.expired_code,"Der Multi-Faktor-Authentifizierungscode ist abgelaufen. Bitte versuchen Sie es erneut.",de_DE
multi_factor_auth.error.authentication_method_not_selected,"Unable to proceed. A multi-factor authentication method must be selected. Please refresh the page and try again or contact support if the problem persists.",en_US
multi_factor_auth.error.authentication_method_not_selected,"Kann nicht fortgesetzt werden. Es muss eine Multi-Faktor-Authentifizierungsmethode ausgewählt werden. Bitte aktualisieren Sie die Seite und versuchen Sie es erneut oder wenden Sie sich an den Support, wenn das Problem weiterhin besteht.",de_DE
multi_factor_auth.method.select,"Select Authentication Method",en_US
multi_factor_auth.method.select,"Authentifizierungsmethode auswählen",de_DE
multi_factor_auth.code.validation,"Enter Authentication Code",en_US
multi_factor_auth.code.validation,"Authentifizierungscode eingeben",de_DE
multi_factor_auth.enter_code_for_method,"We sent the authentication code to your %type%. Type it below to continue.",en_US
multi_factor_auth.enter_code_for_method,"Wir haben Ihnen den Authentifizierungscode per %type% gesendet. Geben Sie ihn unten ein, um fortzufahren.",de_DE
multi_factor_auth.access_denied,"Access is strictly restricted until multi-factor authentication verification is successfully completed. Please ensure that JavaScript is enabled in your browser, refresh the page, and try again. If the problem persists, you may need to complete the multi-factor authentication process again.",en_US
multi_factor_auth.access_denied,"Zugriff ist bis zur erfolgreichen Vollziehung der Multi-Faktor-Authentifizierung eingeschränkt. Bitte stellen Sie sicher, dass JavaScript in Ihrem Browser aktiviert ist, die Seite aktualisieren und erneut versuchen. Wenn das Problem weiterhin besteht, sollten Sie die Multi-Faktor-Authentifizierungprozess erneut abschließen.",de_DE
multi_factor_auth.activation.success,"The multi-factor authentication has been activated.",en_US
multi_factor_auth.activation.success,"Die Multi-Faktor-Authentifizierung wurde aktiviert.",de_DE
multi_factor_auth.deactivation.success,"The multi-factor authentication has been deactivated.",en_US
multi_factor_auth.deactivation.success,"Die Multi-Faktor-Authentifizierung wurde deaktiviert.",de_DE
multi_factor_auth.activation.error,"The multi-factor authentication could not be activated.",en_US
multi_factor_auth.activation.error,"Die Multi-Faktor-Authentifizierung konnte nicht aktiviert werden.",de_DE
multi_factor_auth.deactivation.error,"The multi-factor authentication could not be deactivated.",en_US
multi_factor_auth.deactivation.error,"Die Multi-Faktor-Authentifizierung konnte nicht deaktiviert werden.",de_DE
multi_factor_auth.selection.error.required,"Please choose how you would like to verify your identity.",en_US
multi_factor_auth.selection.error.required,"Bitte wählen Sie aus, wie Sie Ihre Identität überprüfen möchten.",de_DE
multi_factor_auth.continue,"Continue",en_US
multi_factor_auth.continue,"Fortfahren",de_DE
multi_factor_auth.verify_code,"Verify Code",en_US
multi_factor_auth.verify_code,"Code überprüfen",de_DE
multi_factor_auth.required_options,"You must choose one option to continue!",en_US
multi_factor_auth.required_options,"Sie müssen eine Option auswählen, um fortzufahren!",de_DE
  1. Import data:
console data:import glossary
Verification

Make sure that, in the database, the configured data are added to the spy_glossary table.

5) Set up widgets

Register the following plugins to enable widgets:

PLUGIN SPECIFICATION PREREQUISITES NAMESPACE
MultiFactorAuthHandlerWidget Provides MFA handling functionality. SprykerShop\Yves\MultiFactorAuth\Widget
SetMultiFactorAuthMenuItemWidget Adds an MFA menu item to the customer profile navigation. SprykerShop\Yves\MultiFactorAuth\Widget
src/Pyz/Yves/ShopApplication/ShopApplicationDependencyProvider.php
<?php
namespace Pyz\Yves\ShopApplication;

use SprykerShop\Yves\ShopApplication\ShopApplicationDependencyProvider as SprykerShopApplicationDependencyProvider;
use Spryker\Yves\MultiFactorAuth\Widget\MultiFactorAuthHandlerWidget;
use Spryker\Yves\MultiFactorAuth\Widget\SetMultiFactorAuthMenuItemWidget;

class ShopApplicationDependencyProvider extends SprykerShopApplicationDependencyProvider
{
    protected function getGlobalWidgets(): array
    {
        return [
            SetMultiFactorAuthMenuItemWidget::class,
            MultiFactorAuthHandlerWidget::class,
        ];
    }
}

6) Set up behavior

Enable the following behaviors by registering the plugins:

PLUGIN SPECIFICATION PREREQUISITES NAMESPACE
CustomerMultiFactorAuthenticationHandlerPlugin Handles login MFA. Spryker\Yves\MultiFactorAuth\Plugin\AuthenticationHandler\Customer
MultiFactorAuthCustomerRouteProviderPlugin Provides routes for MFA. Spryker\Yves\MultiFactorAuth\Plugin\Router\Customer
MultiFactorAuthExtensionFormPlugin Provides form validation against corrupted requests. Spryker\Yves\MultiFactorAuth\Plugin\Form
src/Pyz/Yves/CustomerPage/CustomerPageDependencyProvider.php
namespace Pyz\Yves\CustomerPage;

use Spryker\Yves\MultiFactorAuth\Plugin\AuthenticationHandler\Customer\CustomerMultiFactorAuthenticationHandlerPlugin;
use SprykerShop\Yves\CustomerPage\CustomerPageDependencyProvider as SprykerShopCustomerPageDependencyProvider;

class CustomerPageDependencyProvider extends SprykerShopCustomerPageDependencyProvider
{
    protected function getCustomerAuthenticationHandlerPlugins(): array
    {
        return [
            new CustomerMultiFactorAuthenticationHandlerPlugin(),
        ];
    }
}
src/Pyz/Yves/Router/RouterDependencyProvider.php
namespace Pyz\Yves\Router;

use Spryker\Yves\Router\RouterDependencyProvider as SprykerRouterDependencyProvider;
use Spryker\Yves\MultiFactorAuth\Plugin\Router\Customer\MultiFactorAuthCustomerRouteProviderPlugin;

class RouterDependencyProvider extends SprykerRouterDependencyProvider
{
    protected function getRouteProvider(): array
    {
        return [
            new MultiFactorAuthCustomerRouteProviderPlugin(),
        ];
    }
}
src/Pyz/Yves/Router/RouterDependencyProvider.php
namespace Pyz\Yves\Form;

use Spryker\Yves\Form\FormDependencyProvider as SprykerFormDependencyProvider;
use Spryker\Yves\MultiFactorAuth\Plugin\Form\MultiFactorAuthExtensionFormPlugin;

class FormDependencyProvider extends SprykerFormDependencyProvider
{
    protected function getFormPlugins(): array
    {
        return [
            new MultiFactorAuthExtensionFormPlugin(),
        ];
    }
}

7) Set up the frontend

Add the following settings:

frontend/settings.json
{
    const globalSettings = {
        ...
        paths: {
            ...
            sprykerCore: './vendor/spryker/spryker/Bundles',
            ...
        };
        
    const paths = {
        ...
        sprykerCore: globalSettings.paths.sprykerCore,   
        ...
        };

    return {
        ...
        find: {
            componentEntryPoints: {
                dirs: [
                    ...
                    join(globalSettings.context, paths.sprykerCore),
                    ...
                ],
                ...
            },
            componentStyles: {
                dirs: [
                    ...
                    join(globalSettings.context, paths.sprykerCore),
                    ...
                ],
                ...
            },
            ...
        },
        ... 
    };
}
  1. Build the MFA frontend assets:
docker/sdk up --assets
Verification
  • Make sure the Set up Multi-Factor Authentication menu item is displayed in the navigation menu.
  • Clicking the menu should open the following page: https://yves.mysprykershop.com/multi-factor-auth/set.