> ## 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 Passkeys as a PIN

> Secure wallet authentication with biometric passkeys instead of PINs

## Overview

WebAuthn passkeys replace PINs with biometric authentication (Face ID, Touch ID, Windows Hello). No PINs to remember or store.

## Prerequisites

* Modern browser with WebAuthn support (Chrome, Safari, Firefox, Edge)
* Biometric hardware (fingerprint, face recognition)
* Chipi React SDK installed

## Installation

```bash theme={null}
npm install @chipi-stack/chipi-passkey
```

## Basic Implementation

<Steps>
  <Step title="Create wallet with passkey">
    <CodeGroup>
      ```typescript Import theme={null}
      import { usePasskeySetup } from "@chipi-stack/chipi-passkey/hooks";
      ```

      ```typescript Usage theme={null}
      <Snippet file="sdk/use-passkeys-create.mdx" />
      ```
    </CodeGroup>
  </Step>

  <Step title="Authenticate with passkey">
    <CodeGroup>
      ```typescript Import theme={null}
      import { usePasskeyAuth } from "@chipi-stack/chipi-passkey/hooks";
      ```

      ```typescript Usage theme={null}
      <Snippet file="sdk/use-passkeys-transfer.mdx" />
      ```
    </CodeGroup>
  </Step>

  <Step title="Migrate existing wallet (optional)">
    If users already have a PIN-based wallet, they can migrate to passkey:

    <CodeGroup>
      ```typescript Import theme={null}
      import { useMigrateWalletToPasskey } from "@chipi-stack/chipi-react";
      ```

      ```typescript Usage theme={null}
      <Snippet file="sdk/use-passkeys-migrate.mdx" />
      ```
    </CodeGroup>
  </Step>
</Steps>

## Example

<Tabs>
  <Tab title="Create Wallet">
    ```typescript theme={null}
    import { useCreateWallet, Chain } from '@chipi-stack/chipi-react';
    import { usePasskeySetup } from '@chipi-stack/chipi-passkey/hooks';
    import { useState } from 'react';

    export function CreateWalletWithPasskey() {
      const { createWalletAsync, isLoading, error } = useCreateWallet();
      const { setupPasskey } = usePasskeySetup();
      const [wallet, setWallet] = useState(null);

      const handleCreate = async () => {
        try {
          // Triggers biometric prompt
          const passkeyResult = await setupPasskey('user-123', 'User Name');
          const encryptKey = passkeyResult.encryptKey;

          const result = await createWalletAsync({
            params: {
              encryptKey,
              usePasskey: true,
              externalUserId: 'user-123',
            },
            bearerToken: 'your-jwt-token',
          });
          
          localStorage.setItem('wallet', JSON.stringify(result));
          setWallet(result);
        } catch (err) {
          console.error(err);
        }
      };

      return (
        <div>
          <button onClick={handleCreate} disabled={isLoading}>
            {isLoading ? 'Creating...' : 'Create Wallet with Passkey'}
          </button>
          {error && <p>Error: {error.message}</p>}
          {wallet && <p>Wallet created: {wallet.publicKey}</p>}
        </div>
      );
    }
    ```
  </Tab>

  <Tab title="Transfer with Passkey">
    ```typescript theme={null}
    import { useTransfer, ChainToken } from '@chipi-stack/chipi-react';
    import { usePasskeyAuth } from '@chipi-stack/chipi-passkey/hooks';
    import { useState } from 'react';

    export function TransferWithPasskey() {
      const { transferAsync, isLoading } = useTransfer();
      const { authenticate } = usePasskeyAuth();
      const [recipient, setRecipient] = useState('');
      const [amount, setAmount] = useState('');

      const handleTransfer = async () => {
        try {
          // Triggers biometric prompt — returns null if user cancels
          const encryptKey = await authenticate();
          if (!encryptKey) return;

          const wallet = JSON.parse(localStorage.getItem('wallet')!);
          
          const txHash = await transferAsync({
            params: {
              encryptKey,
              usePasskey: true,
              wallet,
              token: 'USDC',
              recipient,
              amount: Number(amount),
            },
            bearerToken: 'your-jwt-token',
          });
          
          alert(`Transfer complete: ${txHash}`);
        } catch (err) {
          console.error(err);
        }
      };

      return (
        <div>
          <input 
            placeholder="Recipient address" 
            value={recipient}
            onChange={(e) => setRecipient(e.target.value)}
          />
          <input 
            placeholder="Amount" 
            value={amount}
            onChange={(e) => setAmount(e.target.value)}
            type="number"
          />
          <button onClick={handleTransfer} disabled={isLoading}>
            {isLoading ? 'Sending...' : 'Send with Passkey'}
          </button>
        </div>
      );
    }
    ```
  </Tab>

  <Tab title="Migrate to Passkey">
    ```typescript theme={null}
    import { useMigrateWalletToPasskey } from '@chipi-stack/chipi-react';
    import { useState } from 'react';

    export function MigrateToPasskey() {
      const { migrateWalletToPasskeyAsync, isLoading } = useMigrateWalletToPasskey();
      const [currentPin, setCurrentPin] = useState('');

      const handleMigrate = async () => {
        try {
          const wallet = JSON.parse(localStorage.getItem('wallet')!);

          // The hook handles passkey creation internally —
          // just pass the old PIN and it re-encrypts with passkey
          await migrateWalletToPasskeyAsync({
            wallet,
            oldEncryptKey: currentPin,
            externalUserId: 'user-123',
            bearerToken: 'your-jwt-token',
          });
          
          alert('Successfully migrated to passkey!');
        } catch (err) {
          console.error(err);
        }
      };

      return (
        <div>
          <input
            type="password"
            placeholder="Current PIN"
            value={currentPin}
            onChange={(e) => setCurrentPin(e.target.value)}
          />
          <button onClick={handleMigrate} disabled={isLoading}>
            {isLoading ? 'Migrating...' : 'Migrate to Passkey'}
          </button>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

## Hooks Reference

| Hook                        | Purpose                            |
| --------------------------- | ---------------------------------- |
| `usePasskeySetup`           | Create new passkey                 |
| `usePasskeyAuth`            | Authenticate with existing passkey |
| `usePasskeyStatus`          | Check passkey support & status     |
| `useMigrateWalletToPasskey` | Migrate from PIN to passkey        |

## Browser Support

* ✅ Chrome 67+ (Desktop & Android)
* ✅ Safari 14+ (iOS 14+, macOS)
* ✅ Firefox 60+ (Desktop)
* ✅ Edge 18+ (Desktop)

<Note>
  Passkeys are stored in the browser and synced via platform (iCloud Keychain, Google Password Manager).
</Note>

## Security Benefits

* **No PINs stored** - Keys derived on-demand from biometric
* **Platform-level security** - Hardware-backed authentication
* **Phishing resistant** - Domain-bound credentials
* **User convenience** - One tap authentication

## Next Steps

* Check out [useCreateWallet](/sdk/react/hooks/use-create-wallet) for wallet creation options
* Learn about [useTransfer](/sdk/react/hooks/use-transfer) for token transfers
* Explore [session keys](/sdk/react/hooks/use-create-session-key) for additional security
