Giter Club home page Giter Club logo

laraguard's Introduction

Package superseeded by Laragear/TwoFactor

Please migrate to the new package.


Laraguard

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

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

Requirements

For older versions support, consider helping by sponsoring or donating.

Installation

Fire up Composer and require this package in your project.

composer require darkghosthunter/laraguard

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.

Usage

First, create the two_factor_authentications table by publishing the migration and migrating:

php artisan vendor:publish --provider="DarkGhostHunter\Laraguard\LaraguardServiceProvider" --tag="migrations"
php artisan migrate

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

If you're upgrading from 3.0, you should run a special migration.

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 DarkGhostHunter\Laraguard\TwoFactorAuthentication;
use DarkGhostHunter\Laraguard\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.

Enabling Two-Factor Authentication

To enable Two-Factor Authentication successfully, the User 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', [
        'as_qr_code' => $secret->toQr(),     // As QR Code
        'as_uri'     => $secret->toUri(),    // As "otpauth://" URI.
        'as_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();
    } else {
        return 'Try again!';
    }
}

You're free on how to show these codes to the User, but ensure you show them 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.

The User can generate a fresh batch of codes using generateRecoveryCodes(), which automatically invalidates 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 attemptWhen() with Laraguard, 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 DarkGhostHunter\Laraguard\Laraguard;

public function login(Request $request)
{
    // ...
    
    $credentials = $request->only('email', 'password');
    
    if (Auth::attemptWhen($credentials, Laraguard::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 DarkGhostHunter\Laraguard\Laraguard;

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

Since it's a 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

Laraguard 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')
    ->uses('SystemSettingsController@show')
    ->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', 'laraguard::notice', [
    'url' => url('settings/2fa')
])->name('2fa.notice');

Alternatively, you can just redirect the user to the named route where he can enable 2FA.

use Illuminate\Support\Facades\Route

Route::get('system/settings')
    ->uses('SystemSettingsController@show')
    ->middleware('2fa.enabled:settings.2fa');

Confirm 2FA

Much like the password.confirm middleware, you can also ask the user to confirm an action using 2fa.confirm if it has Two-Factor Authentication enabled.

Route::get('api/token')
    ->uses('ApiTokenController@show')
    ->middleware('2fa.confirm');

Since a user without 2FA enabled won't be asked for a code, you use it with 2fa.require to enforce it.

Route::get('api/token')
    ->uses('ApiTokenController@show')
    ->middleware('2fa.require', '2fa.confirm');

Laraguard uses its Confirm2FACodeController to handle the form view. You can point your own controller actions. The Confirms2FACode trait will aid you in not reinventing the wheel.

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 totp_code rule.

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

    // ...
}

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

Translations

Laraguard comes with translation files (only for english) that you can use immediately in your application. These are also used for the validation rule.

public function disableTwoFactorAuth()
{
    // ...

    session()->flash('2fa_disabled', trans('laraguard::messages.disabled'));

    return back();
}

To add your own in your language, publish the translation files. These will be located in resources/vendor/laraguard:

php artisan vendor:publish --provider="DarkGhostHunter\Laraguard\LaraguardServiceProvider" --tag="translations"

Configuration

To further configure the package, publish the configuration files and assets:

php artisan vendor:publish --provider="DarkGhostHunter\Laraguard\LaraguardServiceProvider"

You will receive the config/laraguard.php config file with the following contents:

return [
    'model' => \DarkGhostHunter\Laraguard\Eloquent\TwoFactorAuthentication::class,
    'cache' => [
        'store' => null,
        'prefix' => '2fa.code'
    ],
    'recovery' => [
        'enabled' => true,
        'codes' => 10,
        'length' => 8,
	],
    'safe_devices' => [
        'enabled' => false,
        'max_devices' => 3,
        'expiration_days' => 14,
	],
    'confirm' => [
        'timeout' => 10800,
        'view' => 'DarkGhostHunter\Laraguard\Http\Controllers\Confirm2FACodeController@showConfirmForm',
        'action' => 'DarkGhostHunter\Laraguard\Http\Controllers\Confirm2FACodeController@confirm'
    ],
    'secret_length' => 20,
    'issuer' => env('OTP_TOTP_ISSUER'),
    'totp' => [
        'digits' => 6,
        'seconds' => 30,
        'window' => 1,
        'algorithm' => 'sha1',
    ],
    'qr_code' => [
        'size' => 400,
        'margin' => 4
    ],
];

Eloquent Model

return [
    'model' => \DarkGhostHunter\Laraguard\Eloquent\TwoFactorAuthentication::class,
];

This is the model where the data for Two-Factor Authentication is saved, like the shared secret and recovery codes, and associated to the models implementing TwoFactorAuthenticatable.

You can change this model for your own if you wish, as long it implements the TwoFactorTotp contract.

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 save the code for a given period.

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.

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 re-enabling Two-Factor Authentication, the list of devices is automatically invalidated.

Confirmation Middleware

return [
    'confirm' => [
        'timeout' => 10800, // 3 hours
        'view' => 'DarkGhostHunter\Laraguard\Http\Controllers\Confirm2FACodeController@showConfirmForm',
        'action' => 'DarkGhostHunter\Laraguard\Http\Controllers\Confirm2FACodeController@confirm'
    ],
];

If the view or action are not null, the 2fa/notice and 2fa/confirm routes will be registered to handle 2FA code notice and confirmation for the 2fa.confirm middleware. If you disable it, you will have to register the routes and controller actions yourself.

This array sets:

  • By how much to "remember" the 2FA Code confirmation.
  • The action that shows the 2FA Code form.
  • The action that receives the 2FA Code and validates it.

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.

Security

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

License

The MIT License (MIT). Please see License File for more information.

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

laraguard's People

Contributors

aneeskhan47 avatar benbjurstrom avatar bskl avatar darkghosthunter avatar dependabot-preview[bot] avatar dependabot[bot] avatar frkcn avatar it-can avatar jeromefitzpatrick avatar victorlap avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laraguard's Issues

Safe devices - let user decide

Currently, the safe devices option is activated in the config. So it is activated globally.

Let's assume I am on a public computer. When I login successfully, the device is marked as safe device, while it is not.

Currently there is no option for a user loging in to manually mark a computer as safe:
https://github.com/DarkGhostHunter/Laraguard/blob/master/src/Listeners/EnforceTwoFactorAuth.php#L87

What if we add something like:

if (request()->input('is_safe', false)) {
   // Safe device
}

(Maybe there is a way to code it without being a breaking change)

Not prompted for 2FA on login

Hi, i just added your package to my Laravel 7 installation on PHP 7.4. I added the Contract and Trait to my User model, ran the migration and published the config without any changes.

I was able to sucessfully generate and confirm my 2FA code and $user->hasTwoFactorEnabled() returns true.

But when i log out and try logging back in again, i'm logged in without any request for a 2fa code! I can log in using the password only.

What have i missed?

Question - TOTP verification on demand

Hi, first of all thank you for the excellent work.
I was looking for a solution to verify an otp for certain operations (on demand), is it possible to trigger the otp verification flow manually or on custom events ?
Maybe like laravel middleware password.confirm
Thanks, regards

notice not working well

Hi.
When i do all like installation guide in readme. I got an error:

Facade\Ignition\Exceptions\ViewException Undefined variable: url (View: /var/www/html/beta9/resources/views/vendor/laraguard/notice.blade.php) http://domain.com/2fa-required Hide solutions $url is undefined Make the variable optional in the blade template. Replace {{ $url }} with {{ $url ?? '' }}

Any ideas?

Thanks

Documentation v4 - not asking for 2FA code

Dear

Upgrading v2 to v4 results in the login process skipping checks for users that have enabled 2FA. To simplify things I installed a clean Laravel v8.62 / PHP v8.0.11 to test it from scratch and the check / validation is not being executed.

