95 lines
2.1 KiB
TypeScript
95 lines
2.1 KiB
TypeScript
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)
|
|
}
|
|
}
|