Authenticate users with fingerprints, patterns and biometric data.

Overview

WebAuthn

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

Authenticate users with fingerprints, patterns and biometric data.

use Laragear\WebAuthn\Http\Requests\AssertedRequest;

public function login(AssertedRequest $request)
{
    $user = $request->login();

    return response()->json(['message' => "Welcome back, $user->name!"]);
}

You want to add two-factor authentication to your app? Check out Laragear TwoFactor.

Keep this package free

PatreonKo-fiBuymeacoffeePayPal

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

Requirements

  • PHP 8.0 or later, with ext-openssl.
  • Laravel 9.x or later.

Installation

Require this package into your project using Composer:

composer require laragear/webauthn

How does it work?

WebAuthn authentication process consists in two ceremonies: attestation, and assertion.

Attestation is the process of asking the authenticator (a phone, laptop, USB key...) to create a private-public key pair, and register the public key inside the app. For that to work, the user must exist, and the browser must support WebAuthn, which is what intermediates between the authenticator and the app.

Assertion is the process of pushing a cryptographic challenge to the device, which will return signed by the private key. Upon arrival, the app checks the signature with the public key, ready to log in.

The private key doesn't leave the authenticator, and there are no shared passwords to save, let alone remember.

Set up

We need to make sure your users can register their devices and authenticate with them.

  1. Add the eloquent-webauthn driver
  2. Create the webauthn_credentials table
  3. Implement the contract and trait

After that, you can quickly start WebAuthn with the included controllers and helpers to make your life easier.

  1. Register the controllers
  2. Use the Javascript helper

1. Add the eloquent-webauthn driver

Laragear WebAuthn works by extending the Eloquent User Provider with an additional check to find a user for the given WebAuthn Credentials (Assertion). This makes this WebAuthn package compatible with any guard you may have.

Simply go into your auth.php configuration file, change the driver from eloquent to eloquent-webauthn, and add the password_fallback to true.

return [
    // ...

    'providers' => [
        'users' => [
            'driver' => 'eloquent-webauthn',
            'model' => App\User::class,
            'password_fallback' => true,
        ],
    ]
];

The password_fallback indicates the User Provider should fall back to validate the password when the request is not a WebAuthn Assertion. It's enabled to seamlessly use both classic and WebAuthn authentication procedures.

2. Create the webauthn_credentials table

Create the webauthn_credentials table by publishing the migration file and migrating the table:

php artisan vendor:publish --provider="Laragear\WebAuthn\WebAuthnServiceProvider" --tag="migrations"
php artisan migrate

You may edit the migration to your liking, like adding new columns, but not to remove them or change their name.

3. Implement the contract and trait

Add the WebAuthnAuthenticatable contract and the WebAuthnAuthentication trait to the User class, or any other that uses authentication.

<?php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Laragear\WebAuthn\Contracts\WebAuthnAuthenticatable;
use Laragear\WebAuthn\WebAuthnAuthentication;

class User extends Authenticatable implements WebAuthnAuthenticatable
{
    use WebAuthnAuthentication;

    // ...
}

From here you're ready to work with WebAuthn Authentication. The following steps will help you close the gap to a full implementation.

4. Register the routes and controllers

WebAuthn uses exclusive routes to register and authenticate users. Creating these routes and controller may be cumbersome, specially if it's your first time in the WebAuthn real.

Instead, go for a quick start and publish the controllers included in Laragear WebAuthn. These controllers will be located at app\Http\Controllers\WebAuthn.

php artisan vendor:publish --provider="Laragear\WebAuthn\WebAuthnServiceProvider" --tag="controllers"

Next, to pick these controllers easily, go into your web.php routes file and register a default set of routes with the WebAuthn::routes() method.

// web.php
use Illuminate\Support\Facades\Route;
use Laragear\WebAuthn\WebAuthn;

Route::view('welcome');

// WebAuthn Routes
WebAuthn::routes();

5. Use the Javascript helper

This package includes a simple but convenient script to handle WebAuthn Attestation and Assertion. To use it, just publish the webauthn.js asset into your application public resources.

php artisan vendor:publish --provider="Laragear\WebAuthn\WebAuthnServiceProvider" --tag="js"

You will receive the resources/js/vendor/webauthn/webauthn.js file which you can include into your authentication views and use it programmatically, anyway you want. For example, compiling it through Laravel Mix into your application global Javascript.

<script src="/js/app.js"></script>

<!-- Registering credentials -->
<script>
    const register = event => {
        event.preventDefault()
        
        new WebAuthn().register()
          .then(response => alert('Registration successful!'))
          .catch(error => alert('Something went wrong, try again!'))
    }

    document.getElementById('register-form').addEventListener('submit', register)
</script>

<!-- Login users -->
<script>
    const login = event => {
        event.preventDefault()
        
        new WebAuthn().login({
            email: document.getElementById('email').value,
        }, {
            remember: document.getElementById('remember').checked ? 'on' : null,
        }).then(response => alert('Authentication successful!'))
          .catch(error => alert('Something went wrong, try again!'))
    }

    document.getElementById('login-form').addEventListener('submit', login)