'How it works' says no extra code is needed.
https://github.com/DarkGhostHunter/Laraguard#how-this-works

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.

Contract & trait are added to my User model
https://github.com/DarkGhostHunter/Laraguard#usage

Login part mentions overriding Login in LoginController. Is this needed for v4 please?
https://github.com/DarkGhostHunter/Laraguard#logging-in

This forces everyone to use 2FA during login

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

FYI: In Laravel 8 the default User model is located in App\Models and the readme still references to namespace App

Brute force Confirm code

Hello,

Are you planning to extend the totp_code rule [ TotpCodeRule ] with an anti brute-force check please?

The Confirm controller has no checks. This could be a potential security risk.

Use with Uuid

Is this package compatible with the user model id being a uuid? I'm not sure if I can just change the migration without breaking anything inside the package.

My idea was to change / replace the line

$table->morphs('authenticatable', '2fa_auth_type_auth_id_index');

with this:

$table->string('authenticatable_type');
$table->uuid('authenticatable_id');

Would that work, of break any logic inside the package itself?

Enabling two factor

In the part about enabling two factor, it is mentioned that it needs to be two way. Where do I send this in from?

$request->input('2fa_code')

Is there a route or a view I have missed?

Suggestion: getAvailableCodes

Hi,
You may add this scope to get only available codes, something like this :

 public function getAvailableCodes(): Collection
    {
        return $this->twoFactorAuth->recovery_codes->whereNull('used_at') ?? collect();
    }

Thanks

Bug on Recovery Code in Login

Hello,
I've just detected a bug when we use recovery code in login instead of TOTP, the reason is the rule validation here :

 protected function requestHasCode(): bool
    {
        return !validator($this->request->only($this->input), [
            $this->input => 'required|numeric',
        ])->fails();
    }

You need to remove 'numeric' to get true for recovery code.
Regards

Can't run migration: index name too long

  • Laravel Version: 6.14.0
  • PHP Version: 7.3
  • Database Driver & Version: MySQL 5.7.27

When running included migration I get the following error:

SQLSTATE[42000]: Syntax error or access violation: 
1059 Identifier name 'two_factor_authentications_authenticatable_type_authenticatable_id_index' is too long 
(SQL: alter table `two_factor_authentications` add index `two_factor_authentications_authenticatable_type_authenticatable_id_index`(`authenticatable_type`, `authenticatable_id`))

A shorter index name here should fix this I guess?

Do not accept a second use of a valid OTP code

First and foremost, I would like to thank you for creating such a nice project. I want to implement this in an app but stumbled accross the following piece in the TOTP RFC:

Note that a prover may send the same OTP inside a given time-step
window multiple times to a verifier. The verifier MUST NOT accept
the second attempt of the OTP after the successful validation has
been issued for the first OTP, which ensures one-time only use of an
OTP.

Maybe it is feasible to cache the usage of a token and only allow the first submission to pass through?

NA

Congrats on a great plugin!

Credentials in hidden fields

Storing the credentials in a hidden field feels like a security issue. Basically, it happens here:

https://github.com/DarkGhostHunter/Laraguard/blob/master/src/Listeners/EnforceTwoFactorAuth.php#L112

The way the package is setup (implementing listeners, non evasive) doesn't really allow for a different way I think. I like the non invasiveness, but aren't there options to avoid the hidden fields, or at least limit security issues?

For example:

  • at least set a no-store cache control in the response header, so browser does not cache.
  • is there a way to encrypt the credentials, than decrypt later, filling the request object with the decrypted credentials?
  • is there a way to maybe first check credentials, than mark as success, use a token for the 2fa check? (Probably not with the listeners used...)
  • use sessions? Although storing credentials in sessions is also a security risk, but maybe again use encrypted credentials?

Need Help

