Skip to content

Twilio Verify Passkeys SDK helps you verify users by adding a low-friction, secure, "Passkeys" factor into your own apps. This project provides a Kotlin multiplatform SDK to implement Verify Passkey to your Android, iOS and Kotlin Multiplatform apps.

License

Notifications You must be signed in to change notification settings

twilio/twilio-verify-passkeys

Repository files navigation

Twilio Verify Passkeys Android & iOS SDKs (KMP)

Table of Contents

About

Twilio Passkeys SDK enables developers to easily add Passkeys into their existing authentication flows within their own mobile applications. The Verify Passkeys SDK supports passkeys creation and authentication using the FIDO/WebAuthn industry standard.

Documentation

Verify Passkeys Overview

Requirements

  • Android Studio for Android development. Minimum version Hedgehog
  • Xcode for iOS development. 15.x
  • IntelliJ IDEA or Android Studio for shared code development.
  • Android 9 (API Level 28) or higher
  • iOS 16 or higher
  • Gradle 8.2
  • Java 17

Installation

Installation Android

  1. Download the .aar file from the release page.
  2. Create a folder libs in the module directory.
  3. Copy/move the .aar file in libs folder.
  4. Add the implementation statement in dependencies:
implementation(files("libs/TwilioPasskeys.aar"))
  1. Sync the project.
  2. Use the SDK by creating an instance of TwilioPasskey:
val twilioPasskey = TwilioPasskey(context)

Installation iOS

  1. Download the XCFramework form the release page.
  2. Create a Framework folder or use any name of your preference.
  3. Copy/Move the XCFramework into the folder created at the previous step.
  4. On your Project Configurations > General > Frameworks, Libraries, and Embedded Content section, drag & drop the XCFramework.
  5. Import TwilioPasskeys in the files you will make use of it:
let twilioPasskey = TwilioPasskey()

Quickstart

Create registration

Use the TwilioPasskey instance to create a registration by calling the create(String, AppContext) function.

The first param is a String representation of a create passkey request, check how to create passkey payload (createPayload).

The second param is an instance of a com.twilio.passkeys.AppContext, it is created by passing the current Activity instance in Android or the UIWindow instance in iOS.

You can also call the create(CreatePasskeyRequest, AppContext) function, where CreatePasskeyRequest is a wrapper object of a create passkey payload schema.

Android

val createPasskeyResult = twilioPasskey.create(createPayload, AppContext(activity))
when(createPasskeyResult) {
  is CreatePasskeyResult.Success -> {
    // verify the createPasskeyResult.createPasskeyResponse against your backend and finish sign up
  }
  
  is  CreatePasskeyResult.Error -> {
    // handle error
  }
}

iOS

let response = try await twilioPasskey.create(createPayload: createPayload, appContext: AppContext(uiWindow: window))
if let success = response as? CreatePasskeyResult.Success {
  // verify the createPasskeyResult.createPasskeyResponse against your backend and finish sign up
} else if let error = response as? CreatePasskeyResult.Error {
  // handle error
}

Authenticate a user

Use the TwilioPasskey instance to authenticate a user by calling the authenticate(String, AppContext) function.

The first param is a String representation of an authentication request, it follows the schema of an authenticate passkey payload (authenticatePayload).

The second param is an instance of a com.twilio.passkeys.AppContext, it is created by passing the current Activity instance in Android or the UIWindow instance in iOS.

You can also call the authenticate(AuthenticatePasskeyRequest, AppContext) function, which the AuthenticatePasskeyRequest is a wrapper object of an authenticate passkey payload.

Android

val authenticatePasskeyResult = twilioPasskey.authenticate(authenticatePayload, AppContext(activity))
when(authenticatePasskeyResult) {
  is AuthenticatePasskeyResult.Success -> {
    // verify the authenticatePasskeyResult.authenticatePasskeyResponse against your backend
  }
  
  is AuthenticatePasskeyResult.Error -> {
    // handle error 
  }
}

iOS

let response = try await twilioPasskey.authenticate(challengePayload: json, appContext: AppContext(uiWindow: window))
if let success = response as? AuthenticatePasskeyResult.Success {
  // verify the authenticatePasskeyResult.authenticatePasskeyResponse against your backend and finish sign in.
} else if let error = response as? AuthenticatePasskeyResult.Error {
  // handle error
}

Create Passkey Payload

The creation payload for creating a passkey is a String obtained by requesting your backend a challenge for registering a user, it uses the JSON schema:

