TryMellon

Fallback by email

Use email OTP when WebAuthn is not available.

Fallback by email

When WebAuthn is not available, use the email fallback. All methods return Result<T, TryMellonError>.

Flow

  1. Start the flow: send OTP to the user’s email.
  2. Ask the user for the code.
  3. Verify the code and get a session token.
  4. Send the session token to your backend (same as with passkeys).

Example

The backend requires both userId and email for sending the OTP. Use the same value for both when the user identifier is their email.

// 1. Send OTP (userId = external id, email = where to send the code)
const startResult = await client.fallback.email.start({
  userId: 'user_123',
  email: 'user@example.com',
})
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({ sessionToken: verifyResult.value.sessionToken }),
})

Combined flow (passkey with fallback)

async function authenticateUser(userId: string, email: string) {
  if (!TryMellon.isSupported()) {
    return await authenticateWithEmail(userId, email)
  }

  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, email)
  }
  return authResult
}

async function authenticateWithEmail(userId: string, email: string) {
  const startRes = await client.fallback.email.start({ userId, email })
  if (!startRes.ok) return startRes
  const code = prompt('Enter the code sent by email:')
  return await client.fallback.email.verify({ userId, code })
}