Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/asbiin/laravel-webauthn
Webauthn adapter for Laravel
https://github.com/asbiin/laravel-webauthn
authentication hacktoberfest laravel laravel-webauthn library php webauthn
Last synced: about 17 hours ago
JSON representation
Webauthn adapter for Laravel
- Host: GitHub
- URL: https://github.com/asbiin/laravel-webauthn
- Owner: asbiin
- License: mit
- Created: 2019-03-30T11:10:45.000Z (over 5 years ago)
- Default Branch: main
- Last Pushed: 2024-08-26T11:31:01.000Z (4 months ago)
- Last Synced: 2024-10-25T06:27:28.365Z (about 2 months ago)
- Topics: authentication, hacktoberfest, laravel, laravel-webauthn, library, php, webauthn
- Language: PHP
- Homepage:
- Size: 591 KB
- Stars: 273
- Watchers: 6
- Forks: 38
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE.md
Awesome Lists containing this project
- awesome-webauthn - asbiin: laravel-webauthn - A Laravel adapter for the WebAuthn Framework (from Spomky-Labs). (Server Libraries)
README
Webauthn adapter for Laravel
============================[![Latest Version](https://img.shields.io/packagist/v/asbiin/laravel-webauthn.svg?style=flat-square&label=Latest%20Version)](https://github.com/asbiin/laravel-webauthn/releases)
[![Downloads](https://img.shields.io/packagist/dt/asbiin/laravel-webauthn.svg?style=flat-square&label=Downloads)](https://packagist.org/packages/asbiin/laravel-webauthn)
[![Workflow Status](https://img.shields.io/github/actions/workflow/status/asbiin/laravel-webauthn/tests.yml?branch=main&style=flat-square&label=Workflow%20Status)](https://github.com/asbiin/laravel-webauthn/actions?query=branch%3Amain)
[![Quality Gate](https://img.shields.io/sonar/quality_gate/asbiin_laravel-webauthn?server=https%3A%2F%2Fsonarcloud.io&style=flat-square&label=Quality%20Gate)](https://sonarcloud.io/dashboard?id=asbiin_laravel-webauthn)
[![Coverage Status](https://img.shields.io/sonar/coverage/asbiin_laravel-webauthn?server=https%3A%2F%2Fsonarcloud.io&style=flat-square&label=Coverage%20Status)](https://sonarcloud.io/dashboard?id=asbiin_laravel-webauthn)- [Features](#features)
- [Installation](#installation)
- [Configuration](#configuration)
- [Set Up](#set-up)
- [Option 1: add LaravelWebauthn middleware](#option-1-add-laravelwebauthn-middleware)
- [Login via remember](#login-via-remember)
- [Option 2: Passwordless authentication](#option-2-passwordless-authentication)
- [Disabling Views](#disabling-views)
- [Cache](#cache)
- [Usage](#usage)
- [Authenticate](#authenticate)
- [Register a new key](#register-a-new-key)
- [Routes](#routes)
- [Ignore route creation](#ignore-route-creation)
- [Customizing The Authentication Pipeline](#customizing-the-authentication-pipeline)
- [Rate Limiter](#rate-limiter)
- [Events](#events)
- [View response](#view-response)
- [Compatibility](#compatibility)
- [Laravel compatibility](#laravel-compatibility)
- [Browser compatibility](#browser-compatibility)
- [Homestead](#homestead)
- [License](#license)**LaravelWebauthn** is the adapter to use Webauthn as [2FA](https://en.wikipedia.org/wiki/Multi-factor_authentication) (two-factor authentication) or as passwordless authentication on Laravel.
**Try this now on the [demo application](https://webauthn.asbin.net/).**
# Features
- Manage Webauthn keys registration
- 2nd factor authentication: add a middleware service to use a Webauthn key as 2FA
- Login provider using a Webauthn key, without password# Installation
Install this package with:
```sh
composer require asbiin/laravel-webauthn
```## Configuration
You can publish LaravelWebauthn configuration in a file named `config/webauthn.php`, and resources using the `vendor:publish` command:
```sh
php artisan vendor:publish --provider="LaravelWebauthn\WebauthnServiceProvider"
```Next, you should migrate your database:
```sh
php artisan migrate
```# Set Up
## Option 1: add LaravelWebauthn middleware
The Webauthn middleware will force the user to authenticate their webauthn key for certain routes.
Assign the middleware to a route or a group of routes:
```php
use LaravelWebauthn\Http\Middleware\WebauthnMiddleware;Route::get('/home', function () {
// ...
})->middleware(WebauthnMiddleware::class);
```The Webauthn middleware will redirect the user to the webauthn login page when required.
### Login via remember
When session expires, but the user have set the `remember` cookie, you can revalidate webauthn session by subscribing to the `LaravelWebauthn\Listeners\LoginViaRemember` listener:
```php
use Illuminate\Support\Facades\Event;
use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Event::listen(
\Illuminate\Auth\Events\Login::class,
\LaravelWebauthn\Listeners\LoginViaRemember::class
);
}
}
```## Option 2: Passwordless authentication
You can use Webauthn to authenticate a user without a password, using only a webauthn key authentication.
To enable passwordless authentication, first add the webauthn user provider: update your `config/auth.php` file and change the `users` provider:
```php
'providers' => [
'users' => [
'driver' => 'webauthn',
'model' => App\Models\User::class,
],
],
```Then allow your login page to initiate a webauthn login with an `email` identifier.
You can call `webauthn.auth.options` route with a POST request and an `email` input to get the challenge data.
See [authentication](#Authenticate) section for more details.## Disabling Views
By default LaravelWebauthn defines routes that are intended to return views for authentication and register key.
However, if you are building a JavaScript driven single-page application, you may not need these routes. For that reason, you may disable these routes entirely by setting the `views` configuration value within your application's `config/webauthn.php` configuration file to false:
```php
'views' => false,
```## Cache
Note this package uses the cache to store the challenge data between the server request and the browser response. You'll need to setup a real cache driver from your `config/cache.php` file, and thus you can't use the `array` or `null` driver.
# Usage
You will find an example of usage on [asbiin/laravel-webauthn-example](https://github.com/asbiin/laravel-webauthn-example). You can try it right now on the [demo application](https://webauthn.asbin.net/).
## Authenticate
To authenticate with a webauthn key, the workflow is the following:
1. Open the `webauthn.login` login page.
You can customize the login page view by calling `Webauthn::loginViewResponseUsing`. See [View response](#view-response)The default behavior will open the [webauthn::authenticate](/resources/views/authenticate.blade.php) page.
You can also change the value of `webauthn.views.authenticate` in the configuration file.2. Or: Get the publicKey challenge by calling `webauthn.auth.options` (if not provided).
3. Start the webauthn browser authentication.
You can use the [`webauthn.js`](/resources/js/webauthn.js) library to do this.Send the signed data to `webauthn.auth` route.
4. The POST response will be:
- a redirect response
- or a json response with a `callback` data.Example:
```html
...
var publicKey = {!! json_encode($publicKey) !!};var webauthn = new WebAuthn();
webauthn.sign(
publicKey,
function (data) {
axios.post("{{ route('webauthn.auth') }}", data)
.then(function (response) {
if (response.data.callback) { window.location.href = response.data.callback;}
});
}
);
```If the authentication is successful, the server will use the `webauthn.redirects.login` configuration:
- to redirect the response on a plain http call
- or with a json response, like:
```javascript
{
result: true,
callback: `webauthn.redirects.login` target url,
}
```## Register a new key
To register a new webauthn key, the workflow is the following:
1. Open the `webauthn.register` page.
You can customize the register page view by calling `Webauthn::registerViewResponseUsing`. See [View response](#view-response)The default behavior will open the [webauthn::register](/resources/views/register.blade.php) page.
You can also change the value of `webauthn.views.register` in the configuration file.2. Or: Get the publicKey challenge by calling `webauthn.store.options` (if not provided).
3. Start the webauthn browser registration.
You can use the [`webauthn.js`](/resources/js/webauthn.js) library to do this.Send the signed data to `webauthn.store` route.
The data should contain a `name` field with the webauthn key name.4. The POST response will be:
- a redirect response
- or a json response with a `callback` data.Example:
```html
...
var publicKey = {!! json_encode($publicKey) !!};var webauthn = new WebAuthn();
webauthn.register(
publicKey,
function (data) {
axios.post("{{ route('webauthn.store') }}", {
...data,
name: "{{ $name }}",
})
}
);
```If the registration is successful, the server will use the `webauthn.redirects.register` configuration:
- to redirect the response on a plain http call
- or with a json response, like:
```javascript
{
result: json serialized webauthn key value,
callback: `webauthn.redirects.register` target url,
}
```## Routes
These routes are defined:
| Request | Route | Description |
|-------------------------------|--------------------------|-----------------------------------------------------------------------|
| GET `/webauthn/auth` | `webauthn.login` | The login page. |
| POST `/webauthn/auth/options` | `webauthn.auth.options` | Get the publicKey and challenge to initiate a WebAuthn login. |
| POST `/webauthn/auth` | `webauthn.auth` | Post data after a WebAuthn login validate. |
| GET `/webauthn/keys/create` | `webauthn.create` | The register key page. |
| POST `/webauthn/keys/options` | `webauthn.store.options` | Get the publicKeys and challenge to initiate a WebAuthn registration. |
| POST `/webauthn/keys` | `webauthn.store` | Post data after a WebAuthn register check. |
| DELETE `/webauthn/keys/{id}` | `webauthn.destroy` | Delete an existing key. |
| PUT `/webauthn/keys/{id}` | `webauthn.update` | Update key properties (name, ...). |You can customize the first part of the url by setting `prefix` value in the config file.
### Ignore route creation
You can disable the routes creation by adding this in your `AppServiceProvider`:
```php
use LaravelWebauthn\Services\Webauthn;
use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
Webauthn::ignoreRoutes();
}
}
```## Customizing The Authentication Pipeline
The Laravel Webauthn authentication pipeline is highly inspired by the [Fortify pipeline](https://laravel.com/docs/9.x/fortify#customizing-the-authentication-pipeline).
If you would like, you may define a custom pipeline of classes that login requests should be piped through. Each class should have an `__invoke` method which receives the incoming `Illuminate\Http\Request` instance and, like middleware, a `$next` variable that is invoked in order to pass the request to the next class in the pipeline.
To define your custom pipeline, you may use the `Webauthn::authenticateThrough` method. This method accepts a closure which should return the array of classes to pipe the login request through. Typically, this method should be called from the `boot` method of your `App\Providers\FortifyServiceProvider` class.
The example below contains the default pipeline definition that you may use as a starting point when making your own modifications:
```php
use LaravelWebauthn\Actions\AttemptToAuthenticate;
use LaravelWebauthn\Actions\EnsureLoginIsNotThrottled;
use LaravelWebauthn\Actions\PrepareAuthenticatedSession;
use LaravelWebauthn\Services\Webauthn;
use Illuminate\Http\Request;Webauthn::authenticateThrough(fn (Request $request) => array_filter([
config('webauthn.limiters.login') !== null ? null : EnsureLoginIsNotThrottled::class,
AttemptToAuthenticate::class,
PrepareAuthenticatedSession::class,
]));
```## Rate Limiter
By default, Laravel Webauthn will throttle logins to five requests per minute for every email and IP address combination. You may specify a custom rate limiter with other specifications.
First define a custom rate limiter. Follow [Laravel rate limiter documentation](https://laravel.com/docs/11.x/routing#defining-rate-limiters) to create a new RateLimiter within the `boot` method of your application's `App\Providers\AppServiceProvider` class.
```php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
protected function boot(): void
{
RateLimiter::for('webauthn-login', function (Request $request) {
return Limit::perMinute(1000);
});
}
}
```Then use this new custom rate limiter in your `webauthn.limiters.login` configuration:
```php
'limiters' => [
'login' => 'webauthn-login',
],
```## Events
Events are dispatched by LaravelWebauthn:
* `\LaravelWebauthn\Events\WebauthnLogin` on login with Webauthn check.
* `\LaravelWebauthn\Events\WebauthnLoginData` on preparing authentication data challenge.
* `\Illuminate\Auth\Events\Failed` on a failed login check.
* `\LaravelWebauthn\Events\WebauthnRegister` on registering a new key.
* `\LaravelWebauthn\Events\WebauthnRegisterData` on preparing register data challenge.
* `\LaravelWebauthn\Events\WebauthnRegisterFailed` on failing registering a new key.## View response
You can easily change the view responses with the Webauthn service.
For instance, call `Webauthn::loginViewResponseUsing` in your `App\Providers\AppServiceProvider` class:
```php
use LaravelWebauthn\Services\Webauthn;class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
Webauthn::loginViewResponseUsing(LoginViewResponse::class);
}
}
```With a `LoginViewResponse` class:
```php
use LaravelWebauthn\Http\Responses\LoginViewResponse as LoginViewResponseBase;class LoginViewResponse extends LoginViewResponseBase
{
public function toResponse($request)
{
return Inertia::render('Webauthn/WebauthnLogin', [
'publicKey' => $this->publicKey
])->toResponse($request);
}
}
```List of methods and their expected response contracts:
| Webauthn static methods | `\LaravelWebauthn\Contracts` |
|--------------------------------|-----------------------------------|
| `loginViewResponseUsing` | `LoginViewResponseContract` |
| `loginSuccessResponseUsing` | `LoginSuccessResponseContract` |
| `registerViewResponseUsing` | `RegisterViewResponseContract` |
| `registerSuccessResponseUsing` | `RegisterSuccessResponseContract` |
| `destroyViewResponseUsing` | `DestroyResponseContract` |
| `updateViewResponseUsing` | `UpdateResponseContract` |# Compatibility
## Laravel compatibility
This package has the following Laravel compatibility:
| Laravel | [asbiin/laravel-webauthn](https://github.com/asbiin/laravel-webauthn) |
|----------|----------|
| 5.8-8.x | <= 1.2.0 |
| 7.x-8.x | 2.0.1 |
| >= 9.x | >= 3.0.0 |## Browser compatibility
Most of the browsers [support Webauthn](https://caniuse.com/webauthn).
However, your browser will refuse to negotiate a relay to your security device without the following:
- a proper domain (localhost and 127.0.0.1 will be rejected by `webauthn.js`)
- an SSL/TLS certificate trusted by your browser (self-signed is okay)
- connected HTTPS on port 443 (ports other than 443 will be rejected)### Homestead
If you are a Laravel Homestead user, the default is to forward ports. You can switch from NAT/port forwarding to a private network with similar `Homestead.yaml` options:```yaml
sites:
- map: homestead.test
networks:
- type: "private_network"
ip: "192.168.254.2"
```Re-provisioning vagrant will inform your virtual machine of the new network and install self-signed SSL/TLS certificates automatically: `vagrant reload --provision`
If you haven't done so already, describe your site domain and network in your hosts file:
```
192.168.254.2 homestead.test
```# License
Author: [Alexis Saettler](https://github.com/asbiin)
Copyright © 2019–2024.
Licensed under the MIT License. [View license](/LICENSE.md).