React Native Passkey Integration

3.3.3 · active · verified Sun Apr 19

react-native-passkey provides native Passkey support for React Native applications targeting iOS 15.0+ and Android API 28+. It bridges WebAuthn API calls to the native platform credential managers, enabling secure, passwordless authentication. The package is currently at version 3.3.3 and maintains an active release cadence, with several minor and patch releases in the past year addressing fixes, updates, and new features like PRF extension support and improved error handling. A key differentiator is its direct native integration, abstracting away the platform-specific complexities of FIDO2 attestation and assertion, and offering support for advanced features like `largeBlob` and `authenticatorSelection` options. It ships with TypeScript types, facilitating safer development. The library works by taking FIDO2 attestation/assertion requests (typically from a backend) and handling the native UI and cryptographic operations, returning FIDO2 results for server verification.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to check for Passkey support and initiate the creation of a new Passkey. It simulates fetching a FIDO2 attestation request from a backend and then uses `Passkey.create()` to prompt the user, subsequently sending the result back for verification. Replace `EXAMPLE_BACKEND_URL` with your actual FIDO2 server endpoint.

import { Passkey } from 'react-native-passkey';
import React, { useState, useEffect } from 'react';
import { View, Text, Button, Alert, ActivityIndicator, StyleSheet } from 'react-native';

const EXAMPLE_BACKEND_URL = process.env.PASSKEY_SERVER_URL ?? 'https://your-passkey-server.com';

const PasskeyDemo = () => {
  const [isSupported, setIsSupported] = useState<boolean | null>(null);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    setIsSupported(Passkey.isSupported());
  }, []);

  const handleCreatePasskey = async () => {
    if (!isSupported) {
      Alert.alert('Not Supported', 'Passkeys are not supported on this device.');
      return;
    }
    setIsLoading(true);
    try {
      // This request would typically come from your backend
      // For demo, we'll simulate a simple registration request
      const registrationChallengeResponse = await fetch(`${EXAMPLE_BACKEND_URL}/register/challenge`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username: 'demoUser' + Date.now() })
      });
      const requestJson = await registrationChallengeResponse.json();

      console.log('FIDO2 attestation request:', JSON.stringify(requestJson, null, 2));
      const result = await Passkey.create(JSON.stringify(requestJson));
      
      // Send the result to your server for verification
      const verificationResponse = await fetch(`${EXAMPLE_BACKEND_URL}/register/verify`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(result)
      });
      const verificationResult = await verificationResponse.json();

      if (verificationResult.verified) {
        Alert.alert('Success', 'Passkey created and verified!');
      } else {
        Alert.alert('Error', 'Passkey creation failed verification.');
      }
    } catch (error: any) {
      console.error('Passkey creation error:', error);
      Alert.alert('Error', `Failed to create Passkey: ${error.message}`);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Passkey Demo</Text>
      {isSupported === null ? (
        <ActivityIndicator size="large" />
      ) : (
        <Text style={styles.status}>Passkey Supported: {isSupported ? 'Yes' : 'No'}</Text>
      )}
      <Button
        title="Create New Passkey"
        onPress={handleCreatePasskey}
        disabled={isLoading || !isSupported}
      />
      {isLoading && <ActivityIndicator size="small" style={styles.spinner} />}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  status: {
    fontSize: 18,
    marginBottom: 20,
  },
  spinner: {
    marginTop: 10
  }
});

export default PasskeyDemo;

view raw JSON →