feat(ux): ✨ allow user to name passkey at register
This commit is contained in:
parent
ee69d545b5
commit
b01bbfdb5b
|
@ -1,6 +1,6 @@
|
||||||
import { startRegistration } from '@simplewebauthn/browser'
|
import { startRegistration } from '@simplewebauthn/browser'
|
||||||
import { PublicKeyCredentialCreationOptionsJSON } from '@simplewebauthn/types'
|
import { PublicKeyCredentialCreationOptionsJSON } from '@simplewebauthn/types'
|
||||||
import { Button } from 'univoq'
|
import { Button, Input } from 'univoq'
|
||||||
import type {
|
import type {
|
||||||
WebAuthnRegisterFinishPayload,
|
WebAuthnRegisterFinishPayload,
|
||||||
WebAuthnRegisterStartPayload,
|
WebAuthnRegisterStartPayload,
|
||||||
|
@ -11,40 +11,50 @@ function isWebAuthnSupported(): boolean {
|
||||||
return 'credentials' in navigator
|
return 'credentials' in navigator
|
||||||
}
|
}
|
||||||
|
|
||||||
function RegisterButton({ disabled }: { disabled?: boolean }) {
|
function RegisterForm({ disabled }: { disabled?: boolean }) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<form onSubmit={register} method='POST' action=''>
|
||||||
label='Enregistrer une PassKey'
|
<Input label='Nom de la clé' name='name' required></Input>
|
||||||
variant='primary'
|
<Button
|
||||||
onClick={register}
|
label='Enregistrer une PassKey'
|
||||||
disabled={disabled}
|
variant='primary'
|
||||||
>
|
disabled={disabled}
|
||||||
Enregistrer une PassKey
|
>
|
||||||
</Button>
|
Enregistrer une PassKey
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PassKeyRegister() {
|
export default function PassKeyRegister() {
|
||||||
if (!isWebAuthnSupported()) {
|
if (!isWebAuthnSupported()) {
|
||||||
return (
|
return (
|
||||||
<label>
|
<div>
|
||||||
<span>Erreur: WebAuthn n'est pas supporté par votre navigateur</span>
|
<span>Erreur: WebAuthn n'est pas supporté par votre navigateur</span>
|
||||||
<RegisterButton disabled />
|
<RegisterForm disabled />
|
||||||
</label>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<label>
|
<div>
|
||||||
<span>Enregistrer une PassKey pour cet appareil</span>
|
<span>Enregistrer une PassKey pour cet appareil</span>
|
||||||
<RegisterButton />
|
<RegisterForm />
|
||||||
</label>
|
</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 {
|
try {
|
||||||
await webAuthnRegister()
|
await webAuthnRegister(fields)
|
||||||
} catch (cause) {
|
} catch (cause) {
|
||||||
console.error(
|
console.error(
|
||||||
new Error('passkey register failed', {
|
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')) {
|
if (localStorage.getItem('webauthn-registered')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -62,7 +72,7 @@ async function webAuthnRegister() {
|
||||||
const registrationOptions = await requestApi<
|
const registrationOptions = await requestApi<
|
||||||
WebAuthnRegisterStartPayload,
|
WebAuthnRegisterStartPayload,
|
||||||
PublicKeyCredentialCreationOptionsJSON
|
PublicKeyCredentialCreationOptionsJSON
|
||||||
>('webauthn/register/start', 'POST')
|
>('webauthn/register/start', 'POST', fields)
|
||||||
|
|
||||||
// Pass the options to the authenticator and wait for a response
|
// Pass the options to the authenticator and wait for a response
|
||||||
const registration = await startRegistration(registrationOptions)
|
const registration = await startRegistration(registrationOptions)
|
||||||
|
@ -92,3 +102,8 @@ async function webAuthnRegister() {
|
||||||
console.error('Oh no, something went wrong! Response:', error)
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue