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

# Use Biometrics as a PIN

> Learn how to implement biometric authentication as a PIN alternative in your Expo app

## Overview

Biometric authentication provides a secure and convenient way for users to authenticate without remembering PINs or passwords. The Chipi SDK supports fingerprint and face recognition on compatible devices.

## Prerequisites

* Expo SDK 55 or later
* Chipi SDK installed and configured
* Device with biometric capabilities (fingerprint sensor or face recognition)

## Installation

First, install the required dependencies:

```bash theme={null}
npx expo install expo-local-authentication
```

## Basic Implementation

This is the minimal configuration required to enroll in and use biometrics instead of a PIN to sign transactions.

<Steps>
  <Step title="Register biometrics along with the PIN">
    ```typescript theme={null}
    await SecureStore.setItemAsync("wallet_pin", pin, {
     requireAuthentication: true,     
    });
    ```
  </Step>

  <Step title="Read the PIN to trigger the biometric prompt">
    ```typescript theme={null}
        import { useTransfer } from "@chipi-stack/chipi-expo";
        import { ChainToken } from "@chipi-stack/chipi-expo";
        
        const storedWallet = await SecureStore.getItemAsync("wallet");
        const pin = await SecureStore.getItemAsync("wallet_pin",{
          requireAuthentication: true,
        });

        const token = await getToken();
        if (!token) {
          setError("No bearer token found");
          return;
        }

        const transferResponse = await transferAsync({
          params: {
            encryptKey: pin,
            wallet: JSON.parse(storedWallet),
            token: ChainToken.USDC,
            recipient: recipientAddress,
            amount: Number(amount),
          },
          bearerToken: token,
        });
    ```
  </Step>
</Steps>

## Example

Here's a simple example of how to implement a secure transfer flow using biometric authentication:

<Tabs>
  <Tab title="Create Wallet Component">
    To use biometrics for authentication, you first need to create and securely store a wallet with a PIN (which can be protected by biometrics).
    Here’s an example wallet creation screen using the [`useCreateWallet`](/sdk/expo/hooks/use-create-wallet) hook:

    ```typescript theme={null}
    // Create Wallet Screen with biometric authentication

    import { useCreateWallet, Chain } from '@chipi-stack/chipi-expo';
    import { useAuth, useUser } from '@clerk/clerk-expo';
    import * as SecureStore from 'expo-secure-store';
    import { useState } from 'react';
    import { StyleSheet, Text, View, Alert, Linking } from 'react-native';
    import { PrimaryButton } from '@/components/ui/PrimaryButton';
    import { SimpleInput } from '@/components/ui/SimpleInput';

    export const CreateWalletView = () => {
      const { getToken } = useAuth();
      const { user } = useUser();
      const [pin, setPin] = useState<string>('');
      const [error, setError] = useState('');
      const { createWalletAsync, isLoading } = useCreateWallet();
      const [walletData, setWalletData] = useState<any>(null);

      const handleCreateWallet = async () => {
        try {
          setError('');
          const token = await getToken();
          if (!token) {
            setError('No bearer token found');
            return;
          }

          const result = await createWalletAsync({
            params: {
              encryptKey: pin,
              externalUserId: user?.id || '',
              chain: Chain.STARKNET,
            },
            bearerToken: token,
          });

          // `createWalletAsync` returns a flat GetWalletResponse. Wallet fields
          // (publicKey, normalizedPublicKey, etc.) live at the top level of
          // `result` — see types/src/wallet.ts: `CreateWalletResponse = GetWalletResponse`.
          await SecureStore.setItemAsync('wallet', JSON.stringify(result));
          await SecureStore.setItemAsync('wallet_pin', pin, {
            requireAuthentication: true,
          });

          setWalletData(result);
          Alert.alert('Success', 'Wallet successfully created!');
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : String(error);
          setError('Error creating wallet: ' + errorMessage);
        }
      };

      const openStarkscan = (address: string) => {
        const url = `https://starkscan.co/contract/${address}`;
        Linking.openURL(url);
      };

      return (
        <View style={styles.container}>
          <Text style={styles.title}>Create New Wallet</Text>
          <Text style={styles.subtitle}>Set a PIN to secure your wallet</Text>

          <SimpleInput
            placeholder="Enter your PIN (min 4 digits)"
            value={pin}
            onChangeText={setPin}
            keyboardType="numeric"
            maxLength={6}
          />

          {error ? <Text style={styles.errorText}>{error}</Text> : null}

          <PrimaryButton
            title={isLoading ? 'Creating...' : 'Create Wallet'}
            active={pin.length >= 4 && !isLoading}
            onPress={handleCreateWallet}
          />

          {walletData && (
            <View style={styles.walletDetails}>
              <View style={styles.detailHeader}>
                <Text style={styles.detailTitle}>Wallet Details</Text>
                <Text
                  style={styles.viewContract}
                  onPress={() => openStarkscan(walletData.publicKey)}>
                  View Contract →
                </Text>
              </View>

              <View style={styles.detailItem}>
                <Text style={styles.detailLabel}>Address:</Text>
                <Text style={styles.detailValue} numberOfLines={2}>
                  {walletData.publicKey}
                </Text>
              </View>
            </View>
          )}
        </View>
      );
    };

    const styles = StyleSheet.create({
      container: {
        flex: 1,
        padding: 20,
        backgroundColor: '#fff',
      },
      title: {
        fontSize: 28,
        fontWeight: 'bold',
        marginBottom: 8,
        color: '#11181C',
      },
      subtitle: {
        fontSize: 16,
        color: '#687076',
        marginBottom: 24,
      },
      errorText: {
        color: '#ff6b6b',
        fontSize: 14,
        marginTop: 8,
      },
      walletDetails: {
        marginTop: 32,
        padding: 16,
        backgroundColor: '#f5f5f5',
        borderRadius: 8,
      },
      detailHeader: {
        flexDirection: 'row',
        justifyContent: 'space-between',
        alignItems: 'center',
        marginBottom: 16,
      },
      detailTitle: {
        fontSize: 18,
        fontWeight: '600',
        color: '#11181C',
      },
      viewContract: {
        fontSize: 14,
        color: '#0a7ea4',
        fontWeight: '600',
      },
      detailItem: {
        marginBottom: 12,
      },
      detailLabel: {
        fontSize: 14,
        fontWeight: '600',
        color: '#687076',
        marginBottom: 4,
      },
      detailValue: {
        fontSize: 14,
        color: '#11181C',
        fontFamily: 'monospace',
      },
    });
    ```
  </Tab>

  <Tab title="Send Token with Biometric">
    Use the [useTransfer](/sdk/expo/hooks/use-transfer) hook to send money to another wallet. Setting **requireAuthentication: true** will prompt for your biometric instead of your PIN.

    ```typescript theme={null}
    // Transfer example with biometric authentication

    import { useState } from 'react';
    import { View, TextInput, TouchableOpacity, StyleSheet, Alert, Text } from 'react-native';
    import { useTransfer } from '@chipi-stack/chipi-expo';
    import { ChainToken } from '@chipi-stack/chipi-expo';
    import { useAuth } from '@clerk/clerk-expo';
    import { getPinStorage, getWalletStorage } from '@/utils/secureStorage';
    import { ThemedText } from './themed-text';

    export function TransferExample() {
      const { getToken } = useAuth();
      const { transferAsync, isLoading, error } = useTransfer();
      const [recipientAddress, setRecipientAddress] = useState('');
      const [amount, setAmount] = useState('');

      const handleTransfer = async () => {
        try {
          if (!recipientAddress || !amount) {
            Alert.alert('Error', 'Please enter recipient address and amount');
            return;
          }

          // Get stored wallet and PIN (triggers biometric prompt)
          const storedWallet = await getWalletStorage();
          const pin = await getPinStorage();

          if (!storedWallet || !pin) {
            Alert.alert('Error', 'Wallet or PIN not found. Please create a wallet first.');
            return;
          }

          // Get JWT token from Clerk
          const token = await getToken();
          if (!token) {
            Alert.alert('Error', 'No bearer token found');
            return;
          }

          // Execute transfer with updated API
          const transferResponse = await transferAsync({
            params: {
              encryptKey: pin,
              wallet: JSON.parse(storedWallet),
              token: ChainToken.USDC,
              recipient: recipientAddress,
              amount: Number(amount),
            },
            bearerToken: token,
          });

          Alert.alert('Success', `Transfer completed! TX: ${transferResponse || 'Pending'}`);
          setRecipientAddress('');
          setAmount('');
        } catch (err) {
          const errorMessage = err instanceof Error ? err.message : String(err);
          Alert.alert('Transfer Error', errorMessage);
        }
      };

      return (
        <View style={styles.container}>
          <View style={styles.inputContainer}>
            <Text style={styles.label}>Recipient Address</Text>
            <TextInput
              style={styles.input}
              value={recipientAddress}
              onChangeText={setRecipientAddress}
              placeholder="0x..."
            />
          </View>

          <View style={styles.inputContainer}>
            <Text style={styles.label}>Amount (USDC)</Text>
            <TextInput
              style={styles.input}
              value={amount}
              onChangeText={setAmount}
              placeholder="0.00"
              keyboardType="decimal-pad"
            />
          </View>

          <TouchableOpacity
            style={[styles.button, isLoading && styles.buttonDisabled]}
            onPress={handleTransfer}
            disabled={isLoading || !recipientAddress || !amount}>
            <Text style={styles.buttonText}>
              {isLoading ? 'Sending...' : 'Send USDC'}
            </Text>
          </TouchableOpacity>

          {error && (
            <ThemedText style={styles.errorText}>
              Error: {error instanceof Error ? error.message : String(error)}
            </ThemedText>
          )}
        </View>
      );
    }

    const styles = StyleSheet.create({
      container: {
        gap: 16,
        marginTop: 12,
      },
      inputContainer: {
        gap: 8,
      },
      label: {
        fontSize: 14,
        fontWeight: '600',
      },
      input: {
        borderWidth: 1,
        borderColor: '#ccc',
        borderRadius: 8,
        padding: 12,
        fontSize: 16,
      },
      button: {
        backgroundColor: '#007AFF',
        borderRadius: 8,
        padding: 16,
        alignItems: 'center',
        marginTop: 8,
      },
      buttonDisabled: {
        opacity: 0.5,
      },
      buttonText: {
        color: '#fff',
        fontSize: 16,
        fontWeight: '600',
      },
      errorText: {
        color: '#ff6b6b',
        fontSize: 14,
        marginTop: 8,
      },
    });
    ```

    **Note:** This example assumes you have utility functions `getPinStorage()` and `getWalletStorage()` in your `@/utils/secureStorage` file. These functions should use `SecureStore.getItemAsync()` with `requireAuthentication: true` for the PIN to trigger biometric prompts.
  </Tab>
</Tabs>

## Useful resources

* Making an EAS Build in [Expo](https://docs.expo.dev/build/introduction/)

## Next Steps

Now that you have biometric authentication working, you can:

* Integrate it with other Chipi SDK features
* Add biometric authentication to wallet operations
* Implement multi-factor authentication combining biometrics and PINs
* Add biometric authentication to transaction signing

For more information, check out the [Expo Local Authentication documentation](https://docs.expo.dev/versions/latest/sdk/local-authentication/).
