Two-Factor Authentication for all your users out-of-the-box.

Overview

Two Factor

Latest Version on Packagist Latest stable test run Codecov coverage Maintainability Sonarcloud Status Laravel Octane Compatibility

On-premises Two-Factor Authentication for all your users out of the box.

use Illuminate\Support\Facades\Auth;
use Laragear\TwoFactor\TwoFactor;

Auth::attemptWhen($request->only('email', 'password'), TwoFactor::hasCode());

This package enables TOTP authentication using 6 digits codes. No need for external APIs.

Keep this package free

Your support allows me to keep this package free, up-to-date and maintainable. Alternatively, you can spread the word!

Requirements

  • Laravel 9.x or later
  • PHP 8.0 or later

Installation

Fire up Composer and require this package in your project.

composer require laragear/two-factor

That's it.

How this works

This package adds a Contract to detect if, after the credentials are deemed valid, should use Two-Factor Authentication as a second layer of authentication.

It includes a custom view and a callback to handle the Two-Factor authentication itself during login attempts.

Works without middleware or new guards, but you can go full manual if you want.

Set up

  1. First, run the migration in your application.
php artisan migrate

This will create a table to handle the Two-Factor Authentication information for each model you want to attach to 2FA.

  1. Add the TwoFactorAuthenticatable contract and the TwoFactorAuthentication trait to the User model, or any other model you want to make Two-Factor Authentication available.
<?php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Laragear\TwoFactor\TwoFactorAuthentication;
use Laragear\TwoFactor\Contracts\TwoFactorAuthenticatable;

class User extends Authenticatable implements TwoFactorAuthenticatable
{
    use TwoFactorAuthentication;
    
    // ...
}

The contract is used to identify the model using Two-Factor Authentication, while the trait conveniently implements the methods required to handle it.

That's it. You're now ready to use 2FA in your application.

Enabling Two-Factor Authentication

To enable Two-Factor Authentication for the User, he must sync the Shared Secret between its Authenticator app and the application.

Some free Authenticator Apps are iOS Authenticator, FreeOTP, Authy, andOTP, Google Authenticator, and Microsoft Authenticator, to name a few.

To start, generate the needed data using the createTwoFactorAuth() method. Once you do, you can show the Shared Secret to the User as a string or QR Code (encoded as SVG) in your view.

use Illuminate\Http\Request;

public function prepareTwoFactor(Request $request)
{
    $secret = $request->user()->createTwoFactorAuth();
    
    return view('user.2fa', [
        'qr_code' => $secret->toQr(),     // As QR Code
        'uri'     => $secret->toUri(),    // As "otpauth://" URI.
        'string'  => $secret->toString(), // As a string
    ]);
}

When you use createTwoFactorAuth() on someone with Two-Factor Authentication already enabled, the previous data becomes permanently invalid. This ensures a User never has two Shared Secrets enabled at any given time.

Then, the User must confirm the Shared Secret with a Code generated by their Authenticator app. The confirmTwoFactorAuth() method will automatically enable it if the code is valid.

use Illuminate\Http\Request;

public function confirmTwoFactor(Request $request)
{
    $request->validate([
        'code' => 'required|numeric'
    ]);
    
    $activated = $request->user()->confirmTwoFactorAuth($request->code);
    
    // ...
}

If the User doesn't issue the correct Code, the method will return false. You can tell the User to double-check its device's timezone, or create another Shared Secret with createTwoFactorAuth().

Recovery Codes

Recovery Codes are automatically generated each time the Two-Factor Authentication is enabled. By default, a Collection of ten one-use 8-characters codes are created.

You can show them using getRecoveryCodes().

use Illuminate\Http\Request;

public function confirmTwoFactor(Request $request)
{
    if ($request->user()->confirmTwoFactorAuth($request->code)) {
        return $request->user()->getRecoveryCodes();
    }
    
    return 'Try again!';
}

You're free on how to show these codes to the User, but ensure you show them at least one time after a successfully enabling Two-Factor Authentication, and ask him to print them somewhere.

These Recovery Codes are handled automatically when the User sends it instead of a TOTP code. If it's a recovery code, the package will use and mark it as invalid, so it can't be used again.

The User can generate a fresh batch of codes using generateRecoveryCodes(), which replaces the previous batch.

use Illuminate\Http\Request;

public function showRecoveryCodes(Request $request)
{
    return $request->user()->generateRecoveryCodes();
}

If the User depletes his recovery codes without disabling Two-Factor Authentication, or Recovery Codes are deactivated, he may be locked out forever without his Authenticator app. Ensure you have countermeasures in these cases.

Logging in

To login, the user must issue a TOTP code along their credentials. Simply use Auth::attemptWhen() with TwoFactor, which will automatically do the checks for you. By default, it checks for the 2fa_code input name, but you can issue your own.

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laragear\TwoFactor\TwoFactor;