</script>

You can copy-paste this helper into your authentication routes, or import it into a bundler like Laravel Vite, Webpack, parcel, or many more. If the script doesn't suit your needs, you're free to create your own.

Requests and Responses parameters

Both register() and login() accept different parameters for the initial request to the server, and the subsequent response to the server. For example, you can use this to remember the user being authenticated.

new WebAuthn().login({
    email: document.getElementById('email').value, // Initial request to the server
}, {
    remember: document.getElementById('remember').checked ? 'on' : null, // Response from the authenticator
})

Custom routes

By default, the helper assumes you're using the default WebAuthn routes. If you're using different routes for WebAuthn, you can set them at runtime.

const webAuthn = new WebAuthn({
    registerOptions: 'webauthn/register/options',
    register: 'webauthn/register',
    
    loginOptions: 'webauthn/login/options',
    login: 'webauthn/login',
});

Here is good place to use ziggy if it's in your project.

Headers

You may add headers to all WebAuthn authentication requests using the second parameter of the WebAuthn constructor. These headers will be present on all requests made by the instance.

const webAuthn = new WebAuthn({}, {
    'X-Colors': 'red',
});

You may use a different WebAuthn instances with different headers for both Attestation and Assertion.

Attestation

Attestation is the ceremony to create WebAuthn Credentials. To create an Attestable Response that the user device can understand, use the AttestationRequest::toCreate() form request.

use Laragear\WebAuthn\Http\Requests\AttestationRequest;

public function createChallenge(AttestationRequest $request)
{
    return $request->toCreate();
}

The device will receive the "instructions" to make a key, and will respond with it. You can use the AttestedRequest form request and its save() method to persist the WebAuthn key if it is valid. The request will automatically return a Validation exception if something fails.

use Laragear\WebAuthn\Http\Requests\AttestedRequest;

public function register(AttestedRequest $attestation)
{
    $attestation->save();
    
    return 'Now you can login without passwords!';
}

You may pass an array, or a callback, to the save(), which will allow you to modify the underlying WebAuthn Eloquent Model before saving it. For example, we could add an alias for the key present in the Request data.

use Laragear\WebAuthn\Http\Requests\AttestedRequest;

public function register(AttestedRequest $request)
{
    $request->validate(['alias' => 'nullable|string']);

    $attestation->save($request->input('alias'));
}

Both AttestationRequest and AttestedRequest validates the authenticated user. If the user is not authenticated, an HTTP 403 status code will be returned.

Attestation User verification

By default, the authenticator decides how to verify user when creating a credential. Some may ask to press a "Continue" button to confirm presence, others will verify the User with biometrics, patterns or passwords.

You can override this using fastRegistration() to only check for user presence if possible, or secureRegistration() to actively verify the User.

use Laragear\WebAuthn\Http\Requests\AttestationRequest;

public function createChallenge(AttestationRequest $request)
{
    return $request->fastRegistration()->toCreate();
}

Userless/One-touch/Typeless Login

Userless/One-touch/Typeless login This enables one click/tap login, without the need to specify the user credentials (like the email) beforehand.

For this to work, the device has to save the "username id" inside itself. Some authenticators may save it regardless, others may be not compatible. To make this mandatory when creating the WebAuthn Credential, use the userless() method of the AttestationRequest form request.

use Laragear\WebAuthn\Http\Requests\AttestationRequest;

public function registerDevice(AttestationRequest $request)
{
    return $request->userless()->toCreate();
}

The Authenticator WILL require user verification on login when using userless(). Its highly probable the user will also be asked for user verification on login, as it will depend on the authenticator itself.

Multiple credentials per device

By default, during Attestation, the device will be informed about the existing enabled credentials already registered in the application. This way the device can avoid creating another one for the same purpose.

You can enable multiple credentials per device using allowDuplicates(), which in turn will always return an empty list of credentials to exclude. This way the authenticator will think there are no already stored credentials for your app.

use Laragear\WebAuthn\Http\Requests\AttestationRequest;

public function registerDevice(AttestationRequest $request)
{
    return $request->allowDuplicates()->make();
}

Assertion

The Assertion procedure also follows a two-step procedure: the user will input its username, the server will return the IDs of the WebAuthn credentials to use, and the device pick one to sign the response. If you're using userless login, only the challenge is returned.

First, use the AssertionRequest::toVerify() form request. It will automatically create an assertion for the user that matches the credentials, or a blank one in case you're using userless login. Otherwise, you may set stricter validation rules to always ask for credentials.

use Laragear\WebAuthn\Http\Requests\AssertionRequest;

public function createChallenge(AssertionRequest $request)
{
    $request->validate(['email' => 'sometimes|email']);

    return $request->toVerify($request->only('email'));
}

After that, you may receive the challenge using the AssertedRequest request object by just type-hinting it in the controller.

Since the authentication is pretty much straightforward, you only need to check if the login() method returns the newly authenticated user or null when it fails. When it's a success, it will take care of regenerating the session for you.

use Laragear\WebAuthn\Http\Requests\AssertedRequest;

