Authsignal’s Mobile SDKs let you rapidly implement passkeys in your mobile apps using fully native iOS and Android UI.
Passkeys on iOSPasskeys on Android

Native passkey UI on iOS and Android

Configure passkeys in the Authsignal Portal

  1. Navigate to the Authenticators section of the Portal and click Set up Passkey.
  2. Set your Relying Party ID. The value should correspond to the web domain associated with your mobile app. For more information refer to our Mobile SDK documentation.
    Add relying party ID
  3. If targeting Android you should also click Add Android app origin and enter your app’s SHA-256 fingerprint value. For more information on how to obtain this value refer to our Mobile SDK documentation.

    Setting an expected origin value for your Android app's SHA-256 fingerprint

Setup SDKs

Passkeys require integration from your backend server and your mobile app.
  1. Get your tenant’s credentials from the API keys page.
  2. Follow the setup instructions for one of our Server SDKs - or integrate via REST with our Server API.
  3. Follow the setup instructions for our Mobile SDKs for Swift, Kotlin, React Native, or Flutter.

Creating passkeys

In Authsignal, you define an action to let users create passkeys. This does two things:
  1. It provides observability for all passkey creation events in the Authsignal Portal.
  2. It ensures that the passkey is securely bound to an existing user.

1. Backend - Generate token

In your backend, track an action using a Server SDK to generate a short-lived enrollment token.
const request = {
  userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
  action: "createPasskey",
  attributes: {
    scope: "add:authenticators",
  },
};

const response = await authsignal.track(request);

const token = response.token;
This token includes the add:authenticators scope to authorize binding a passkey to an existing user so you should only generate it when the user is strongly authenticated.

2. App - Create passkey

In your app, call the signUp method using one of our Mobile SDKs, passing the token generated in step 1.
let response = await authsignal.passkey.signUp(
    token: "eyJhbGciOiJIUzI....",
    username: "jane@authsignal.com",
    displayName: "Jane Smith"
)
You can also use our SDK to help determine when to display a passkey creation prompt based on whether or not the user has an existing passkey available on their device.
let showPrompt = await authsignal.passkey.shouldPromptToCreatePasskey()

if showPrompt {
    let response = await authsignal.passkey.signUp(
        token: "eyJhbGciOiJIUzI....",
        username: "jane@authsignal.com",
        ignorePasskeyAlreadyExistsError: true,
    )
}
To learn more about how to conditionally create passkeys refer to the section below on passkey availability.

Authenticating with passkeys

You can define another action to let users authenticate with their passkeys. This action will be used for observability and to authenticate the user on the server.

1. App - Sign in with passkey

In your app, call the signIn method using one of our Mobile SDKs.
let response = await authsignal.passkey.signIn(action: "signInWithPasskey")

if let token = response.data?.token {
    // Send token to your backend for validation
}
Because some users may not have a passkey available, you can conditionally present a fallback authentication method by handling error codes returned by the SDK.
let response = await authsignal.passkey.signIn(action: "signInWithPasskey")

if response.errorCode == "user_canceled" {
  // Present fallback authentication method
}
To learn more about how to handle if passkeys are available when authenticating refer to the section below on passkey availability.

2. Backend - Validate action

Pass the token returned in the previous step to your backend, validating the result of the authentication server-side.
const response = await authsignal.validateChallenge({
  action: "signInWithPasskey",
  token: "eyJhbGciOiJIUzI....",
});

if (response.state === "CHALLENGE_SUCCEEDED") {
  // User successfully authenticated with passkey
  const userId = response.userId;
} else {
  // Authentication failed
}
This server-side validation step can be used within one of our popular IdP integrations or with our session APIs to issue access tokens and refresh tokens.

Passkey availability

Due to security restrictions in the design of passkeys, iOS and Android don’t expose an API to query if a passkey is available on a device. This means we need to handle the UX around passkey availability carefully both when creating and authenticating with passkeys.

Creating passkeys

Prompting users to create a passkey proactively is a great way of increasing adoption.

An example of prompting users to create a passkey from the Uber app

The Mobile SDKs include a helper method to determine whether prompting the user to create a passkey is recommended.
let showPrompt = await authsignal.passkey.shouldPromptToCreatePasskey()
This method will return true if the following conditions are met:
  • A passkey has not been created on the current device.
  • A passkey has not been used on the current device after it was created on another device.
  • A passkey has been removed in the Authsignal Portal after it was created or used on the current device.
The method will also return true as a “false positive” in the following edge case:
  • A passkey is available which was created on another device and has not yet been used on the current device.
This case can be handled by ignoring any errors thrown because a valid passkey already exists.
let response = await authsignal.passkey.signUp(
    token: "eyJhbGciOiJIUzI....",
    username: "jane@authsignal.com",
    ignorePasskeyAlreadyExistsError: true,
)

if !response.error {
    // Alert the user that the passkey was successfully created
}

Authenticating with passkeys

Since we can’t query up front whether a passkey is available or not, the recommended pattern is to attempt passkey sign-in for all users and then provide a fallback option by handling error codes.
let response = await authsignal.passkey.signIn(action: "signInWithPasskey")

if response.errorCode == "user_canceled" {
  // Present fallback authentication method
}
iOS imposes an additional privacy restriction which prevents apps from determining if the user canceled the passkey flow or if they didn’t have a passkey available. For this reason we recommend presenting an alternative authentication method in both cases. To learn more about handling error codes refer to the Mobile SDK documentation.

Passkey support

Passkeys are supported on iOS devices running iOS 15 or higher and on Android devices running Android 9 (API level 28) or higher. You can use the SDK to perform this check.
let isSupported = await authsignal.passkey.isSupported()

Next steps