{"rp":{"id":"your_backend","name":"PasskeySample"},"user":{"id":"WUV...5Ng","name":"1234567890","displayName":"1234567890"},"challenge":"WUY...jZQ","pubKeyCredParams":[{"type":"public-key","alg":-7}],"timeout":600000,"excludeCredentials":[],"authenticatorSelection":{"authenticatorAttachment":"platform","requireResidentKey":false,"residentKey":"preferred","userVerification":"preferred"},"attestation":"none"}

Authenticate Passkey Payload

The authenticate payload for authenticating a user is a JSON with the schema:

{"publicKey":{"challenge":"WUM...2Mw","timeout":300000,"rpId":"your_backend","allowCredentials":[],"userVerification":"preferred"}}

Building and Running Sample App

Android

  1. Clone this repository.
  2. Open the project in IntelliJ IDEA or Android Studio.
  3. Set your backend URL BaseUrl.
  4. Build and run the Android app from the androidApp module.

Note: To start sign up/in flows, the Android device must have a valid Google account to store and fetch passkeys.

Backend-side configuration for Android Sample App

  1. Make sure you already added support for digital asset links in your backend by checking whether an entry with the build sha256 value exists. You can generate a sha256 by running ./gradlew signingreport.
  2. Add the origin if you have not added it yet, following the official documentation.

iOS

  1. Clone this repository.
  2. Open the project in IntelliJ IDEA or Android Studio or open iosApp module in Xcode.
  3. Configure your backend
    • Set your backend domain and entitlements. Update these values in Constants.swift and iosApp.entitlements
      let domain: String = "passkeys-service.com" // Example domain; replace with your backend domain
      <string>webcredentials:passkeys-service.com</string> <!-- Example entitlement; update with your domain -->
  4. Build and run the iOS app from the iosApp module.

Note: To start sign up/in flows, the iPhone must have a valid iCloud account to store and fetch passkeys.

Project Structure

  • shared: This module contains the shared code, including business logic, data models, and utility functions.
  • androidApp: This module is specific to the Android platform and includes the Android sample app code.
  • iosApp: This module is specific to the iOS platform and includes the iOS sample app code.

Code Structure

Shared Code

The shared module contains code shared between Android and iOS. This includes:

  • Data models
  • Business logic
  • Utility functions

Android App

The androidApp module contains Android-specific code, such as:

  • Sample application that works as a code snippet for integrating with the Twilio Verify Passkeys SDK
  • Android-specific UI components

iOS App

The iosApp module contains iOS-specific code, such as:

  • Sample application that works as a code snippet for integrating with the Twilio Verify Passkeys SDK
  • iOS-specific UI components

Exception Types

The TwilioException class offers structured error handling for various scenarios specific to Twilio's passkeys features. Each error type is represented by a subclass with a unique error code, enabling precise exception management. Below are the defined exception types:

Exception Overview

Exception Code Description Platform-Specific Details
DomException 1001 Handles errors related to WebAuthn DOM configurations for passkeys. Android: Ensure /.well-known/assetlinks.json is set up. See Android Guide.
iOS: Ensure /.well-known/apple-app-site-association is set up. See Apple Guide.
UserCanceledException 1002 Thrown when the user voluntarily cancels an operation, allowing graceful termination of user actions. N/A
InterruptedException 1003 Thrown when an operation is interrupted, typically recoverable by retrying. Android Only
UnsupportedException 1004 Indicates the device does not support or has disabled the passkeys feature, preventing passkey operations. N/A
NoCredentialException 1005 Thrown when no passkey credentials are available, indicating no user credentials are set up for authentication. Android Only
MissingAttestationObjectException 1006 Raised when the attestation object is null, which is essential for passkey operations. iOS Only
InvalidPayloadException 1007 Thrown when the JSON payload is invalid, meaning the data does not meet the expected format or schema. N/A
GeneralException 1008 Represents a general or unspecified error used as a fallback for errors not fitting other categories. N/A

Useful Gradle Tasks

Running Unit Tests

Shared iOS Unit Tests

./gradlew :shared:iosSimulatorArm64Test

Shared Android Unit Tests

./gradlew :shared:testDebugUnitTest

To run tests with coverage report

./gradlew :shared:koverHtmlReportDebug

Code coverage rule only working on Android

./gradlew :shared:koverVerify

Code rules

Ktlint Check

Check Ktlint rule violations

./gradlew ktlintCheck

Ktlint Format

Try to solve Ktlint rule violations

./gradlew ktlintFormat

Detekt Check

Check Detekt rule violations

./gradlew detekt

About

Twilio Verify Passkeys SDK helps you verify users by adding a low-friction, secure, "Passkeys" factor into your own apps. This project provides a Kotlin multiplatform SDK to implement Verify Passkey to your Android, iOS and Kotlin Multiplatform apps.

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published