public function login(Request $request)
{
    // ...
    
    $credentials = $request->only('email', 'password');
    
    if (Auth::attemptWhen($credentials, TwoFactor::hasCode(), $request->filled('remember'))) {
        return redirect()->home(); 
    }
    
    return back()->withErrors(['email' => 'Bad credentials'])
}

Behind the scenes, once the User is retrieved and validated from your guard of choice, it makes an additional check for a valid TOTP code. If it's invalid, it will return false and no authentication will happen.

For Laravel Breeze, you may need to edit the LoginRequest::authenticate() call. For Laravel Fortify and Jetstream, you may need to set a custom callback with the Fortify::authenticateUsing() method.

Separating the TOTP requirement

In some occasions you will want to tell the user the authentication failed not because the credentials were incorrect, but because of the TOTP code was invalid.

You can use the hasCodeOrFails() method that does the same, but throws a validation exception, which is handled gracefully by the framework. It even accepts a custom message in case of failure, otherwise a default translation line will be used.

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laragear\TwoFactor\TwoFactor;

public function login(Request $request)
{
    // ...
    
    $credentials = $request->only('email', 'password');
    
    if (Auth::attemptWhen($credentials, TwoFactor::hasCodeOrFails(), $request->filled('remember'))) {
        return redirect()->home(); 
    }
    
    return back()->withErrors(['email', 'Authentication failed!']);
}

Since InvalidCodeException extends the ValidationException, you can catch it and do more complex things, like those fancy views that hold the login procedure until the correct TOTP code is issued.

Deactivation

You can deactivate Two-Factor Authentication for a given User using the disableTwoFactorAuth() method. This will automatically invalidate the authentication data, allowing the User to log in with just his credentials.

public function disableTwoFactorAuth(Request $request)
{
    $request->user()->disableTwoFactorAuth();
    
    return 'Two-Factor Authentication has been disabled!';
}

Events

The following events are fired in addition to the default Authentication events.

  • TwoFactorEnabled: An User has enabled Two-Factor Authentication.
  • TwoFactorRecoveryCodesDepleted: An User has used his last Recovery Code.
  • TwoFactorRecoveryCodesGenerated: An User has generated a new set of Recovery Codes.
  • TwoFactorDisabled: An User has disabled Two-Factor Authentication.

You can use TwoFactorRecoveryCodesDepleted to tell the User to create more Recovery Codes or mail them some more.

Middleware

TwoFactor comes with two middleware for your routes: 2fa.enabled and 2fa.confirm.

To avoid unexpected results, middleware only act on your users models implementing the TwoFactorAuthenticatable contract. If a user model doesn't implement it, the middleware will bypass any 2FA logic.

Require 2FA

If you need to ensure the User has Two-Factor Authentication enabled before entering a given route, you can use the 2fa.enabled middleware. Users who implement the TwoFactorAuthenticatable contract and have 2FA disabled will be redirected to a route name containing the warning, which is 2fa.notice by default.

Route::get('system/settings', function () {
    // ...
})->middleware('2fa.enabled');

You can implement the view easily with the one included in this package, optionally with a URL to point the user to enable 2FA:

use Illuminate\Support\Facades\Route;

Route::view('2fa-required', 'two-factor::notice', [
    'url' => url('settings/2fa')
])->name('2fa.notice');

Confirm 2FA

Much like the password.confirm middleware, you can also ask the user to confirm entering a route by issuing a 2FA Code with the 2fa.confirm middleware.

Route::get('api/token', function () {
    // ...
})->middleware('2fa.confirm');

Route::post('api/token/delete', function () {
    // ...
})->middleware('2fa.confirm');

The middleware will redirect the user to the named route 2fa.confirm by default, but you can change it in the first parameter. To implement the receiving routes, TwoFactor comes with the Confirm2FACodeController anda view you can use for a quick start.

use Illuminate\Support\Facades\Route;
use Laragear\TwoFactor\Http\Controllers\ConfirmTwoFactorCodeController;

Route::get('2fa-confirm', [ConfirmTwoFactorCodeController::class, 'form'])
    ->name('2fa.confirm');

Route::post('2fa-confirm', [ConfirmTwoFactorCodeController::class, 'confirm']);

Since a user without 2FA enabled won't be asked for a code, you can combine the middleware with 2fa.require to ensure confirming is mandatory for users without 2FA enabled.

use Illuminate\Support\Facades\Route;

Route::get('api/token', function () {
    // ...
})->middleware('2fa.require', '2fa.confirm');

Validation

Sometimes you may want to manually trigger a TOTP validation in any part of your application for the authenticated user. You can validate a TOTP code for the authenticated user using the topt rule.

public function checkTotp(Request $request)
{
    $request->validate([
        'code' => 'totp'
    ]);

    // ...
}

This rule will succeed only if the user is authenticated, it has Two-Factor Authentication enabled, and the code is correct or is a recovery code.

You can enforce the rule to NOT use recovery codes using totp:code.

