Two-factor authentication (2fa)
Sharp provides a two-factor authentication (2fa) system, out of the box. You can configure it like this:
class SharpServiceProvider extends SharpAppServiceProvider
{
protected function configureSharp(SharpConfigBuilder $config): void
{
$config
->enable2faByNotification()
// or ->enable2faByTotp()
// or ->enable2faCustom()
// [...]
}
}With this configuration, Sharp will display a second screen to the user, after a successful password based login, asking for a 6-digit code. This code will be provided to the user depending on the configuration:
enable2faByNotification(): a notification is sent to the user (email by default, but you can tweak this, see below)enable2faByTotp(): the user must use a 2fa authenticator app (like Google or Microsoft Authenticator) to generate a codeenable2faCustom(): in this case you must provide your own 2fa handler, see below.
Handling the 2fa code via a notification
WARNING
To be able to receive notifications, your User model must use the Illuminate\Notifications\Notifiable trait.
With this option, Sharp will send a notification to the user, containing the 6-digit code. By default, this notification is sent by email. You can override this behavior by providing your own handler class which must extend Code16\Sharp\Auth\TwoFactor\Sharp2faNotificationHandler:
class SharpServiceProvider extends SharpAppServiceProvider
{
protected function configureSharp(SharpConfigBuilder $config): void
{
$config
->enable2faCustom(\App\Sharp\My2faNotificationHandler::class)
// [...]
}
}class My2faNotificationHandler extends Sharp2faNotificationHandler
{
protected function getNotification(int $code): Notification
{
return new My2faDefaultNotification($code);
}
}Handling the 2fa code via a TOTP authenticator app
WARNING
This implies a bit more work to implement, but this method is more secure than the notification handler. The out-of-the-box implementation implies that you leverage Eloquent.
With this option, Sharp will ask the user to register the app in a 2fa authenticator (like Google or Microsoft Authenticator). The user will have to provide a 6-digit code generated by the app to Sharp, in order to be authenticated.
First, require two packages needed for this feature:
composer require pragmarx/google2fa-laravel
composer require bacon/bacon-qr-codeThen, you'll need to configure the totp handler:
class SharpServiceProvider extends SharpAppServiceProvider
{
protected function configureSharp(SharpConfigBuilder $config): void
{
$config
->enable2faByTotp()
// [...]
}
}Add three columns in the users table to store the 2fa secret, 2fa recovery codes and 2fa confirmation timestamp. Here’s a migration example:
return new class extends Migration
{
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->text('two_factor_secret')
->after('password')
->nullable();
$table->text('two_factor_recovery_codes')
->after('two_factor_secret')
->nullable();
$table->timestamp('two_factor_confirmed_at')
->after('two_factor_recovery_codes')
->nullable();
});
}
};After that, you must provide a way for your users to register the app in their 2fa authenticator. Sharp can help a lot with that, by extending two built-in Commands; one for activating and one for deactivating 2fa. The idea is to add these commands in a "profile" SingleShow, or in some related Entity List.
class Activate2faCommand extends SingleInstanceWizardCommand
{
use Code16\Sharp\Auth\TwoFactor\Commands\Activate2faViaTotpWizardCommandTrait;
}class Deactivate2faCommand extends SingleInstanceCommand
{
use Code16\Sharp\Auth\TwoFactor\Commands\Deactivate2FaViaTotpSingleInstanceCommandTrait;
// or Code16\Sharp\Auth\TwoFactor\Commands\Deactivate2FaViaTotpEntityCommandTrait
}The first command is a wizard which will guide the user through the registration process; the second one is to deactivate the 2fa. Both require to enter a password. You can tweak these commands and provide your own implementation if needed.
Finally, if you need more control, you can provide your own handler class via ->enable2faCustom(), which must extend Code16\Sharp\Auth\TwoFactor\Sharp2faTotpHandler.
Enabling 2fa for some users only
Providing your own handler implementation, you can override the isEnabledFor method to enable 2fa for some users only:
class My2faNotificationHandler extends Sharp2faNotificationHandler // or Sharp2faTotpHandler
{
public function isEnabledFor($user): bool
{
return $user->hasGroup('sharp');
}
}Customize the 2fa form
You can also change the default help text display above the 2fa form in the handler:
class My2faNotificationHandler extends Sharp2faNotificationHandler // or Sharp2faTotpHandler
{
public function formHelpText(): string
{
return sprintf(
'You code was sent via SMS to your phone number ending in %s',
substr(User::find($this->userId())->phone, -4)
);
}
}