public function createChallenge(AssertedRequest $request)
{
    $user = $request->login();
    
    return $user 
        ? response("Welcome back, $user->name!");
        : response('Something went wrong, try again!');
}

If you need greater control on the Assertion procedure, you may want to Assert manually.

If you have debugging enabled the assertion error during authentication will be logged in your application logs, which by default is storage/logs/laravel.log.

Assertion User Verification

In the same style of attestation user verification, the authenticator decides if it should verify the user on login or not.

You may only require the user presence with fastLogin(), or actively verify the user with secureLogin().

use Laragear\WebAuthn\Http\Requests\AssertionRequest;

public function createChallenge(AssertionRequest $request)
{
    $request->validate(['email' => 'sometimes|email']);

    return $request->fastLogin()->toVerify($request->only('email'));
}

Password Fallback

By default, the eloquent-webauthn can be used to log in users with passwords when the credentials are not a WebAuthn JSON payload. This way, your normal Authentication flow is unaffected:

use Illuminate\Support\Facades\Auth;

public function login(Request $request)
{
    $request->validate(['email' => 'required|email', 'password' => 'required|string']);

    if (Auth::attempt($request->only('email', 'password'))) {
        return redirect()->home();
    }
    
    return back()->withErrors(['email' => 'No user found with these credentials']);
}

You may disable the fallback to only allow WebAuthn authentication by setting password_fallback to false. This may force you to handle classic user/password using a separate guard.

Detecting Cloned Credentials

During assertion, the package will automatically detect if a Credential has been cloned by comparing how many times the user has logged in with it.

If it's detected as cloned, the Credential is disabled, a CredentialCloned event is fired, and the Assertion gets denied.

You can use the event to warn the user:

use Illuminate\Support\Facades\Event;
use Laragear\WebAuthn\Events\CredentialCloned;
use App\Notifications\SecureYourDevice;

Event::listen(CredentialCloned::class, function ($cloned) {
    $notification = new SecureYourDevice($cloned->credential);
    
    $cloned->credential->user->notify($notification);
});

Managing Credentials

The purpose of the WebAuthnAuthenticatable contract is to allow managing credentials within the User instance. The most useful methods are:

  • webAuthnData(): Returns the non-variable WebAuthn user data to create credentials.
  • flushCredentials(): Removes all credentials. You can exclude credentials by their id.
  • disableAllCredentials(): Disables all credentials. You can exclude credentials by their id.
  • makeWebAuthnCredential(): Creates a new WebAuthn Credential instance.
  • webAuthnCredentials(): One-to-Many relation to query for WebAuthn Credentials.

You can use these methods to, for example, find a credential to blacklist, or disable WebAuthn completely by flushing all registered devices.

Events

The following events are fired by this package, which you can hook into in your application:

Event Description
CredentialCreated An User has registered a new WebAuthn Credential through Attestation.
CredentialEnabled A disabled WebAuthn Credential was enabled using enable().
CredentialDisabled A enabled WebAuthn Credential was disabled using disable().
CredentialCloned A WebAuthn Credential was detected as cloned dring Assertion.

Manually Attesting and Asserting

If you want to manually Attest and Assert users, you may instance their respective pipelines used for both WebAuthn Ceremonies:

Pipeline Description
AttestationCreator Creates a request to create a WebAuthn Credential.
AttestationValidator Validates a response with the WebAuthn Credential and stores it.
AssertionCreator Creates a request to validate a WebAuthn Credential.
AssertionValidator Validates a response for a WebAuthn Credential.

All of these pipelines require the current Request to work, as is used to generate Challenges in the Session and validate different parts of the authentication data.

For example, you may manually authenticate a user with its WebAuthn Credentials AssertionValidator pipeline.

use Laragear\WebAuthn\Assertion\Validator\AssertionValidation;
use Laragear\WebAuthn\Assertion\Validator\AssertionValidator;
use Illuminate\Support\Facades\Auth;

public function authenticate(Request $request, AssertionValidator $assertion)
{
    $credential = $assertion
        ->send(new AssertionValidation($request))
        ->thenReturn()
        ->credential;
    
    Auth::login($credential->user);
    
    return "Welcome aboard, {$credential->user->name}!";
}

Since these are Laravel Pipelines, you're free to push additional pipes:

use Laragear\WebAuthn\Assertion\Validator\AssertionValidator;

public function addPipes(AssertionValidator $attestation)
{
    $attestation->pipe(VerifyUserIsAwesome::class, NotifyIfAssertionFailed::class);
}

The pipes list and the pipes themselves are not covered by API changes, and are marked as internal. These may change between versions without notice.

Advanced Configuration

Laragear WebAuthn was made to work out-of-the-box, but you can override the configuration by simply publishing the config file.

php artisan vendor:publish --provider="Laragear\WebAuthn\WebAuthnServiceProvider" --tag="config"

After that, you will receive the config/webauthn.php config file with an array like this:

<?php

return [
    'relaying_party' => [
        'name' => env('WEBAUTHN_NAME', env('APP_NAME')),
        'id'   => env('WEBAUTHN_ID'),
    ],
    'challenge' => [
        'bytes' => 16,
        'timeout' => 60,
        'key' => '_webauthn',
    ]
];

