Authentication
==============

This plugin uses the new CakePHP Authentication plugin [cakephp/authentication](https://github.com/cakephp/authentication/)
instead of CakePHP Authentication component, but don't worry, the default configuration should be enough for your
projects.

We've tried to simplify configuration as much as possible using defaults, but keep the ability to override them when needed.

Authentication Component
------------------------

The default behavior is to load the authentication component at ``UsersController``,
defining the default URLs for ``loginAction``, ``loginRedirect``, ``logoutRedirect`` but not requiring
the request to have an identity.

If you prefer to load the component yourself you can set ``Auth.AuthenticationComponent.load``:

```
Configure:write('Auth.AuthenticationComponent.load', false);
```

And load the component at any controller:

```
$authenticationConfig = Configure::read('Auth.AuthenticationComponent');
$this->loadComponent('Authentication.Authentication', $authenticationConfig);
$userId = $this->Authentication->getIdentity()->getIdentifier();
$user = $this->Authentication->getIdentity()->getOriginalData();
```

The default configuration for ``Auth.AuthenticationComponent`` is:

```php
[
    'load' => true,
    'loginRedirect' => '/',
    'requireIdentity' => false
]
```

Check [the component options at the its source code](https://github.com/cakephp/authentication/blob/master/src/Controller/Component/AuthenticationComponent.php#L38) for more infomation.

Authenticators
--------------

The ``cakephp/authentication`` plugin provides the main structure for the authenticators used in this plugin,
we also use some custom authenticators to work with social providers, reCaptcha and cookie. The default
list of authenticators includes:

- ``Authentication.Session``
- ``CakeDC/Auth.Form``
- ``Authentication.Token``
- ``CakeDC/Auth.Cookie``
- ``CakeDC/Users.Social`` which works with the ``SocialAuthMiddleware``
- ``CakeDC/Users.SocialPendingEmail``

If you enable ``OneTimePasswordAuthenticator.login`` we also load the ``CakeDC/Auth.TwoFactor``

These authenticators should be enough for your application, but you can easily customize it
setting the ``Auth.Authenticators`` config key.

These authenticators are loaded by the ``\CakeDC\Users\Loader\AuthenticationServiceLoader`` class in the ``loadAuthenticators`` method. See [Authentication Service Loader](#authentication-service-loader) on how to adjust it to your needs.

For example, if you want to add the JWT authenticator you must add the following to your ``config/users.php`` file:

```php
'Auth.Authenticators.Jwt' => [
    'queryParam' => 'token',
    'skipTwoFactorVerify' => true,
    'className' => 'Authentication.Jwt',
],
```

The ``skipTwoFactorVerify`` option is used to skip the two factor flow for a given authenticator

Identifiers
-----------

The identifiers are defined to work correctly with the default authenticators. We are using these identifiers:

- `Authentication.Password`, for `Form` authenticator
- `CakeDC/Users.Social`, for `Social` and `SocialPendingEmail` authenticators
- `Authentication.Token`, for `Token` authenticator

As you add more authenticators you may also need to add other identifiers. Please see [the identifiers available in the official CakePHP Authentication plugin documentation](https://book.cakephp.org/authentication/3/en/identifiers.html).

> **Note:** Configuring identifiers globally via `Auth.Identifiers` is deprecated. Please move each identifier's configuration into the `identifier` key within its specific authenticator under `Auth.Authenticators`.

The default list for `Auth.Authenticators.Form.identifier` is:

```php
'identifier' => [
    'Authentication.Password' => [
        'className' => 'Authentication.Password',
        'fields' => [
            'username' => ['username', 'email'],
            'password' => 'password'
        ],
        'resolver' => [
            'className' => 'Authentication.Orm',
            'finder' => 'active'
        ],
    ],
]
```

These identifiers are loaded by the `\CakeDC\Users\Loader\AuthenticationServiceLoader` class. See [Authentication Service Loader](#authentication-service-loader) on how to adjust it to your needs.

Account lockout policy
----------------------
Lock a users account after a number of failed password attempts in a certain time window.

To enable this, update your `config/users.php` file with:

```php
'Auth.Authenticators.Form.identifier.Authentication.Password.className' => 'CakeDC/Users.PasswordLockout',
'Auth.PasswordRehash' => [
    'identifiers' => ['PasswordLockout'],
],
```

Additionally, you can set the number of attempts until lock, lockout time, time window and more, e.g.:

```php
'Auth.Authenticators.Form.identifier.Authentication.Password' => [
    'className' => 'CakeDC/Users.PasswordLockout',
    'lockoutHandler' => [
        'timeWindowInSeconds' => 30 * 60, // 30 minutes (default is 15 minutes)
        'lockoutTimeInSeconds' => 100 * 60, // 100 minutes (default is 30 minutes)
        'numberOfAttemptsFail' => 4, // default is 6 attempts
        'failedPasswordAttemptsModel' => 'CakeDC/Users.FailedPasswordAttempts',
        'userLockoutField' => 'lockout_time', // Field in user entity used to lock the user.
        'usersModel' => 'Users',
        'userForeignKeyField' => 'user_id', // Field defined in the 'failed_password_attempts' table as foreignKey of the model Users.
    ],
],
'Auth.PasswordRehash' => [
    'identifiers' => ['PasswordLockout'],
],
```


Handling Login Result
---------------------

For both form login and social login we use a base component ``CakeDC/Users.Login`` to handle the login.
It checks the result of the authentication service and either redirects the user or shows an authentication
error. It provides some error messages for specific authentication results. Please check the ``config/users.php`` file.

To use a custom component to handle the login you should update your ``config/users.php`` file with:

```php
'Auth.SocialLoginFailure.component' => 'MyLoginA',
'Auth.FormLoginFailure.component' => 'MyLoginB',
```

The default configuration is:

```php
[
    ...
    'Auth' => [
        ...
        'SocialLoginFailure' => [
            'component' => 'CakeDC/Users.Login',
            'defaultMessage' => __d('cake_d_c/users', 'Could not proceed with social account. Please try again'),
            'messages' => [
                'FAILURE_USER_NOT_ACTIVE' => __d(
                    'cake_d_c/users',
                    'Your user has not been validated yet. Please check your inbox for instructions'
                ),
                'FAILURE_ACCOUNT_NOT_ACTIVE' => __d(
                    'cake_d_c/users',
                    'Your social account has not been validated yet. Please check your inbox for instructions'
                )
            ],
            'targetAuthenticator' => 'CakeDC\Users\Authenticator\SocialAuthenticator'
        ],
        'FormLoginFailure' => [
            'component' => 'CakeDC/Users.Login',
            'defaultMessage' => __d('cake_d_c/users', 'Username or password is incorrect'),
            'messages' => [
                'FAILURE_INVALID_RECAPTCHA' => __d('cake_d_c/users', 'Invalid reCaptcha'),
            ],
            'targetAuthenticator' => 'CakeDC\Auth\Authenticator\FormAuthenticator'
        ]
        ...
    ]
]
```

Authentication Service Loader
-----------------------------

To make the integration with CakePHP Authenication plugin easier we load the authenticators and identifiers
defined at the ``Auth`` configuration key.

If the default configuration is not enough for your project's needs you may create a custom loader extending the
default loader provided.

For example, create a file ``src/Loader/AppAuthenticationServiceLoader.php``:

```php
<?php
namespace App\Loader;

use \CakeDC\Users\Loader\AuthenticationServiceLoader;

class AppAuthenticationServiceLoader extends AuthenticationServiceLoader
{
    /**
     * Load the authenticators with my custom condition
     *
     * @param \CakeDC\Auth\Authentication\AuthenticationService $service Authentication service to load identifiers
     *
     * @return void
     */
    protected function loadAuthenticators($service)
    {
        parent::loadAuthenticators($service);

        if (\Cake\Core\Configure::read('MyApp.enabledCustom')) {
            $service->loadAuthenticator('MyCustom', []);
        }
    }
}
```

Add the following to your ``config/users.php`` configuration to change the authentication service loader:

```php
'Auth.Authentication.serviceLoader' => \App\Loader\AppAuthenticationServiceLoader::class,
```


Password Reset
--------------

When a user requests to reset their password, the plugin needs to find their account. By default, it searches using both the `username` and `email` fields.
You can customize which fields are used for this lookup by configuring the `Users.PasswordReset.findWith` setting in your `config/users.php` file.

The value should be an array of column names that exist in your `users` table. The system will dynamically build a query to search using these fields.

For example, if your application only uses email for identification, you can restrict the search to just the `email` column to avoid errors and improve performance:

```php
// in config/users.php
'Users' => [
    'PasswordReset' => [
        'findWith' => ['email']
    ],
]
```

If you need to search by `username` and another custom field, you could configure it like this:

```php
// in config/users.php
'Users' => [
    'PasswordReset' => [
        'findWith' => ['username', 'legacy_user_id']
    ],
]
```
