This document describes the internal structure of the react-native-passkey-autofill module and how it works.
The project follows the standard layout for an Expo module:
src/: TypeScript source files for the module's JavaScript API.android/: Native Android implementation using Kotlin.ios/: Native iOS implementation using Swift.example/: An example app demonstrating the use of the module.
The module provides an interface to interact with native Passkey AutoFill capabilities. It uses Expo's native module system to bridge the JavaScript code with the platform-specific implementations.
index.ts: The entry point for the module, re-exporting the native module.ReactNativePasskeyAutofillModule.ts: Defines theReactNativePasskeyAutofillModuleclass and its methods (setMasterKey,setHdRootKeyId,getHdRootKeyId, etc.).ReactNativePasskeyAutofill.types.ts: Defines types and interfaces used by the module.
The Android part is implemented using Kotlin and follows the Android Autofill Framework.
ReactNativePasskeyAutofillModule.kt: The main class that exposes methods to React Native.service/PasskeyAutofillCredentialProviderService.kt: Implements theCredentialProviderServiceto handle Passkey AutoFill requests from the Android system.credentials/: Contains logic for managing credentials and interacting with the local storage.GetPasskeyActivity.ktandCreatePasskeyActivity.kt: Activities used to handle the UI flow for getting and creating passkeys.
The PasskeyAutofillCredentialProviderService is the core of the Android implementation. It extends the Android Jetpack CredentialProviderService to provide passkeys directly to the system's Credential Manager.
Introduced in Android 14 (API level 34) and backported to Android 9 via the Jetpack Credentials library, this service allows password managers and other credential providers to integrate with the system's unified sign-in flow. When a user interacts with a sign-in or sign-up field, the system queries registered services to provide available credentials.
The "Chain of Trust" ensures that passkeys are only used by the legitimate owners of a domain or application. This is handled through several layers of validation:
- Digital Asset Links: For a passkey to be used across a website and an Android app, the website must host a
/.well-known/assetlinks.jsonfile that explicitly authorizes the Android app (via its package name and certificate fingerprint). This establishes a cryptographically verified link between the web origin and the mobile application. - Relying Party ID (rpId) Validation: When the service receives a
BeginGetCredentialRequestorBeginCreateCredentialRequest, it includes information about therpId(e.g.,example.com). The system and the provider must ensure that the requesting app is authorized to use credentials for thatrpId. - App Signature Verification: The Android system verifies the signature of the app requesting the credential. It will only offer credentials to apps that can prove their identity through the Digital Asset Link chain.
- User Consent: The
CredentialProviderServicedoes not directly return the credential. Instead, it returns a list of "Entries" (likePublicKeyCredentialEntry). When a user selects an entry, aPendingIntentis triggered, which typically launches an activity (likeGetPasskeyActivity) to perform user verification (e.g., biometric check) before the actual passkey is released to the requesting app.
The iOS part is implemented using Swift.
ReactNativePasskeyAutofillModule.swift: Defines the native module for iOS.ReactNativePasskeyAutofillView.swift: If any native views are required.
The following methods are exposed to the JavaScript layer:
setMasterKey(secret: string): Sets the master key for credential encryption/decryption.setHdRootKeyId(id: string): Sets the ID for the HD root key.getHdRootKeyId(): Retrieves the current HD root key ID.configureIntentActions(getPasskeyAction: string, createPasskeyAction: string): Configures the intent actions used for Passkey flows.clearCredentials(): Clears all stored credentials.
As this module handles sensitive information (Passkeys), it is crucial to ensure that keys and secrets are handled securely in the native layers. Master keys should be stored in secure storage (like Android Keystore or iOS Keychain).