Hello,
Thanks for this great package,
I'm little confused on how to use this package on login page, as I know, once the user types the correct email/password, he should be redirected to a modal or page to enter the 2fa code.
But what I saw in the docs, it seems I need to set an input 2fa_code inside login form.
Am I correct ? How could I ask the user to enter the 2fa_code just after a success login ?

Regards.

Ajax support?

I assume this isn't going to happen considering how the package is built, using listeners. But are there any plans to make it possible to use with javascript/ajax? I am using inertia for a project where I would love to add two factor auth, but I need to have control over the response (Inertia::render())

[4.x] Option to encrypt Shared Secret and Recovery Codes

The RFC for TOTP recommends encrypting the shared secret when storing it. I feel that is an important option to have on this package.

I had previously implemented this for my own use of the package using accessors/mutators, but with Laravel 8 we can take advantage of the encrypted attribute cast type. I've made a proof of concept doing this.

There are some considerations:

  1. In order to maintain backward-compatibility with existing uses of the package, I dynamically adjust the $casts property based on the laraguard.encrypted config value. The default value is false. This makes the change completely invisible to existing uses.
  2. Additionally, to maintain compatibility with the current table schema, I continue to use an accessor/mutator for the recovery codes so they are able to be stored as json. If we modify the column to text we can use the cast type for them as well.
  3. With the current table schema the maximum secret length that can be stored encrypted is 25. If we change the column back to text we can support longer encrypted secret lengths.

I'm interested in hearing your thoughts on this and how you would want to handle backward-compatibility

Serialization of 'Closure' is not allowed

Laravel 7.12

Exception
Serialization of 'Closure' is not allowed

error appear when Laraguard package is installed. It appears on successfull request login and only on no 2fa user accounts

Entering code on login seems to cause redis to crash

I've started implementing this into my application, running locally on devilbox.

I was able to create the tokens, but it seems when i login and get to entering the code it causes the application to hang, redis server to die and then eventually end up with a 502.

It appears even changing the cache to file, I can see the file gets written, but even so redis crashes and it's restarted I'm logged in.

Is there something I may be falling foul of causing a timeout after verifying the code?

I'm not seeing this behaviour in other aspects of the app, and seems to be specific to laraguard.

Well done

I just went through the README.md and I have to say, this looks like a very nice piece of work! Thank you very much for open sourcing it. Please close this issue when you read this token of appreciation, have a nice day.

[Question] Laravel Passport Integration

Hi! This looks like such a nice library.
I'm wondering if can be integrated with Laravel Passport or any OAuth2 server implementation.
I'm working with Vue Js as a front-end and Laravel as a Rest API service. It would be great to have this working on my projects.

Thanks!

Invalid argument supplied for foreach()

laravel version: 7.12

Facade\Ignition\Exceptions\ViewException
Invalid argument supplied for foreach() (View: /resources/views/vendor/laraguard/auth.blade.php)

@foreach($credentials as $name => $value)

            <input type="hidden" name="{{ $name }}" value="{{ $value }}">

  @endforeach

This error appears when 2fa is activated on a successfull login request at the 2fa step

$credentials is empty.

Control by Admin user

firstly thank you for Laraguard it is a great work.
sometimes need admin users control other users guard like update recovery codes or disable tow factor recovery from specific user, is there any plan to do something like this?, i can help in this upgrade work, thank you

Unable to locate publishable resources.

When I run:

php artisan vendor:publish --provider=DarkGhostHunter\Laraguard\LaraguardServiceProvider

I had to add double quotes:

php artisan vendor:publish --provider="DarkGhostHunter\Laraguard\LaraguardServiceProvider"

Thanks!

Class name must be a valid object or a string

Installed as per instructions, getting the following error:

Error
Class name must be a valid object or a string

    $secret = $User->createTwoFactorAuth();

App/User.php

// 3rd Party Components

use \Spatie\Tags\HasTags;
use Spatie\Permission\Traits\HasRoles;
use DarkGhostHunter\Laraguard\TwoFactorAuthentication;
use DarkGhostHunter\Laraguard\Contracts\TwoFactorAuthenticatable;

class User extends Authenticatable implements TwoFactorAuthenticatable
{
use Notifiable;
use HasRoles;
use HasTags;
use TwoFactorAuthentication;

...

App/Http/Controllers/UserController.php

public function prepareTwoFactor(Request $request)
{
if( TRUE == ( $User = Auth::user() ) )
{
$secret = $User->createTwoFactorAuth();

    return view('user.enable2fa', [
        'as_qr_code' => $secret->toQr(),     // As QR Code
        'as_uri'     => $secret->toUri(),    // As "otpauth://" URI.
        'as_string'  => $secret->toString(), // As a string
    ]);
}
...

Laravel 8 compatibility

Hey,

First off: thanks for this great package.
Secondly: Do you plan on releasing a Laravel 8 compatible version any time soon?

Regards

Composer require failing

When i run composer require i get the following error:
Your requirements could not be resolved to an installable set of packages.

Problem 1
- darkghosthunter/laraguard[v2.0.0, ..., v2.0.2] require illuminate/support ^6.15||^7.0 -> found illuminate/support[v6.15.0, ..., v6.20.26, v7.0.0, ..., v7.30.4] but these were not
loaded, likely because it conflicts with another require.
- Root composer.json requires darkghosthunter/laraguard ^2.0 -> satisfiable by darkghosthunter/laraguard[v2.0.0, v2.0.1, v2.0.2].

Installation failed, reverting ./composer.json and ./composer.lock to their original content.
root@peddy-backend:/app# php artisan vendor:publish --provider="DarkGhostHunter\Laraguard\LaraguardServiceProvider" --tag="migrations"

C:\Users\Alican\Documents\Technoperia\Peddy\peddy_backend>docker exec -it peddy_backend_fpm_1 bash
root@peddy-backend:/app# composer require darkghosthunter/laraguard
Using version ^2.0 for darkghosthunter/laraguard
./composer.json has been updated
Running composer update darkghosthunter/laraguard

php artisan clear-compiled
Compiled services and packages files removed!
Loading composer repositories with package information
Updating dependencies

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - darkghosthunter/laraguard[v2.0.0, ..., v2.0.2] require illuminate/support ^6.15||^7.0 -> found illuminate/support[v6.15.0, ..., v6.20.26, v7.0.0, ..., v7.30.4] but these were not
 loaded, likely because it conflicts with another require.
    - Root composer.json requires darkghosthunter/laraguard ^2.0 -> satisfiable by darkghosthunter/laraguard[v2.0.0, v2.0.1, v2.0.2].


Installation failed, reverting ./composer.json and ./composer.lock to their original content.

Here is my composer json file:

{ "name": "appnormal/happymondays", "description": "Happy Mondays", "license": "MIT", "type": "project", "require": { "php": "7.3.*", "ext-json": "*", "laravel/framework": "^8.0", "laravelcollective/html": "^6.0.0", "barryvdh/laravel-debugbar": "~3.1", "barryvdh/laravel-ide-helper": "~2.4", "imagine/imagine": "0.6.*", "panique/laravel-sass": "1.0", "doctrine/dbal": "~2.5", "fideloper/proxy": "^4.0", "maatwebsite/excel": "~3.1.18", "google/apiclient": "^2.2", "pusher/pusher-php-server": "^4.0", "fruitcake/laravel-cors": "^2.0", "phpoffice/phpexcel": "^1.8", "edujugon/push-notification": "^4.4", "laravel/ui": "^3.1", "laravel/telescope": "^4.4" }, "require-dev": { "fzaninotto/faker": "~1.4", "mockery/mockery": "^1.0", "phpunit/phpunit": "^9.0", "phpspec/phpspec": "6.*", "symfony/dom-crawler": "5.*", "symfony/css-selector": "5.*", "filp/whoops": "~2.0", "laravel/browser-kit-testing": "^6.1", "knuckleswtf/scribe": "^2.0.0-beta" }, "autoload": { "classmap": [ "database" ], "psr-4": { "App\\": "app/", "Database\\Factories\\": "database/factories/", "Database\\Seeders\\": "database/seeders/" } }, "autoload-dev": { "classmap": [ "tests/TestCase.php", "tests/BrowserKitTestCase.php" ] }, "scripts": { "post-install-cmd": [ "php artisan clear-compiled", "php artisan optimize", "php artisan telescope:install" ], "pre-update-cmd": [ "php artisan clear-compiled" ], "post-update-cmd": [ "php artisan optimize", "php artisan ide-helper:generate", "composer require laravel/ui", "php artisan telescope:install" ], "post-root-package-install": [ "php -r \"copy('.env.example', '.env');\"" ], "post-create-project-cmd": [ "php artisan key:generate" ] }, "config": { "preferred-install": "dist" } }

JSON Support

Hi DarkGhostHunter,

Thanks for the great work, I just had an enquiry/feature request.

It looks like there is no support out of the box for JSON responses for 2fa.require middleware.

I am over-riding the listener as described in your README.MD, but just wanted to know if:
a) Am I missing something and this functionality already exists?
b) Were there plans to implement this?

Not an issue. A question.

Hi,

Can we use Laraguard with Laravel Breeze? Seems that the documentation is for Laravel UI only.

Thanks and best regards

Publish database migration

The current table does not accommodate a User table using uuids as the primary key.

I suggest making the migration publishable so the consumer can make this adjustment. Also, being able to change the timestamp in the migration name would give greater control over when it is run.

I'll fork and submit the PR shortly.

verification code never validate

Hello,
I'm trying to implement laraguard but i'm encountered some issues.
I'm on "Enabling Two Factor Authentication" step
qr code is showing - google auth app generate a code when i scan but it's always false^^
Have ou got an idea why ?
i have installed ntp in my server but no success - Timezone with laravel app are same as server.........
I don't understand where is the problem.

Ok. Issue Solved. Work very well.

Exception setting shared_secret on PostgreSQL

Laraguard version: 2.0.2
Laravel version: 6.18.31
PostgreSQL version: 12.3
PHP version: 7.4.7

Having set up laraguard as described in the README, an exception is thrown when calling the route associated with prepareTwoFactor().

A stacktrace is attached: 2020-07-31 11-22-00 stacktrace.txt

The relevant part is where Illuminate will throw an exception with the following message:

SQLSTATE[22021]: Character not in repertoire: 7 ERROR:  invalid byte sequence for encoding "UTF8": 0x9f (SQL: update "two_factor_authentications" set "shared_secret" = X[S�
���	���"|>�}��, "updated_at" = 2020-07-31 09:03:05 where "id" = 1)

The characters following "0x" and the actual byte sequence will vary from request to request because the shared secret will be generated anew.

On PostgreSQL, the column type for "shared_secret" is "bytea". It seems that laraguard does not handle encoding the value for the database correctly.

The PostgreSQL server's encoding as indicated by "show server_encoding;" is "UTF8". The charset for the DB driver in config/database.php is "utf8".

MySQL 5.6 support

The migration uses JSON field types which are not supported by MySQL 5.6.

Changing the fields to TEXT appears to work fine, but there is no way to publish the migration file to persist this change in our application.

Custom Logo

Is there any way to supply an application logo when using the QR code? For some strange reason it says "SIPPEL" for my app and I don't even know what that is. o_O

This is with Authy after I scan the QR code:

IMG_0242

username based login fail

I've setup 2FA for a login system I'm using, and it works great when logging in through email address, however it fails when we attempt username based login instead.

to allow the users to login through both email/user
we override LoginController ::credentials as follows

LoginController:credentials(Request)
{
        $field = filter_var($request->get($this->username()), FILTER_VALIDATE_EMAIL)
            ? $this->username()
            : 'username';
        return [
            $field => $request->get($this->username()),
            'password' => $request->password,
        ];
}

because of this, saveCredentials saves field username which results in fail login attempt after entering the 2fa code, The email field is required.

I'm not sure what's the best way around to fixing this, Im currently overriding the view and changing the field name username to email, as a workaround.

Invalid codes

I cannot enable Two Factor Authentication because the code generated by my authentication application does not match the value generated by the generateCode() function.

When I scan the QR code to confirm enablement the validateCode() function always returns false because the code is not valid.

I had to debug the value returned by $this->makeCode($at, -$i) and use it to be able to enable it.

Otherwise, thank you very much for this great package. I was able to use all the features.

But validateCode always returns false because the code doesn't match my authentication application :-(

Class Laraguard not found

I currently want to implement the 2FA into a project. Everything works fine except for the logging in part (https://github.com/DarkGhostHunter/Laraguard#logging-in). I added the example code in the login controller but get the following error: https://github.com/DarkGhostHunter/Laraguard#logging-in.

This is the full code of the controller:

<?php

namespace Slim\Controllers\Backend\Auth;

use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Slim\Controllers\Backend\BackendController;
use Slim\Models\User\Backend;
use DarkGhostHunter\Laraguard\Laraguard;
use Illuminate\Support\Facades\Auth;

class LoginController extends BackendController
{

    //
   
    public function login(Request $request)
    {
        $this->validateLogin($request);

        // If the class is using the ThrottlesLogins trait, we can automatically throttle
        // the login attempts for this application. We'll key this by the username and
        // the IP address of the client making these requests into this application.
        if (method_exists($this, 'hasTooManyLoginAttempts') &&
            $this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);

            return $this->sendLockoutResponse($request);
        }

        if ($this->attemptLogin($request)) {

            $credentials = $request->only('email', 'password');

            if (Auth::attemptWhen($credentials, Laraguard::hasCode(), $request->filled('remember'))) {
                return $this->sendLoginResponse($request);
            }
        }

        // If the login attempt was unsuccessful we will increment the number of attempts
        // to login and redirect the user back to the login form. Of course, when this
        // user surpasses their maximum number of attempts they will get locked out.
        $this->incrementLoginAttempts($request);

        return $this->sendFailedLoginResponse($request);
    }
}

Also when I check the folder in the vendor directory I can't find the class Laraguard. Am I missing something?

[documentation] Cannot declare class CreateTwoFactorAuthenticationsTable, because the name is already in use

Documentation says you can change the migration file by running this command.

php artisan vendor:publish --provider="DarkGhostHunter\Laraguard\LaraguardServiceProvider" --tag="migrations"

But then you cannot run 'php artisan migrate' anymore.

php artisan migrate
   Symfony\Component\ErrorHandler\Error\FatalError 

  Cannot declare class CreateTwoFactorAuthenticationsTable, because the name is already in use

  at \database\migrations\2020_07_16_162410_create_two_factor_authentications_table.php:42
    38|     public function down()
    39|     {
    40|         Schema::dropIfExists('two_factor_authentications');
    41|     }
  > 42| }
    43|


   Whoops\Exception\ErrorException 

  Cannot declare class CreateTwoFactorAuthenticationsTable, because the name is already in use

  at \database\migrations\2020_07_16_162410_create_two_factor_authentications_table.php:42
    38|     public function down()
    39|     {
    40|         Schema::dropIfExists('two_factor_authentications');
    41|     }
  > 42| }
    43|

  1   \vendor\filp\whoops\src\Whoops\Run.php:408
      Whoops\Run::handleError("Cannot declare class CreateTwoFactorAuthenticationsTable, because the name is already in use", "\database\migrations\2020_07_16_162410_create_two_factor_authentications_table.php")

  2   [internal]:0
      Whoops\Run::handleShutdown()

Delete the created file and then you can run migrate.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.