Relaying Party Information

return [
    'relaying_party' => [
        'name' => env('WEBAUTHN_NAME', env('APP_NAME')),
        'id'   => env('WEBAUTHN_ID'),
    ],
];

The Relaying Party is just a way to uniquely identify your application in the user device:

  • name: The name of the application. Defaults to the application name.
  • id: An unique ID the application, like the site domain. If null, the device may fill it internally, usually as the full domain.

WebAuthn authentication only work on the top domain it was registered.

Challenge configuration

return [
    'challenge' => [
        'bytes' => 16,
        'timeout' => 60,
        'key' => '_webauthn',
    ]
];

The outgoing challenges are random string of bytes. This controls how many bytes, the seconds which the challenge is valid, and the session key used to store the challenge while its being resolved by the device.

Laravel UI, Jetstream, Fortify, Sanctum, Breeze, Inertia and Livewire

In theory this package should work without any problems with these packages, but you may need to override or redirect the authentication flow (read: method codes) to one using WebAuthn.

There is no support for using WebAuthn with these packages because these are meant to be used with classic user-password authentication. Any issue regarding these packages will be shot down with extreme prejudice.

If you think WebAuthn is critical for these packages, consider supporting this package.

FAQ

  • Does this work with any browser?

Yes. In the case of old browsers, you should have a fallback detection script. This can be asked with the included Javascript helper in a breeze:

if (WebAuthn.doesntSupportWebAuthn()) {
   alert('Your device is not secure enough to use this site!');
}
  • Does this store the user fingerprints, PINs or patterns in my site?

No. WebAuthn only stores a cryptographic public key generated randomly by the device.

  • Can a phishing site steal WebAuthn credentials and use them in my site?

No. WebAuthn kills the phishing because, unlike passwords, the private key never leaves the device.

  • Can WebAuthn data identify a particular device?

No, unless explicitly requested and consented. This package doesn't support other attestation conveyances than none, so it's never transmitted.

  • Are my user's classic passwords safe?

Yes, as long you are hashing them as you should. This is done by Laravel by default. You can also disable them.

  • Can a user register two or more different devices for the same account?

Yes.

  • Can a user register two or more credentials in the same device?

Not by default, but you can enable it.

  • If a user loses his device, can he register a new device?

Yes. If you're not using a password fallback, you may need to create a logic to register a new device using an email. It's assumed he is reading his email using a trusted device.

  • What's the difference between disabling and deleting a credential?

Disabling a credential doesn't delete it, so it's useful as a blacklisting mechanism and these can also be re-enabled. When the credential is deleted, it goes away forever.

  • Can a user delete its credentials from its device?

Yes. If it does, the other part of the credentials in your server gets virtually orphaned. You may want to show the user a list of registered credentials in the application to delete them.

  • How secure is this against passwords or 2FA?

Extremely secure since it works only on HTTPS (or localhost), no password or codes are exchanged nor visible in the screen.

  • Can I deactivate the password fallback? Can I enforce only WebAuthn authentication?

Yes. Just be sure to create recovery helpers to avoid locking out your users.

  • Does this includes a frontend Javascript?

Yes, but it's very basic.

  • Does WebAuthn eliminate bots? Can I forget about captchas?

No, you still need to use captcha, honeypots, or other mechanisms to stop bots.

  • Does this encodes/decode the WebAuthn data automatically in the frontend?

Yes, the included WebAuthn Helper does it automatically for you.

  • Does this encrypts the public keys?

Yes, public keys are encrypted when saved into the database.

  • Does this include a credential recovery routes?

No. You're free to create your own flow for recovery.

  • Can I use my smartphone as authenticator through my PC or Mac?

It depends. This is entirely up to hardware, OS and browser vendor themselves.

  • Why my device doesn't show Windows Hello/Passkey/TouchId/FaceId/pattern/fingerprint authentication?

By default, this WebAuthn implementation accepts almost everything. Some combinations of devices, OS and Web browsers may differ on what to make available for WebAuthn authentication. For example, Windows 7 only supports USB keys.

  • Why my device doesn't work at all with this package?

This package supports WebAuthn 2.0, which is W3C Recommendation. Your device/OS/browser may be using an unsupported version. There are no plans to support older specs.

  • I'm trying to test this in my development server, but it doesn't work

Use localhost exclusively, not 127.0.0.1, or use a proxy to tunnel your site through HTTPS. WebAuthn only works on localhost or under HTTPS only.

  • Why this package supports only none attestation conveyance?

Because direct, indirect and enterprise attestations are mostly used on high-security high-risk scenarios, where an entity has total control on the devices used to authenticate.

If you deem this feature critical for you, consider supporting this package.

  • Can I allow logins with only USB keys?

No. The user can use whatever to authenticate in your app. This may be enabled on future versions.

  • Everytime I make attestations or assertions, it says no challenge exists!

Remember that your WebAuthn routes must use Sessions, because the Challenge gets saved there.

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

