# Auth challenges

****

Authentication challenges are used to generate and verify codes for logging in. Kirby ships with an email challenge that sends a random code via email.

You can create additional authentication challenges (e.g. TOTP, SMS, hardware tokens) with the `authChallenges` plugin extension:

## Example plugin

```php
<?php

namespace Superwoman;

use Kirby;
use Kirby\Cms\Auth\Challenge;
use Kirby\Cms\User;

class CustomChallenge extends Challenge
{
    /**
     * Checks whether the challenge is available
     * for the passed user and purpose
     *
     * @param \Kirby\Cms\User $user User the code will be generated for
     * @param 'login'|'password-reset'|'2fa' $mode Purpose of the code
     * @return bool
     */
    public static function isAvailable(User $user, string $mode): bool
    {
        // check the plugin configuration and the requirements of your challenge
        return true;
    }

    /**
     * Generates a random one-time auth code and returns that code
     * for later verification
     *
     * @param \Kirby\Cms\User $user User to generate the code for
     * @param array $options Details of the challenge request:
     *                       - 'mode': Purpose of the code ('login', 'password-reset' or '2fa')
     *                       - 'timeout': Number of seconds the code will be valid for
     * @return string|null The generated and sent code or `null` in case
     *                     there was no code to generate by this algorithm
     */
    public static function create(User $user, array $options): ?string
    {
        // if you generate a code yourself, send it and return it here
        // return 'generated-code';

        // if the code gets generated by the user, you don't need to anything here
        return null;
    }

    /**
     * Verifies the provided code against the created one
     *
     * @param \Kirby\Cms\User $user User to check the code for
     * @param string $code Code to verify
     * @return bool
     */
    public static function verify(User $user, string $code): bool
    {
        // you only need to implement this method if you need to
        // verify a code that was generated by the user;
        // if you returned a code from `create()`, then *don't*
        // define this method to use the automatic internal logic

        return false;
    }
}

Kirby::plugin('superwoman/custom-challenge', [
    'authChallenges' => [
        'custom' => CustomChallenge::class
    ],
    'translations' => [
        'en' => [
            // Placeholder for the code field with the general format of the code
            'login.code.placeholder.custom' => '000 000',

            // Help text below the code field
            'login.code.text.custom' => 'If your email address is registered, the requested code was sent via *custom*.'
        ]
    ]
]);
```

## How configuration can impact your plugin

### Challenge order

Kirby will try all installed challenges <a href="https://getkirby.com/docs/reference/system/options/auth#configuration-of-the-challenge-priority">in the configured order</a>.

With the `isAvailable()` method, the challenges can tell Kirby if the challenge can be used to authenticate the current user. If `false` is returned, the next challenge is tried. This is useful for challenges that have additional requirements, e.g. a TOTP challenge needs a prior registration, an SMS challenge needs the mobile number etc.

### Code timeout

Users can define a <a href="https://getkirby.com/docs/reference/system/options/auth#authentication-challenges__code-timeout">code timeout</a> for generated codes.

This affects your plugin if you return a generated code from the `create()` method. Kirby will automatically check the timeout when verifying the entered code (even a valid code won't be accepted if it was entered after the timeout).

If your challenge *doesn't* generate and return a code but the code instead gets generated by the user themselves (e.g. via TOTP or with a hardware token), the code timeout does *not* have an effect. However you can use the option `auth.challenge.timeout` for your own validation if applicable.