Skip to content

Commit 30a399b

Browse files
committed
feat: Improve error handling and registration options for WebAuthn passkeys
- Enhanced error parsing in passkey login to extract specific error messages - Updated registration options schema to include optional authenticator selection parameters - Renamed schema from RegistrationResultSchema to RegistrationOptionsSchema for clarity
1 parent 2078c90 commit 30a399b

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

app/routes/_auth+/login.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,21 @@ function PasskeyLogin({
255255
})
256256

257257
if (!verificationResponse.ok) {
258-
throw new Error('Failed to authenticate with passkey')
258+
const json = await verificationResponse.json().catch(() => ({
259+
status: 'error',
260+
error: 'Unknown error',
261+
}))
262+
const parsed = z
263+
.object({
264+
status: z.literal('error'),
265+
error: z.string(),
266+
})
267+
.safeParse(json)
268+
if (parsed.success) {
269+
throw new Error(parsed.data.error)
270+
} else {
271+
throw new Error('Unknown error')
272+
}
259273
}
260274

261275
const verificationJson = await verificationResponse.json()

app/routes/settings+/profile.passkeys.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export async function action({ request }: Route.ActionArgs) {
5656
)
5757
}
5858

59-
const RegistrationResultSchema = z.object({
59+
const RegistrationOptionsSchema = z.object({
6060
options: z.object({
6161
rp: z.object({
6262
id: z.string(),
@@ -74,6 +74,20 @@ const RegistrationResultSchema = z.object({
7474
alg: z.number(),
7575
}),
7676
),
77+
authenticatorSelection: z
78+
.object({
79+
authenticatorAttachment: z
80+
.enum(['platform', 'cross-platform'])
81+
.optional(),
82+
residentKey: z
83+
.enum(['required', 'preferred', 'discouraged'])
84+
.optional(),
85+
userVerification: z
86+
.enum(['required', 'preferred', 'discouraged'])
87+
.optional(),
88+
requireResidentKey: z.boolean().optional(),
89+
})
90+
.optional(),
7791
}),
7892
}) satisfies z.ZodType<{ options: PublicKeyCredentialCreationOptionsJSON }>
7993

@@ -86,7 +100,7 @@ export default function Passkeys({ loaderData }: Route.ComponentProps) {
86100
setError(null)
87101
const resp = await fetch('/webauthn/registration')
88102
const jsonResult = await resp.json()
89-
const parsedResult = RegistrationResultSchema.parse(jsonResult)
103+
const parsedResult = RegistrationOptionsSchema.parse(jsonResult)
90104

91105
const regResult = await startRegistration({
92106
optionsJSON: parsedResult.options,

0 commit comments

Comments
 (0)