These are some details about this WebAuthn implementation:

  • Registration (attestation) and Login (assertion) challenges use the current request session.
  • Only one ceremony can be done at a time.
  • Challenges are pulled from the session on resolution, independently of their result.
  • All challenges and ceremonies expire at 60 seconds.
  • WebAuthn User Handle is UUID v4, reusable if another credential exists.
  • Credentials can be blacklisted (enabled/disabled).
  • Public Keys are encrypted in the database automatically.

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.

Contains Code from Lukas Buchs WebAuthn 2.0 implementation. The MIT License (MIT) where applicable.

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

Comments
  • [1.x] Enable phpstan + bug fix

    [1.x] Enable phpstan + bug fix

    This Pull request enable phpstan on the full code base with a very strict set of rules (some opinionated).

    Description

    • fixes all the complaints of phpstan
    • make sure the tests are still passing
    • stronger code base against bug due to static analysis.
    • no perceptible change in behavior for the user
    • improves CI with actions managing the composer cache directly

    Fixes undiscovered bug

    See changes in src/Auth/WebAuthnUserProvider.php

    opened by ildyria 6
  • [1.x] Improve test suite

    [1.x] Improve test suite

    Description

    Improve yaml for test runs.

    • laravel/orchestra version are provided in the composer file (in require-dev).
    • make use of https://github.com/ramsey/composer-install to manage the composer installation & cache.
    • Now runs on 3 levels:
      • lowest : installs the lowest versions of Composer dependencies
        (equivalent to running composer update --prefer-lowest --prefer-stable)
      • locked : installs the locked versions of Composer dependencies (equivalent to running composer install)
      • highest : installs the highest versions of Composer dependencies (equivalent to running composer update)
    opened by ildyria 5
  • FIX: relaying_party typo

    FIX: relaying_party typo

    Description

    Some instructions use the string relaying_party, others use relying_party. This causes (at least) a 422 response when the webauthn.php config file is published as it declares relying_party while the following instruction in Laragear\WebAuthn\SharedPipes\CheckRelyingPartyIdContained.php waits for relaying_party:

    $this->config->get('webauthn.relaying_party.id') ?? $this->config->get('app.url'), PHP_URL_HOST
    
    opened by Bubka 4
  • [1.x] Add phpstan static code analysis.

    [1.x] Add phpstan static code analysis.

    Description

    This Pull request enables php stan static code analysis which ensure a stronger code base and resistance to bugs. Issue #6 is the result of this analysis and would not have been found otherwise.

    Rules applied are the following:

    From basic phpstan:

    • level 0 : basic checks, unknown classes, unknown functions, unknown methods called on $this, wrong number of arguments passed to those methods and functions, always undefined variables
    • level 1 : possibly undefined variables, unknown magic methods and properties on classes with __call and __get
    • level 2 : unknown methods checked on all expressions (not just $this), validating PHPDocs
    • level 3 : return types, types assigned to properties
    • level 4 : basic dead code checking - always false instanceof and other type checks, dead else branches, unreachable code after return; etc.
    • level 5 : checking types of arguments passed to methods and functions
    • level 6 : report missing typehints
    • level 7 : report partially wrong union types - if you call a method that only exists on some types in a union type, level 7 starts to report that; other possibly incorrect situations

    I did not enable level 8 and 9 because they are too restrictive:

    • level 8 : report calling methods and accessing properties on nullable types
    • level 9 : be strict about the mixed type - the only allowed operation you can do with it is to pass it to another mixed

    Additionally the following rules have been added from : https://github.com/phpstan/phpstan-strict-rules

    • == and != are forbidden in favor of === and !==
    • Require booleans in if, elseif, ternary operator, after !, and on both sides of && and ||.
    • Require numeric operands or arrays in + and numeric operands in -/*///**/%.
    • Require numeric operand in $var++, $var--, ++$varand --$var.
    • These functions contain a $strict parameter for better type safety, it must be set to true:
      • in_array (3rd parameter)
      • array_search (3rd parameter)
      • array_keys (3rd parameter; only if the 2nd parameter $search_value is provided)
      • base64_decode (2nd parameter)
    • Variables assigned in while loop condition and for loop initial assignment cannot be used after the loop.
    • Variables set in foreach that's always looped thanks to non-empty arrays cannot be used after the loop.
    • Types in switch condition and case value must match. PHP compares them loosely by default and that can lead to unexpected results.
    • Check that statically declared methods are called statically.
    • Disallow empty() - it's a very loose comparison (see manual), it's recommended to use more strict one.
    • Disallow short ternary operator (?:) - implies weak comparison, it's recommended to use null coalesce operator (??) or ternary operator with strict condition.
    • Disallow variable variables ($$foo, $this->$method() etc.)
    • Disallow overwriting variables with foreach key and value variables
    • Always true instanceof, type-checking is_* functions and strict comparisons ===/!==. These checks can be turned off by setting checkAlwaysTrueInstanceof/checkAlwaysTrueCheckTypeFunctionCall/checkAlwaysTrueStrictComparison to false.
    • Correct case for referenced and called function names.
    • Correct case for inherited and implemented method names.
    • Contravariance for parameter types and covariance for return types in inherited methods (also known as Liskov substitution principle - LSP)
    • Check LSP even for static methods
    • Require calling parent constructor
    • Disallow usage of backtick operator ($ls = `ls -la`)
    • Closure should use $this directly instead of using $this variable indirectly

    And the following extra:

    • Boolean casting is forbidden boolval() (bool) $var, prefer explicit operation e.g. $var === '' for if($var) where $var is a string.
    • Forbid the use of @ to silence errors
    • Verify that there are no unused variables

    Feel free to check: https://github.com/ildyria/WebAuthn/runs/7193039501?check_suite_focus=true to skim through the issues.

    Do note that this pull request does not include all the code fixes as you asked to see all the ingredients before baking the cake.

    enhancement help wanted 
    opened by ildyria 4
  • [minor] correct publishing the config file not working

    [minor] correct publishing the config file not working

    When Publishing the config file

    php artisan vendor:publish --provider="Laragear\WebAuthn\WebAuthnServiceProvider" --tag="config"
    

    It will return

    INFO  No publishable resources for tag [config].
    

    LINE FOR CONFIG WAS MISSING

    opened by fidelisepeter 3
  • POST /webauthn/register 422 at webauthn.js:159

    POST /webauthn/register 422 at webauthn.js:159

    HELP

    Please i am trying to use webauthn in my app i had to upgrade to laravel 9 to user Laragear/WebAuthn because i was unable to set up Larapass and i can't create any issue there.

    Wel Successfull Set WebAuthn but having Issue registering Device... I get 422 Error Code

    Actually need Help is not a bug

    bug 
    opened by fidelisepeter 3
  • [1.x] Allow user credential to have id = 0

    [1.x] Allow user credential to have id = 0

    Description

    if (!$credentials) {
      return null
    }
    

    will return null if $credentials is one of the following: null, 0, ''. I strongly believe that it is possible for a user_id to be 0 for example. This check is breaking in such occasion.

    This pull request aims to provide a stronger check while respecting the spirit of the code.

    opened by ildyria 3
  • [1.1.2] Routes namespace issue

    [1.1.2] Routes namespace issue

    PHP & Platform

    8.1.6 - Windows 11

    Database

    MySQL 8.0.27

    Laravel version

    9.33.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)
    • [X] I can suggest a workaround as a Pull Request

    Expectation

    On new install, have in my /routes/web

    use Laragear\WebAuthn\WebAuthn;
    WebAuthn::routes();
    

    When I try to use the register/options route, I get a 500 error

    Description

    In the log, I get this:

    [2022-10-04 01:07:58] local.ERROR: Target class [App\Http\Controllers\App\Http\Controllers\WebAuthn\WebAuthnRegisterController] does not exist. {"exception":"[object] (Illuminate\\Contracts\\Container\\BindingResolutionException(code: 0): Target class [App\\Http\\Controllers\\App\\Http\\Controllers\\WebAuthn\\WebAuthnRegisterController] does not exist. at C:\\wamp\\www\\station\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php:877)
    [stacktrace]
    

    It appears that there is a namespacing issue because App\Http\Controllers is repeated.

    For example, when I put the following in my web.php file, it works:

    Route::controller(WebAuthnRegisterController::class)->middleware('web')->prefix('webauthn')->group(function () {
      Route::post('register/options', 'options')->name('webauthn.register.options');
      Route::post('register', 'register')->name('webauthn.register');
    });
    Route::controller(WebAuthnLoginController::class)->middleware('web')->prefix('webauthn')->group(function () {
      Route::post('login/options', 'options')->name('webauthn.login.options');
      Route::post('login', 'login')->name('webauthn.login');
    });
    

    Reproduction

    As above
    

    Stack trace & logs

    as above
    
    bug 
    opened by mankowitz 2
  • [1.x] Fix: support for xcrf token

    [1.x] Fix: support for xcrf token

    Fixes #13

    Description

    • Add method to fetch the XSRF token from the header cookies.
    • Rework the logic to differentiate between XSRF and CSRF tokens (differentiating on the length: 40 vs 224).
    • Throw error if length of provided token in constructor argument does not match.
    • Throw error if no [xc]srf token are found & not provided
    opened by ildyria 2
  • Database Migration fails

    Database Migration fails

    PHP & Platform

    PHP 8.1.7 (in Valet) (MAC OS dev)

    Laravel version

    9.17.0

    Authenticator type

    not applicable

    OS and Browser versions

    MAC OS Monterrey, FireFox (current)

    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

    For the database migration to complete without error. I just ginned up a totally new clean install, installed breeze, created one user, then tried, same issue. MySQL: 10.7.3-MariaDB - Homebrew

    Description

    I get this error:

    Illuminate\Database\QueryException

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

    at vendor/laravel/framework/src/Illuminate/Database/Connection.php:742 738▕ // If an exception occurs when attempting to run a query, we'll format the error 739▕ // message to include the bindings with SQL, which will make this exception a 740▕ // lot more helpful to the developer instead of just the database's errors. 741▕ catch (Exception $e) { ➜ 742▕ throw new QueryException( 743▕ $query, $this->prepareBindings($bindings), $e 744▕ ); 745▕ } 746▕ }

      +9 vendor frames 
    

    10 database/migrations/2022_06_17_161949_create_webauthn_credentials.php:25 Illuminate\Support\Facades\Facade::__callStatic("create")

      +22 vendor frames 
    

    33 artisan:35 Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))

    Reproduction

    not applicable
    

    Stack trace & logs

    Illuminate\Database\QueryException 
    
      SQLSTATE[42000]: Syntax error or access violation: 1059 Identifier name 'webauthn_credentials_authenticatable_type_authenticatable_id_index' is too long (SQL: alter table `webauthn_credentials` add index `webauthn_credentials_authenticatable_type_authenticatable_id_index`(`authenticatable_type`, `authenticatable_id`))
    
      at vendor/laravel/framework/src/Illuminate/Database/Connection.php:742
        738▕         // If an exception occurs when attempting to run a query, we'll format the error
        739▕         // message to include the bindings with SQL, which will make this exception a
        740▕         // lot more helpful to the developer instead of just the database's errors.
        741▕         catch (Exception $e) {
      ➜ 742▕             throw new QueryException(
        743▕                 $query, $this->prepareBindings($bindings), $e
        744▕             );
        745▕         }
        746▕     }
    
          +9 vendor frames 
      10  database/migrations/2022_06_17_161949_create_webauthn_credentials.php:25
          Illuminate\Support\Facades\Facade::__callStatic("create")
    
          +22 vendor frames 
      33  artisan:35
          Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
    

    Attestation / Assertion objects

    No response

    Are you a Patreon supporter?

    No, don't give priority to this

    bug 
    opened by OliverGrimsley 2
  • POST https://domain/webauthn/register 422 at webauthn.js:159

    POST https://domain/webauthn/register 422 at webauthn.js:159

    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

    Please i am trying to use webauthn in my app i had to upgrade to laravel 9 to user Laragear/WebAuthn because i was unable to set up Larapass and i can't create any issue there.

    Wel Successfull Set WebAuthn but having Issue registering Device... I get 422 Error Code

    And when I tried publishing the config file.

    php artisan vendor:publish --provider="Laragear\WebAuthn\WebAuthnServiceProvider" --tag="config"

    It doesn't work.

    Please I need guidelines on how to successfully set it up

    Code sample

    public function register(AttestedRequest $request): Response
        {
            $request->save();
    
            return response()->noContent();
        }
    
    enhancement 
    opened by fidelisepeter 1
  • AttestationController not found

    AttestationController not found

    PHP & Platform

    8.1.2 & Ubuntu

    Database

    No response

    Laravel version

    9

    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)
    • [X] I can suggest a workaround as a Pull Request

    Expectation

    Description

    Hey Guys,

    The README file talks about an AttestationController file. This is not created during installation.

    1. How do I create these?
    2. How does Laravel know to speak to this controller?

    Reproduction

    -
    

    Stack trace & logs

    No response

    bug 
    opened by wwwDESIGN-basti 0
