website/islands/PassKeyRegister.tsx

95 lines
2.1 KiB
TypeScript
Raw Normal View History

import { startRegistration } from '@simplewebauthn/browser'
import { PublicKeyCredentialCreationOptionsJSON } from '@simplewebauthn/types'
import { Button } from 'univoq'
import type {
WebAuthnRegisterFinishPayload,
WebAuthnRegisterStartPayload,
} from '../routes/api/webauthn/register/[step].ts'
import { requestApi } from '../src/utils.ts'
function isWebAuthnSupported(): boolean {
return 'credentials' in navigator
}
function RegisterButton({ disabled }: { disabled?: boolean }) {
return (
<Button
label='Enregistrer une PassKey'
variant='primary'
onClick={register}
disabled={disabled}
>
Enregistrer une PassKey
</Button>
)
}
export default function PassKeyRegister() {
if (!isWebAuthnSupported()) {
return (
<label>
<span>Erreur: WebAuthn n'est pas supporté par votre navigateur</span>
<RegisterButton disabled />
</label>
)
}
return (
<label>
<span>Enregistrer une PassKey pour cet appareil</span>
<RegisterButton />
</label>
)
}
async function register() {
try {
await webAuthnRegister()
} catch (cause) {
console.error(
new Error('passkey register failed', {
cause,
}),
)
}
}
async function webAuthnRegister() {
if (localStorage.getItem('webauthn-registered')) {
return
}
const registrationOptions = await requestApi<
WebAuthnRegisterStartPayload,
PublicKeyCredentialCreationOptionsJSON
>('webauthn/register/start', 'POST')
// Pass the options to the authenticator and wait for a response
const registration = await startRegistration(registrationOptions)
.catch((error) => {
// Some basic error handling
if (error.name === 'InvalidStateError') {
console.error(
'Authenticator was probably already registered by user',
)
return null
} else {
throw error
}
})
if (registration === null) return
// Verify the registration
try {
await requestApi<
WebAuthnRegisterFinishPayload,
{ verified: boolean }
>('webauthn/register/finish', 'POST', registration)
console.log('Success!')
localStorage.setItem('webauthn-registered', 'true')
} catch (error) {
console.error('Oh no, something went wrong! Response:', error)
}
}