Translations

TwoFactor comes with translation files that you can use immediately in your application. These are also used for the validation rule.

public function disableTwoFactorAuth()
{
    // ...

    session()->flash('message', trans('two-factor::messages.success'));

    return back();
}

To add your own language, publish the translation files. These will be located in lang/vendor/two-factor:

php artisan vendor:publish --provider="Laragear\TwoFactor\TwoFactorServiceProvider" --tag="translations"

Configuration

To further configure the package, publish the configuration file:

php artisan vendor:publish --provider="Laragear\TwoFactor\TwoFactorServiceProvider" --tag="config"

You will receive the config/two-factor.php config file with the following contents:

return [
    'cache' => [
        'store' => null,
        'prefix' => '2fa.code'
    ],
    'recovery' => [
        'enabled' => true,
        'codes' => 10,
        'length' => 8,
	],
    'safe_devices' => [
        'enabled' => false,
        'max_devices' => 3,
        'expiration_days' => 14,
	],
    'confirm' => [
        'key' => '_2fa',
        'time' => 60 * 3,
    ],
    'secret_length' => 20,
    'issuer' => env('OTP_TOTP_ISSUER'),
    'totp' => [
        'digits' => 6,
        'seconds' => 30,
        'window' => 1,
        'algorithm' => 'sha1',
    ],
    'qr_code' => [
        'size' => 400,
        'margin' => 4
    ],
];

Cache Store

return  [
    'cache' => [
        'store' => null,
        'prefix' => '2fa.code'
    ],
];

RFC 6238 states that one-time passwords shouldn't be able to be usable more than once, even if is still inside the time window. For this, we need to use the Cache to ensure the same code cannot be used again.

You can change the store to use, which it's the default used by your application, and the prefix to use as cache keys, in case of collisions.

Recovery

return [
    'recovery' => [
        'enabled' => true,
        'codes' => 10,
        'length' => 8,
    ],
];

Recovery codes handling are enabled by default, but you can disable it. If you do, ensure Users can authenticate by other means, like sending an email with a link to a signed URL that logs him in and disables Two-Factor Authentication, or SMS.

The number and length of codes generated is configurable. 10 Codes of 8 random characters are enough for most authentication scenarios.

Safe devices

return [
    'safe_devices' => [
        'enabled' => false,
        'max_devices' => 3,
        'expiration_days' => 14,
    ],
];

Enabling this option will allow the application to "remember" a device using a cookie, allowing it to bypass Two-Factor Authentication once a code is verified in that device. When the User logs in again in that device, it won't be prompted for a 2FA Code again.

The cookie contains a random value which is checked against a list of safe devices saved for the authenticating user. It's considered a safe device if the value matches and has not expired.

There is a limit of devices that can be saved, but usually three is enough (phone, tablet and PC). New devices will displace the oldest devices registered. Devices are considered no longer "safe" until a set amount of days.

You can change the maximum number of devices saved and the amount of days of validity once they're registered. More devices and more expiration days will make the Two-Factor Authentication less secure.

When disabling Two-Factor Authentication, the list of devices is flushed.

Confirmation Middleware

return [
    'confirm' => [
        'key' => '_2fa',
        'time' => 60 * 3,
    ],
];

These control which key to use in the session for handling 2fa.confirm middleware, and the expiration time in minutes.

Secret length

return [
    'secret_length' => 20,
];

This controls the length (in bytes) used to create the Shared Secret. While a 160-bit shared secret is enough, you can tighten or loosen the secret length to your liking.

It's recommended to use 128-bit or 160-bit because some Authenticator apps may have problems with non-RFC-recommended lengths.

TOTP Configuration

return [
    'issuer' => env('OTP_TOTP_ISSUER'),
    'totp' => [
        'digits' => 6,
        'seconds' => 30,
        'window' => 1,
        'algorithm' => 'sha1',
    ],
];

This controls TOTP code generation and verification mechanisms:

  • Issuer: The name of the issuer of the TOTP. Default is the application name.
  • TOTP Digits: The amount of digits to ask for TOTP code.
  • TOTP Seconds: The number of seconds a code is considered valid.
  • TOTP Window: Additional steps of seconds to keep a code as valid.
  • TOTP Algorithm: The system-supported algorithm to handle code generation.

This configuration values are always passed down to the authentication app as URI parameters:

otpauth://totp/Laravel:[email protected]?secret=THISISMYSECRETPLEASEDONOTSHAREIT&issuer=Laravel&label=taylor%40laravel.com&algorithm=SHA1&digits=6&period=30

These values are printed to each 2FA data record inside the application. Changes will only take effect for new activations.

Do not edit these parameters if you plan to use publicly available Authenticator apps, since some of them may not support non-standard configuration, like more digits, different period of seconds or other algorithms.

QR Code Configuration

return [
    'qr_code' => [
        'size' => 400,
        'margin' => 4
    ],
];

This controls the size and margin used to create the QR Code, which are created as SVG.

Laravel Octane Compatibility

  • There are no singletons using a stale application instance.
  • There are no singletons using a stale config instance.
  • There are no singletons using a stale request instance.
  • There are no static properties written during a request.

There should be no problems using this package with Laravel Octane.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

License

This specific package version is licensed under the terms of the MIT License, at time of publishing.

Laravel is a Trademark of Taylor Otwell. Copyright © 2011-2022 Laravel LLC.

Comments
  • 2fa.confirm middleware do not attach to POST login route.

    2fa.confirm middleware do not attach to POST login route.

    Checklist

    • [X] I have checked my stack trace and logs.
    • [X] I can reproduce this in isolation.
    • [ ] I can suggest a workaround or PR.

    Dependencies

    • PHP: 8.1.3 Linux
    • Laravel: 9.1.0

    Description

    This is NOT a bug report at the moment.

    I just upgraded the project I'm working on to L9. As such I had to move from darkghosthunter/laraguard to laragear/two-factor. This change required a lot of code change and now I'm not so sure if I took the best path.

    My app has no frontend. It's just a backend where all the action happens. All users must be logged in, but not everyone may have 2FA enabled. The 2fa_code is asked on a dedicated form just after the login one IF the user has 2FA enabled.

    So I thought to do this in routes/web.php:

    Route::post('/', 'Auth\LoginController@login')
        ->name('login.submit')
        ->middleware('2fa.confirm');
    

    But nope... it won't work that way. At least it didn't here. Users with 2FA enabled are just logged in as soon as they submit their login credentials. No 2FA form page presented as it used to be in darkghosthunter/laraguard wonderful magic listeners.

    After thoroughly reading this package README and many attempts later, the only way I found to accomplish the old behavior was to override L9's Auth\LoginController@login. I'm not so confident if I got right and what kind of security holes I may have opened. Here's how it looks now:

    <?php
    
    namespace App\Http\Controllers\Auth;
    
    use App\Http\Controllers\Controller;
    use App\Providers\RouteServiceProvider;
    use Auth;
    use DB;
    use Illuminate\Http\JsonResponse;
    use Illuminate\Http\RedirectResponse;
    use Illuminate\Http\Request;
    use Illuminate\Http\Response;
    use Laragear\TwoFactor\TwoFactor;
    use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
    
    class LoginController extends Controller
    {
        /**
         * Where to redirect users after login.
         *
         * @var string
         */
        protected $redirectTo = RouteServiceProvider::HOME;
    
        /**
         * Override AuthenticatesUsers::login() to implement 2FA.
         *
         * @see AuthenticatesUsers::login() To the original login implementation.
         * @see https://github.com/Laragear/TwoFactor#logging-in To the Laragear\TwoFactor login implementation.
         *
         * @param Request $request
         *
         * @return JsonResponse|RedirectResponse|Response|SymfonyResponse
         */
        public function login(Request $request) {
            $credentials = $request->validate([
                $this->username() => 'required|string',
                'password' => 'required|string',
            ]);
    
            if (method_exists($this, 'hasTooManyLoginAttempts') &&
                $this->hasTooManyLoginAttempts($request)) {
                $this->fireLockoutEvent($request);
    
                return $this->sendLockoutResponse($request);
            }
    
            $twoFactor = DB::table('two_factor_authentications')->where('label', $credentials['email'])->count();
            if ($twoFactor && ! $request->filled(config('app.2fa_field'))) {
                return response()->view(
                    'two-factor::confirm',
                    [
                        'credentials' => $credentials,
                        'remember' => $request->filled('remember'),
                    ]
                );
            } else {
                if (Auth::attemptWhen($credentials, TwoFactor::hasCodeOrFails(), $request->filled('remember'))) {
                    if ($request->hasSession()) {
                        $request->session()->put('auth.password_confirmed_at', time());
                    }
    
                    return $this->sendLoginResponse($request);
                }
            }
    
            $this->incrementLoginAttempts($request);
    
            return $this->sendFailedLoginResponse($request);
        }
    }
    

    It worked as expected, except that if users type a wrong 2FA code shw will be redirected back to login page (user/password). I can live with that, as it won't make explicit to an attacker if the wrong piece of data was the email, password or the TOTP code.

    But at the end, is that right? Can it be improved somehow? Did I broke my auth toy?

    PS: The documentation is far from clear when someone needs a custom login method like the case above (TOTP code in it's own form). But as I'm not sure if this is a bug with the middleware not attaching to POST login method, I will leave this as is for now.

    Reproduction

    Not available yet.

    Expected behavior

    It would be really nice if Route::post()->middleware('2fa.confirm') just worked as expected (i.e. force a user with 2FA enabled to enter TOTP code on it's own form page, leave users with 2FA disabled alone and just log them in). This would also leave such a critical method as Auth\LoginController@login alone.

    Stack Trace

    The issue generates no stack trace.

    bug wontfix 
    opened by denydias 12
  • [1.x] Credentials aren't being flashed to session

    [1.x] Credentials aren't being flashed to session

    PHP & Platform

    8.1.7 - Fedora 35 x64

    Laravel verion

    9.17.0

    Have you done this?

    • [X] I am willing to share my stack trace and logs
    • [X] I can reproduce this bug in isolation (vanilla Laravel install)
    • [ ] I can suggest a workaround as a Pull Request

    Expectation

    When a user with 2FA enabled logs in and confirms their TOTP, they should be redirected to the application as authenticated.

    Description

    The user is redirected back to the login page with an error stating that their credentials are invalid. This seems to be caused by the session flash not being set. Looking into TwoFactorLoginHelper.php I identified that Illuminate\Contracts\Session\Session does not have flash() as a member function https://laravel.com/api/9.x/Illuminate/Contracts/Session/Session.html

    protected function flashData(array $credentials, bool $remember): void
        {
            foreach ($credentials as $key => $value) {
                $credentials[$key] = Crypt::encryptString($value);
            }
    
            $this->session->flash($this->sessionKey, ['credentials' => $credentials, 'remember' => $remember]);
        }
    

    As a result, when the TOTP form is submitted the credentials are blank. And since validation is overridden due to 2fa_code being present, the app kicks back a credentials not found error. You may want to use $this->session->put(...) and $this->session->forget(...) in combination with flashData() and getFlashedData() to approximate flash() or instead use the $request->session() which does have flash().

    Reproduction

    // https://github.com/Laragear/TwoFactor
    

    Stack trace & logs

    No response

    Are you a Patreon supporter?

    No, don't give priority to this

    bug unreproducible 
    opened by aadrian624 11
  • Call Auth2FA::attempt gives warning 'Non static method 'attempt' should not be called statically.'

    Call Auth2FA::attempt gives warning 'Non static method 'attempt' should not be called statically.'

    PHP & Platform

    8.1.6 Windows

    Database

    mysqlnd 8.1.6

    Laravel version

    9.43.0

    Have you done this?

    • [X] I have checked my logs and I'm sure is a bug in this package.
    • [X] I can reproduce this bug in isolation (vanilla Laravel install)
    • [ ] I can suggest a workaround as a Pull Request

    Expectation

    No warnings should be issued

    Description

    When using this line:

    $attempt = Auth2FA::attempt($request->only('email', 'password'), $request->filled('remember'));

    like in the documentation VSCode intelephense marks it as: "Non static method 'attempt' should not be called statically."

    Reproduction

    /**
         * Handle an authentication attempt.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return \Illuminate\Http\Response
         */
        public function authenticate(Request $request)
        {
            // If the user is trying for the first time, ensure both email and the password are
            // required to log in. If it's not, then he would issue its 2FA code. This ensures
            // the credentials are not required again when is just issuing his 2FA code alone.
            if ($request->isNotFilled('2fa_code')) {
                $request->validate([
                    'email' => 'required|email',
                    'password' => 'required|string'
                ]);
            }
            
            $attempt = Auth2FA::guard('admin')->attempt($request->only('email', 'password'), $request->filled('remember'));
        
            if ($attempt) {
                return redirect()->intended('/');
            }
     
            return back()->withErrors([
                'email' => 'The provided credentials do not match our records.',
            ])->onlyInput('email');
        }
    

    Stack trace & logs

    No response

    bug 
    opened by michelterstege81 8
  • Unable to login after setting up the 2fa

    Unable to login after setting up the 2fa

    Most probably I have done something wrong while setting everything up (this project is very early development still).

    So for this project, all users are required to enable 2fa; so on my authenticated routes, I have added the 2fa.enabled middleware. While I am using Laravel Breeze, for now I am mostly using your original views (though I created a 'confirm', 'prepare' and 'recovery' view to also use during the setup of 2fa for a user). I am also using the Facade to handle the login (as per the readme, set in the LoginRequest).

    I further copied the "ConfirmtwoFactorCodeController" over to my other controllers, and modified it to also handle the setup of the 2fa for a user, using the following routes:

    Route::get('2fa-notice', [\App\Http\Controllers\Frontend\ConfirmTwoFactorCodeController::class, 'notifyTwoFactor'])->name('2fa.notice');
    Route::get('2fa-prepare', [\App\Http\Controllers\Frontend\ConfirmTwoFactorCodeController::class, 'prepareTwoFactor'])->name('2fa.prepare');
    Route::post('2fa-prepare', [\App\Http\Controllers\Frontend\ConfirmTwoFactorCodeController::class, 'confirmTwoFactor'])->name('2fa.confirm');
    Route::get('2fa-recovery', [\App\Http\Controllers\Frontend\ConfirmTwoFactorCodeController::class, 'showRecoveryCodes'])->name('2fa.recovery');
    

    So the setup part is working, and the app code, verifies correctly.

    The issue is happening when I attempt to log in. I provide the email and password, and then see the screen asking for the code (weird thing here is it immediately shows the field as having an error, saying the code is either wrong or expired - this is prior to me providing any code). Then when I provide the correct code, it tells me the login was unsuccessful (basically that both the email and password fields are required).

    Any idea how I can solve this issue.

    opened by Jacotheron 6
  • [1.x] Fix: Use config model for `twoFactorAuth` relation

    [1.x] Fix: Use config model for `twoFactorAuth` relation

    Description

    The twoFactorAuth relation always returns an instance of the base TwoFactorAuthentication class, regardless of the config model value.

    Updated the relation to return an instance of the config model.

    opened by JasonHobson 5
  • [1.x] Independent Recovery Codes

    [1.x] Independent Recovery Codes

    Description

    The recovery code logic is great! If you use multiple two-factor options for the application, you may want to reuse the recovery code logic independently of the TOTP method.

    This PR simply changes the logic so that recovery codes are not deleted when disabled. This allows the developer to use the recovery code system independently and make sure recovery codes are not generated or deleted when enabling or disabling TOTP.

    opened by FabioWidmer 5
  • [1.x] Add input name

    [1.x] Add input name

    The attributes id and name are empty in the form

    https://github.com/Laragear/TwoFactor/blob/aed2545da20cad2958733f26af69d9bcdfb7c8d3/resources/views/confirm.blade.php#L20

    opened by padre 4
  • Extending the section in documentation: set up->Logging in

    Extending the section in documentation: set up->Logging in

    Please check these requirements

    • [X] This feature helps everyone using this package
    • [X] It's feasible and maintainable
    • [X] It's non breaking
    • [ ] I issued a PR with the implementation (optional)

    Description

    I've installed the package following the readme.md. I still don't understand how to turn the login process into a two-step process for users who have enabled 2fa. As I've read in the instructions I should add a field to the login form for the 2fa_code, and this works. Users without 2fa enabled are logged in without entering anything, and users who do have one must enter a code.

    However, I would prefer the user to first enter a valid username/password and then be asked for the 2fa_code. It would be great if the readme was a bit more explanatory on implementing the login routine. Alternatively, an example package that implements the functionality would be valuable.

    Thanks for your great work!

    Code sample

    - i have no idea on how to write that code.
    

    Are you a Patreon supporter?

    No, don't give priority to this

    enhancement 
    opened by OliverScrew 3
  • Login fails for users using totp when package is used with sanctum

    Login fails for users using totp when package is used with sanctum

    PHP & Platform

    8.0.12

    Laravel verion

    9.17.0

    Have you done this?

    • [X] I am willing to share my stack trace and logs
    • [X] I can reproduce this bug in isolation (vanilla Laravel install)
    • [ ] I can suggest a workaround as a Pull Request

    Expectation

    When totp code is correct i expect the user to be logged in.

    Description

    Users not using 2fa gets logged inn correctly. Users who has activated 2fa are getting the login page again with no error message.

    Reproduction

    //To activate sanctum for api calls (SPA authentication) i  uncommented EnsureFrontendRequestsAreStateful in app/http/Kernel.php. That is when this "bug" sets in.
    
    'api' => [
                \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
                'throttle:api',
                \Illuminate\Routing\Middleware\SubstituteBindings::class,
            ],
    

    Stack trace & logs

    no stacktrace and nothing logged in laravel.log
    

    Are you a Patreon supporter?

    No, don't give priority to this

    bug question 
    opened by OysteinHoiby 2
  • [1.x] Login helper, code generator

    [1.x] Login helper, code generator

    Description

    This feature allows to login users with a helper. This helper will throw a response with a form to issue or re-issue a 2FA Code. It will capture and persist the encrypted credentials for the next request.

    Also includes a code generator for Recovery Codes.

    Code samples

    (Included in the README)

    opened by DarkGhostHunter 2
  • Migration should be optional

    Migration should be optional

    PHP & Platform

    8.1.3

    Laravel verion

    9.5.1

    Have you done this?

    • [X] I am willing to share my stack trace and logs
    • [X] I can reproduce this bug in isolation (vanilla Laravel install)
    • [ ] I can suggest a workaround as a Pull Request

    Expectation

    The migration included in this package should be optional.

    Description

    I'm migrating from the old Laraguard package. I already have a database table called two_factor_authentications, from a migration that has a slightly different name than the migration included with this package.

    This causes a Table 'two_factor_authentications' already exists error when running php artisan migrate, where the migration included in this package is called because it is not listed in my migrations table.

    As far as I can see I cannot cancel this migration.

    Reproduction

    Schema::create('two_factor_authentications', function (Blueprint $table) {
                $table->bigIncrements('id');
    });
    
    then run php artisan migrate
    

    Stack trace & logs

    No response

    Are you a Patreon supporter?

    No, don't give priority to this

    bug 
    opened by Grldk 2
  • Determine if user bypassed 2 factor with safe device.

    Determine if user bypassed 2 factor with safe device.

    Please check these requirements

    • [X] This feature helps everyone using this package
    • [X] It's feasible and maintainable
    • [X] It's non breaking
    • [ ] I issued a PR with the implementation (optional)

    Description

    Hi.

    Thanks! Great package, it has everything that Fortify lacks and is much more customizable.

    One small feature Im missing is telling if the user is logged in with a real 2-factor authentication challenge or bypassed the auth with a "safe device". It would be optimal if the validate() method could set some session variable when bypassing the two-factor challenge. Or vice versa, some session variable being set only when the user did a real 2-factor auth.

    I will have a middleware forcing users to confirm important actions if:

    • They bypassed the 2 factor auth in the login
    • Havent authenticated in xx time, since last time.

    Maybe this feature exists but I've missed it somewhere? Thanks.

    Code sample

    // If safe devices are enabled, and this is a safe device, bypass.
          if ($this->isSafeDevicesEnabled() && $user->isSafeDevice($this->request)) {
            
          **ADD**
            $this->request->session()->put("bypassed_two_factor", $time);
            
              return true;
          }
    
    enhancement 
    opened by stefan-sandberg 1
  • safe_devices does not remember device

    safe_devices does not remember device

    PHP & Platform

    8.1.6 & Windows (localhost)

    Database

    mysqlnd 8.1.6

    Laravel version

    9.43.0

    Have you done this?

    • [X] I have checked my logs and I'm sure is a bug in this package.
    • [X] I can reproduce this bug in isolation (vanilla Laravel install)
    • [ ] I can suggest a workaround as a Pull Request

    Expectation

    2FA code not requested on next login on same device when safe_devices enabled = true.

    Description

    2FA code is requested on every login on the same device.

    Column safe_devices stays on value null.

    No additional browser cookie stored (2 cookies in use: session and csrf)

    Reproduction

    'safe_devices' => [
            'enabled'         => true,
            'cookie'          => '_2fa_remember',
            'max_devices'     => 3,
            'expiration_days' => 14,
        ],
    

    Stack trace & logs

    No response

    bug 
    opened by michelterstege81 2
Releases(v1.1.3)
  • v1.1.3(Dec 15, 2022)

    What's Changed

    • Update Auth2FA.php by @michelterstege81 in https://github.com/Laragear/TwoFactor/pull/35

    New Contributors

    • @michelterstege81 made their first contribution in https://github.com/Laragear/TwoFactor/pull/35

    Full Changelog: https://github.com/Laragear/TwoFactor/compare/v1.1.2...v1.1.3

    Source code(tar.gz)
    Source code(zip)
  • v1.1.2(Jul 29, 2022)

    What's Changed

    • [1.x] Improves CI by @DarkGhostHunter in https://github.com/Laragear/TwoFactor/pull/28
    • [1.x] Uses flash only if available by @DarkGhostHunter in https://github.com/Laragear/TwoFactor/pull/24
    • [1.x] Removes lingering config key by @DarkGhostHunter in https://github.com/Laragear/TwoFactor/pull/32

    Full Changelog: https://github.com/Laragear/TwoFactor/compare/v1.1.1...v1.1.2

    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(Jun 22, 2022)

    What's Changed

    • Apply fixes from StyleCI by @DarkGhostHunter in https://github.com/Laragear/TwoFactor/pull/13
    • [1.x] Minor refactoring, better tests. by @DarkGhostHunter in https://github.com/Laragear/TwoFactor/pull/14
    • Apply fixes from StyleCI by @DarkGhostHunter in https://github.com/Laragear/TwoFactor/pull/17
    • Apply fixes from StyleCI by @DarkGhostHunter in https://github.com/Laragear/TwoFactor/pull/19
    • [1.x] Fixes error on first 2FA response by @DarkGhostHunter in https://github.com/Laragear/TwoFactor/pull/20

    Full Changelog: https://github.com/Laragear/TwoFactor/compare/v1.1.0...v1.1.1

    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(May 26, 2022)

    What's Changed

    • [1.x] Login helper by @DarkGhostHunter in https://github.com/Laragear/TwoFactor/pull/11
    • [1.x] Recovery Code generator by @DarkGhostHunter in https://github.com/Laragear/TwoFactor/pull/11

    Full Changelog: https://github.com/Laragear/TwoFactor/compare/v1.0.2...v1.1.0

    Source code(tar.gz)
    Source code(zip)
  • v1.0.2(Mar 24, 2022)

    What's Changed

    • [1.x] Add input name by @padre in https://github.com/Laragear/TwoFactor/pull/6
    • [1.x] Update readme with correct method name by @padre in https://github.com/Laragear/TwoFactor/pull/5
    • [1.x] Does not create a table if it exists by @DarkGhostHunter in https://github.com/Laragear/TwoFactor/commit/efe103d6be0a9606c4b7ebc9e3dd8a9770b69997

    New Contributors

    • @padre made their first contribution in https://github.com/Laragear/TwoFactor/pull/5

    Full Changelog: https://github.com/Laragear/TwoFactor/compare/v1.0.1...v1.0.2

    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Feb 23, 2022)

Owner
Laragear
Packages for Laravel
Laragear
PHP library for Two Factor Authentication (TFA / 2FA)

PHP library for Two Factor Authentication PHP library for two-factor (or multi-factor) authentication using TOTP and QR-codes. Inspired by, based on b

Rob Janssen 896 Dec 30, 2022
Vendor-Agnostic Two-Factor Authentication

Multi-Factor Designed to be a vendor-agnostic implementation of various Two-Factor Authentication solutions. Developed by Paragon Initiative Enterpris

Paragon Initiative Enterprises 139 Dec 21, 2022
Redirects any user which hasn't setup two factor authentication yet to /2fa/

force-two-factor Redirects any user which hasn't setup two factor authentication yet to /2fa/. Use together with the forked two-factor plugin at https

Aiwos 0 Dec 24, 2021
Secure WordPress login with two factor authentication

This plugin allows you to secure your WordPress login with two factor authentication. The users will have to enter a one time password every time they log in.

Volodymyr Kolesnykov 6 Nov 2, 2022
A simple two factor authentication for laravel applications

Laravel 2fa A simple two factor authentication for laravel applications. Installation Require via composer Update database Replace authentication trai

Rezkonline 1 Feb 9, 2022
Laravel Two-Factor Authentication

This package allow you to enable two-factor authentication in your Laravel applications very easily, without the need to add middleware or any modification to your routes. It stores tokens in your database in a distinct table, so you don't need to alter your users table. Notify users about their token via mail, SMS or any custom channel.

null 7 Jun 24, 2022
Google Two-Factor Authentication Package for Laravel

Google2FA for Laravel Google Two-Factor Authentication Package for Laravel Google2FA is a PHP implementation of the Google Two-Factor Authentication M

Antonio Carlos Ribeiro 785 Dec 31, 2022
PHP library for Two Factor Authentication (TFA / 2FA)

PHP library for Two Factor Authentication PHP library for two-factor (or multi-factor) authentication using TOTP and QR-codes. Inspired by, based on b

Rob Janssen 896 Dec 30, 2022
phpCAS is an authentication library that allows PHP applications to easily authenticate users via a Central Authentication Service (CAS) server.

phpCAS is an authentication library that allows PHP applications to easily authenticate users via a Central Authentication Service (CAS) server.

Apereo Foundation 780 Dec 24, 2022
API stubs for developing a plugin that provides a 2FA authentication factor in JobRouter®.

Authentication Factor API JobRouter® is a scalable digitisation platform which links processes, data and documents. Starting with JobRouter® 5.2, a se

JobRouter 4 Nov 4, 2021
This repository includes a sample project to illustrate the usage of the JobRouter® Authentication Factor API.

JR 2FA Example Plugin This repository includes a sample project to illustrate the usage of the JobRouter® Authentication Factor API. It can be used as

JobRouter 4 Sep 10, 2021
PHP class to generate and verify Google Authenticator 2-factor authentication

Google Authenticator PHP class Copyright (c) 2012-2016, http://www.phpgangsta.de Author: Michael Kliewe, @PHPGangsta and contributors Licensed under t

Michael Kliewe 2.1k Jan 2, 2023
Multi-factor Authentication using a Public PGP key for web based applications

PGPmfa() a PHP Class for PGP Multi-factor Authentication using a Public PGP key for web based applications Multi-factor Authentication with PGP Second

null 2 Nov 27, 2022
It's a Laravel 8 authentication markdown that will help you to understand and grasp all the underlying functionality for Session and API Authentication

About Auth Starter It's a Laravel 8 authentication markdown that will help you to understand and grasp all the underlying functionality for Session an

Sami Alateya 10 Aug 3, 2022
permission generation for all your declared routes with corresponding controller action

Permissions Generator This package add some artisan command to help generating permissions for your declared routes. Each route should have an alias (

Diagana Mouhamed Fadel 4 Nov 30, 2022
Associate users with roles and permissions

Associate users with permissions and roles Sponsor If you want to quickly add authentication and authorization to Laravel projects, feel free to check

Spatie 10.9k Jan 3, 2023
Laravel Users (Roles & Permissions, Devices, Password Hashing, Password History).

LARAVEL USERS Roles & Permissions Devices Password Hashing Password History Documentation You can find the detailed documentation here in Laravel User

Pharaonic 8 Dec 14, 2022
Laravel package to easily login as other users during development.

A Laravel 5.4 utility package to enable developers to log in as other users during development. Installation To install the package, simply follow the

VIA Creative 555 Jan 8, 2023