Releases(v1.1.4)
  • v1.1.4(Nov 11, 2022)

    What's Changed

    • [1.1.3] FIX: Query error when disabling all credentials by @Bubka in https://github.com/Laragear/WebAuthn/pull/23
    • [1.x] Adds tests for trait, fixing some methods. by @DarkGhostHunter in https://github.com/Laragear/WebAuthn/pull/24

    Full Changelog: https://github.com/Laragear/WebAuthn/compare/v1.1.3...v1.1.4

    Source code(tar.gz)
    Source code(zip)
  • v1.1.3(Oct 28, 2022)

    What's Changed

    • FIX: relaying_party typo by @Bubka in https://github.com/Laragear/WebAuthn/pull/20
    • [minor] correct publishing the config file not working by @fidelisepeter in https://github.com/Laragear/WebAuthn/pull/22

    New Contributors

    • @Bubka made their first contribution in https://github.com/Laragear/WebAuthn/pull/20
    • @fidelisepeter made their first contribution in https://github.com/Laragear/WebAuthn/pull/22

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

    Source code(tar.gz)
    Source code(zip)
  • v1.1.2(Aug 25, 2022)

    What's Changed

    • [1.x] FIX #10 - missing jetbrains/phpstorm-attributes dependency by @ildyria in https://github.com/Laragear/WebAuthn/pull/11
    • [1.x] FIX #6 - use class_implements as intended by @ildyria in https://github.com/Laragear/WebAuthn/pull/8
    • [1.x] Fix typos in readme. by @ildyria in https://github.com/Laragear/WebAuthn/pull/12
    • [1.x] Fix: support for xcrf token by @ildyria in https://github.com/Laragear/WebAuthn/pull/14
    • [1.x] Improve CI by @DarkGhostHunter in https://github.com/Laragear/WebAuthn/pull/15
    • [1.x] Allow user credential to have id = 0 by @ildyria in https://github.com/Laragear/WebAuthn/pull/16

    New Contributors

    • @ildyria made their first contribution in https://github.com/Laragear/WebAuthn/pull/11
    • @DarkGhostHunter made their first contribution in https://github.com/Laragear/WebAuthn/pull/15

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

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

  • v1.1.0(Jun 15, 2022)

    Before, you had to publish the routes and register them manually.

    Now, this step is simplified: only use WebAuthn::routes() to register a default set of routes.

    The previous method will still be available for version 1.x

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Jun 14, 2022)

