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

# MFA with Passkey (Hooks Only)

<Warning>
  Passkeys MFA is still in close beta. Please contact us to request access to enable this feature for your app.
</Warning>

## Introduction

This guide will show you how to add a passkey for MFA to your app using your own custom UI. You can also refer to the general MFA guide [here](/react-native/authentication-methods/mfa) to learn more about this feature (note that this guide is for account level MFA, rather than transaction level MFA).

## General Flow

### When user already has a passkey registered

1. User logs in
2. User is redirected to the MFA view
3. User adds a passkey
4. User is redirected to the recovery codes view
5. User acknowledges the recovery codes

<Info>
  The user must acknowledge the recovery codes before the MFA setup flow is complete.
</Info>

### When user does not have a passkey registered

1. User logs in
2. User is redirected to the MFA view
3. User selects existing passkey to authenticate

<Info>
  User does not need to acknowledge the recovery codes again in this flow.
</Info>

React Native provides passkey MFA support through the dynamic client's passkey methods.

```ts React Native theme={"system"}
import { dynamicClient } from '<path to client file>';
import { useState, useEffect } from 'react';

const MfaComponent = () => {
  const [passkeys, setPasskeys] = useState([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const loadPasskeys = async () => {
      try {
        setLoading(true);
        const userPasskeys = await dynamicClient.passkeys.get();
        setPasskeys(userPasskeys);
      } catch (error) {
        console.error('Failed to load passkeys:', error);
      } finally {
        setLoading(false);
      }
    };

    loadPasskeys();
  }, []);

  const handleRegisterPasskey = async () => {
    try {
      await dynamicClient.passkeys.register();
      // Refresh passkeys after registration
      const userPasskeys = await dynamicClient.passkeys.get();
      setPasskeys(userPasskeys);
    } catch (error) {
      console.error('Failed to register passkey:', error);
    }
  };

  const handleAuthenticateMFA = async () => {
    try {
      const verifyResponse = await dynamicClient.passkeys.authenticateMFA();
      console.log('MFA authentication successful:', verifyResponse);
    } catch (error) {
      console.error('MFA authentication failed:', error);
    }
  };

  const handleDeletePasskey = async (passkeyId: string) => {
    try {
      await dynamicClient.passkeys.delete({ passkeyId });
      // Refresh passkeys after deletion
      const userPasskeys = await dynamicClient.passkeys.get();
      setPasskeys(userPasskeys);
    } catch (error) {
      console.error('Failed to delete passkey:', error);
    }
  };

  if (loading) {
    return <Text>Loading passkeys...</Text>;
  }

  return (
    <View>
      <Text>Registered Passkeys: {passkeys.length}</Text>
      {passkeys.map((passkey) => (
        <View key={passkey.id}>
          <Text>Passkey ID: {passkey.id}</Text>
          <Button
            title="Delete"
            onPress={() => handleDeletePasskey(passkey.id)}
          />
        </View>
      ))}
      {passkeys.length > 0 ? (
        <Button
          title="Authenticate with passkey (MFA)"
          onPress={handleAuthenticateMFA}
        />
      ) : (
        <Text>No passkeys registered. Register a passkey first.</Text>
      )}
      <Button
        title="Register new passkey"
        onPress={handleRegisterPasskey}
      />
    </View>
  );
};
```

<Note>
  React Native requires platform setup for passkeys. See the setup guide: [/react-native/setup-passkey](/react-native/reference/setup-passkey)
</Note>
