feat(ux): allow user to name passkey at register

This commit is contained in:
Julien Oculi 2024-06-19 10:34:43 +02:00
parent ee69d545b5
commit b01bbfdb5b

View file

@ -1,6 +1,6 @@
import { startRegistration } from '@simplewebauthn/browser'
import { PublicKeyCredentialCreationOptionsJSON } from '@simplewebauthn/types'
import { Button } from 'univoq'
import { Button, Input } from 'univoq'
import type {
WebAuthnRegisterFinishPayload,
WebAuthnRegisterStartPayload,
@ -11,40 +11,50 @@ function isWebAuthnSupported(): boolean {
return 'credentials' in navigator
}
function RegisterButton({ disabled }: { disabled?: boolean }) {
function RegisterForm({ disabled }: { disabled?: boolean }) {
return (
<Button
label='Enregistrer une PassKey'
variant='primary'
onClick={register}
disabled={disabled}
>
Enregistrer une PassKey
</Button>
<form onSubmit={register} method='POST' action=''>
<Input label='Nom de la clé' name='name' required></Input>
<Button
label='Enregistrer une PassKey'
variant='primary'
disabled={disabled}
>
Enregistrer une PassKey
</Button>
</form>
)
}
export default function PassKeyRegister() {
if (!isWebAuthnSupported()) {
return (
<label>
<div>
<span>Erreur: WebAuthn n'est pas supporté par votre navigateur</span>
<RegisterButton disabled />
</label>
<RegisterForm disabled />
</div>
)
}
return (
<label>
<div>
<span>Enregistrer une PassKey pour cet appareil</span>
<RegisterButton />
</label>
<RegisterForm />
</div>
)
}
async function register() {
type RegisterFormFields = {
name: string
}
async function register(event: Event) {
if (!(event instanceof SubmitEvent)) return false
event.preventDefault()
const form = event.target as HTMLFormElement
const fields = formJSON<RegisterFormFields>(form)
try {
await webAuthnRegister()
await webAuthnRegister(fields)
} catch (cause) {
console.error(
new Error('passkey register failed', {
@ -54,7 +64,7 @@ async function register() {
}
}
async function webAuthnRegister() {
async function webAuthnRegister(fields: RegisterFormFields) {
if (localStorage.getItem('webauthn-registered')) {
return
}
@ -62,7 +72,7 @@ async function webAuthnRegister() {
const registrationOptions = await requestApi<
WebAuthnRegisterStartPayload,
PublicKeyCredentialCreationOptionsJSON
>('webauthn/register/start', 'POST')
>('webauthn/register/start', 'POST', fields)
// Pass the options to the authenticator and wait for a response
const registration = await startRegistration(registrationOptions)
@ -92,3 +102,8 @@ async function webAuthnRegister() {
console.error('Oh no, something went wrong! Response:', error)
}
}
function formJSON<T extends Record<string, unknown>>(form: HTMLFormElement): T {
const formData = new FormData(form)
return Object.fromEntries(formData) as unknown as T
}