Owner
Laragear
Packages for Laravel
Laragear
Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.

This is a port of the VCR Ruby library to PHP. Record your test suite's HTTP interactions and replay them during future test runs for fast, determinis

php-vcr 1.1k Dec 23, 2022
Requests for PHP is a humble HTTP request library. It simplifies how you interact with other sites and takes away all your worries.

Requests for PHP Requests is a HTTP library written in PHP, for human beings. It is roughly based on the API from the excellent Requests Python librar

null 3.5k Dec 31, 2022
PHP Curl Class makes it easy to send HTTP requests and integrate with web APIs

PHP Curl Class: HTTP requests made easy PHP Curl Class makes it easy to send HTTP requests and integrate with web APIs. Installation Requirements Quic

null 3.1k Jan 5, 2023
Simple handler system used to power clients and servers in PHP (this project is no longer used in Guzzle 6+)

RingPHP Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function. RingPHP be used to power HTTP clie

Guzzle 846 Dec 6, 2022
Application for logging HTTP and DNS Requests

Request Logger Made by Adam Langley ( https://twitter.com/adamtlangley ) What is it? Request logger is a free and open source utility for logging HTTP

null 13 Nov 28, 2022
librestful is a virion for PocketMine servers that make easier, readable code and for async http requests.

librestful is a virion for PocketMine servers that make easier, readable code for async rest requests.

RedMC Network 17 Oct 31, 2022
A simple PHP Toolkit to parallel generate combinations, save and use the generated terms to brute force attack via the http protocol.

Brutal A simple PHP Toolkit to parallel generate combinations, save and use the generated terms to apply brute force attack via the http protocol. Bru

Jean Carlo de Souza 4 Jul 28, 2021
🐼 Framework agnostic package using asynchronous HTTP requests and PHP generators to load paginated items of JSON APIs into Laravel lazy collections.

Framework agnostic package using asynchronous HTTP requests and generators to load paginated items of JSON APIs into Laravel lazy collections.

Andrea Marco Sartori 61 Dec 3, 2022
Pushpin is a publish-subscribe server, supporting HTTP and WebSocket connections.

Pushpin and 1 million connections Pushpin is a publish-subscribe server, supporting HTTP and WebSocket connections. This repository contains instructi

Fanout 14 Jul 15, 2022
A functional and simple rate limit control to prevent request attacks ready-to-use for PHP.

RateLimitControl A functional and simple rate limit control to prevent request attacks ready-to-use for PHP. Features: Prepared statements (using PDO)

b(i*2)tez 5 Sep 16, 2022
Proxy method and property interactions in PHP. ⚡️

Proxy method and property interactions in PHP. Provides a Proxy class that can be used to intercept method calls, property access and updates. Support

Ryan Chandler 4 Mar 28, 2022
Composer package providing HTTP Methods, Status Codes and Reason Phrases for PHP

HTTP Enums For PHP 8.1 and above This package provides HTTP Methods, Status Codes and Reason Phrases as PHP 8.1+ enums All IANA registered HTTP Status

Alexander Pas 72 Dec 23, 2022
Read-only WebDAV server written in php8.0; supports browsing archives and GETting files in encodings other than what's on disk

Best Read-only WebDAV Server: TODO Features and notes of implementation Keeping generated files in a place that nginx can find them (2 ways to do this

Joe Koop 1 Nov 17, 2021
Finds installed HTTPlug implementations and PSR-7 message factories.

Finds installed HTTPlug implementations and PSR-7 message factories.

The PHP HTTP group 1.1k Dec 29, 2022
Event-driven, streaming HTTP client and server implementation for ReactPHP

HTTP Event-driven, streaming HTTP client and server implementation for ReactPHP. This HTTP library provides re-usable implementations for an HTTP clie

ReactPHP 640 Dec 29, 2022
A simple yet powerful HTTP metadata and assets provider for NFT collections using Symfony

Safe NFT Metadata Provider A simple yet powerful HTTP metadata and assets provider for NFT collections using Symfony.

HashLips Lab 66 Oct 7, 2022
The Library for HTTP Status Codes, Messages and Exception

This is a PHP library for HTTP status codes, messages and error exception. Within the library, HTTP status codes are available in classes based on the section they belong to. Click this link for more information.

Sabuhi Alizada 5 Sep 14, 2022
YOURLS QRCode plugin with exposed options and full integration

YOURLS-IQRCodes YOURLS Integrated QRCodes plugin with exposed options and full integration This is an updated fork of Inline QRCode which is more comp

Josh Panter 17 Oct 4, 2021
Declarative HTTP Clients using Guzzle HTTP Library and PHP 8 Attributes

Waffler How to install? $ composer require waffler/waffler This package requires PHP 8 or above. How to test? $ composer phpunit Quick start For our e

Waffler 3 Aug 26, 2022