> ## Documentation Index
> Fetch the complete documentation index at: https://docs.authsignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Passkeys best practice for native mobile apps

> Design seamless passkey flows for iOS and Android native applications

The following recommendations are designed to help you create the best passkey experience for your users when using Authsignal's [mobile SDKs](/sdks/client/mobile/setup).

## Ensuring a backup option exists when passkeys are unavailable

Even if users have previously created a passkey, they may be authenticating on a new device where the passkey cannot be synced - for example, when switching between an iOS and an Android device or vice versa.

Additionally, it is possible a user may have deleted their existing passkey credential from Apple iCloud or Google Password Manager.

One way to ensure a user always has a backup option available is to prompt the user to create a passkey only after they enroll another authentication method such as [email OTP](/sdks/client/mobile/email-otp) or [SMS OTP](/sdks/client/mobile/sms).

Since Authsignal supports binding multiple authentication factors together, this can easily be achieved with the mobile SDK.

<Frame caption="Creating a passkey after completing an email OTP challenge">
  <video controls className="w-full aspect-video" src="https://mintcdn.com/authsignal-23/o0kRW78VfDNgNDjk/images/docs/passkeys/mobile-create-account.mp4?fit=max&auto=format&n=o0kRW78VfDNgNDjk&q=85&s=11bca80886e9c1c6cae57974a3cf0fa0" data-path="images/docs/passkeys/mobile-create-account.mp4" />
</Frame>

## Optimizing sign-in UX

Now that we can be confident the user always has a backup option, we can design an optimal sign-in UX which puts passkeys front and center while also providing a safe fallback.

For the happy path when a passkey is available, presenting a "Sign in" button which immediately displays the passkey prompt provides a smooth UX.

<Frame caption="Signing in with an available passkey">
  <video controls className="w-full aspect-video" src="https://mintcdn.com/authsignal-23/o0kRW78VfDNgNDjk/images/docs/passkeys/mobile-sign-in.mp4?fit=max&auto=format&n=o0kRW78VfDNgNDjk&q=85&s=8fa476133f97564b5a88372d3be06ffc" data-path="images/docs/passkeys/mobile-sign-in.mp4" />
</Frame>

If no passkey is available on the device, however, we can gracefully fall back to presenting email as a backup option.
This can be implemented by handling error codes returned by the mobile SDK.

<CodeGroup>
  ```swift iOS theme={null}
  let response = await authsignal.passkey.signIn(action: "signInWithPasskey")

  if response.errorCode == "user_canceled" {
    // Present email sign-in screen
  }
  ```

  ```kotlin Android theme={null}
  val response = await authsignal.passkey.signIn(action = "signInWithPasskey")

  if (response.errorCode == "user_canceled" || response.errorCode == "no_credential") {
    // Present email sign-in screen
  }
  ```

  ```ts React Native theme={null}
  const response = await authsignal.passkey.signIn({ action: "signInWithPasskey" });

  if (
    response.errorCode === ErrorCode.user_canceled ||
    response.errorCode === ErrorCode.no_credential
  ) {
    // Present email sign-in screen
  }
  ```

  ```dart Flutter theme={null}
  final response = await authsignal.passkey.signIn(action: "signInWithPasskey");

  if (response.errorCode == ErrorCode.userCanceled.value ||
      response.errorCode == ErrorCode.noCredential.value) {
    // Present email sign-in screen
  }
  ```
</CodeGroup>

For a consistent experience between iOS and Android, here we treat the scenario where a user has no passkey available exactly the same as if they dismiss the passkey prompt.
This is required because while Android returns a different error in either case, iOS doesn't differentiate between these two scenarios and returns the same cancellation error in each case.

<Frame caption="Falling back to email OTP when a passkey is unavailable">
  <video controls className="w-full aspect-video" src="https://mintcdn.com/authsignal-23/o0kRW78VfDNgNDjk/images/docs/passkeys/mobile-sign-in-no-credential.mp4?fit=max&auto=format&n=o0kRW78VfDNgNDjk&q=85&s=27fc817fe90af40d9b21fa8b2a229a00" data-path="images/docs/passkeys/mobile-sign-in-no-credential.mp4" />
</Frame>

<Info>
  The above behavior is possible because iOS and Android both expose a
  [preferImmediatelyAvailableCredentials
  parameter](/sdks/client/mobile/passkeys#param-prefer-immediately-available-credentials) which will
  avoid showing the passkey prompt if no credentials are available on the current device. Set this
  value to false if you want to allow signing in via QR code with a passkey on another device.
</Info>
