WebAuthn Key Registration - Laravel WebAuthn Package
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{{-- note: you will need to implement your own "modal" component for this to work properly. see laravel/jetstream for modal example --}} | |
<div> | |
@if (\Rawilk\Webauthn\Facades\Webauthn::webauthnEnabled()) | |
@webauthnScripts | |
<button type="button" wire:click="showAddKey"> | |
Add security key | |
</button> | |
<!-- register modal --> | |
<div x-data="{ | |
keyName: @entangle('newKeyName').defer, | |
showInstructions: @entangle('showInstructions').defer, | |
showName: false, | |
webAuthn: new WebAuthn, | |
webAuthnSupported: true, | |
errorMessages: {{ Js::from($this->errorMessages) }}, | |
errorMessage: null, | |
notifyCallback() { | |
return (errorName, defaultMessage) => { | |
this.errorMessage = this.errorMessages[errorName] || defaultMessage; | |
}; | |
}, | |
keyData: null, | |
publicKey: @entangle('publicKey').defer, | |
init() { | |
this.webAuthnSupported = this.webAuthn.supported(); | |
if (! this.webAuthnSupported) { | |
this.errorMessage = this.errorMessages[this.webAuthn.notSupportedType()]; | |
} | |
// Register a callback when errors happen so we can notify the user. | |
this.webAuthn.registerNotifyCallback(this.notifyCallback()); | |
}, | |
// Prompt user to register their security key. | |
register() { | |
if (! this.webAuthnSupported) { | |
return; | |
} | |
this.errorMessage = null; | |
this.keyData = null; | |
this.showInstructions = false; | |
this.showName = false; | |
// This is the most important part! | |
this.webAuthn.register(JSON.parse(this.publicKey), (publicKeyCredential, deviceName) => { | |
// WebAuthn script will try to guess the device's name. | |
this.keyName = deviceName; | |
this.keyData = publicKeyCredential; | |
this.showName = true; | |
setTimeout(() => this.$refs.name.focus(), 250); | |
}); | |
}, | |
// Send the key data to the server. | |
sendKey() { | |
if (! this.keyData) { | |
return; | |
} | |
@this.registerKey(this.keyData); | |
}, | |
}"> | |
<x-dialog-modal wire:model.defer="showAddKey"> | |
<x-slot name="title">Register Security Key</x-slot> | |
<x-slot name="content"> | |
<div x-show="showInstructions && webAuthnSupported"> | |
<p>Some instructions on how to use a security key here...</p> | |
</div> | |
<div x-show="! showInstructions || ! webAuthnSupported"> | |
<!-- we are waiting for user to interact with their authenticator --> | |
<div x-show="! showName && ! errorMessage && webAuthnSupported"> | |
<p>Interact with your authenticator...</p> | |
</div> | |
<!-- an error ocurred (user probably canceled) --> | |
<div x-show="errorMessage"> | |
<p x-html="errorMessage"></p> | |
<button type="button" x-on:click="register">Retry</button> | |
</div> | |
<!-- registration successful, now name key --> | |
<div x-show="showName"> | |
<label for="newKeyName">Name your key</label> | |
<input | |
x-model="keyName" | |
name="newKeyName" | |
id="newKeyName" | |
required | |
x-ref="name" | |
x-on:keydown.enter.prevent.stop="keyName && sendKey" | |
> | |
</div> | |
</div> | |
</x-slot> | |
<x-slot name="footer"> | |
<!-- button to open webauthn prompt --> | |
<button type="button" x-show="showInstructions" x-on:click="register">Next</button> | |
<!-- button to complete registration --> | |
<button type="button" | |
x-show="! showInstructions && showName" | |
x-on:click="sendKey" | |
x-bind:disabled="! keyName" | |
> | |
Register key | |
</button> | |
</x-slot> | |
</x-dialog-modal> | |
</div> | |
@endif | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Illuminate\Support\Facades\Lang; | |
use Livewire\Component; | |
use Rawilk\Webauthn\Actions\PrepareKeyCreationData; | |
class RegisterWebauthnKey extends Component | |
{ | |
/** | |
* This will be the public key credential options required for the front-end. | |
*/ | |
public ?string $publicKey = null; | |
/** | |
* Indicates whether or not to show the key registration modal. | |
*/ | |
public bool $showAddKey = false; | |
/** | |
* The name for the newly registered security key. | |
*/ | |
public string $newKeyName = ''; | |
/** | |
* Indicates security key instructions should be shown in the modal. | |
*/ | |
public bool $showInstructions = true; | |
public function getErrorMessagesProperty(): array | |
{ | |
return [ | |
...Lang::get('webauthn::alerts.auth') ?? [], | |
'InvalidStateError' => __('webauthn::alerts.login_not_allowed_error'), | |
'notSupported' => __('webauthn::alerts.browser_not_supported'), | |
'notSecured' => __('webauthn::alerts.browser_not_secure'), | |
]; | |
} | |
/** | |
* Show the register security key modal dialog. | |
*/ | |
public function showAddKey(): void | |
{ | |
$this->resetErrorBag(); | |
$this->showInstructions = true; | |
$this->showAddKey = true; | |
} | |
public function render() | |
{ | |
if (! $this->publicKey) { | |
$this->publicKey = json_encode(app(PrepareKeyCreationData::class)(auth()->user())); | |
} | |
return view('livewire.register-webauthn-key'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment