Fallback by email
When WebAuthn is not available, use the email fallback. All methods return Result<T, TryMellonError>.
Flow
- Start the flow: send OTP to the user’s email.
- Ask the user for the code.
- Verify the code and get a session token.
- Send the session token to your backend (same as with passkeys).
Example
// 1. Send OTP
const startResult = await client.fallback.email.start({ userId: 'user_123' })
if (!startResult.ok) {
console.error(startResult.error)
return
}
// 2. Get code from user
const code = prompt('Enter the code sent by email:')
// 3. Verify
const verifyResult = await client.fallback.email.verify({
userId: 'user_123',
code: code,
})
if (!verifyResult.ok) {
console.error(verifyResult.error)
return
}
// 4. Send to backend
await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ session_token: verifyResult.value.sessionToken }),
})
Combined flow (passkey with fallback)
async function authenticateUser(userId: string) {
if (!TryMellon.isSupported()) {
return await authenticateWithEmail(userId)
}
const authResult = await client.authenticate({ externalUserId: userId })
if (authResult.ok) return authResult
if (
authResult.error.code === 'PASSKEY_NOT_FOUND' ||
authResult.error.code === 'NOT_SUPPORTED'
) {
return await authenticateWithEmail(userId)
}
return authResult
}
async function authenticateWithEmail(userId: string) {
const startRes = await client.fallback.email.start({ userId })
if (!startRes.ok) return startRes
const code = prompt('Enter the code sent by email:')
return await client.fallback.email.verify({ userId, code })
}