# `usePhoneOtpAuth`

Authenticate users with phone OTP (SMS one-time password) for passwordless login.

## Usage

```tsx
import { usePhoneOtpAuth } from '@openfort/react';

function PhoneOtpLogin() {
  const { requestPhoneOtp, logInWithPhoneOtp, isRequesting, isLoading } = usePhoneOtpAuth();
  const [phoneNumber, setPhoneNumber] = useState('');
  const [otp, setOtp] = useState('');
  const [otpSent, setOtpSent] = useState(false);

  const handleRequestOtp = async () => {
    const { error } = await requestPhoneOtp({ phoneNumber });
    if (!error) setOtpSent(true);
  };

  const handleSignIn = async () => {
    const { user, error } = await logInWithPhoneOtp({ phoneNumber, otp });
    if (user) console.log('Signed in:', user.id);
  };

  return (
    <div>
      <input value={phoneNumber} onChange={(e) => setPhoneNumber(e.target.value)} placeholder="+1234567890" />
      {otpSent && (
        <input value={otp} onChange={(e) => setOtp(e.target.value)} placeholder="Enter OTP" />
      )}
      {!otpSent ? (
        <button onClick={handleRequestOtp} disabled={isRequesting}>
          {isRequesting ? 'Sending...' : 'Send OTP'}
        </button>
      ) : (
        <button onClick={handleSignIn} disabled={isLoading}>
          {isLoading ? 'Signing in...' : 'Sign In'}
        </button>
      )}
    </div>
  );
}
```

## Return type

```ts
type PhoneOtpAuthReturn = {
  requestPhoneOtp(options: RequestPhoneOtpOptions): Promise<PhoneAuthResult>
  logInWithPhoneOtp(options: LoginWithPhoneOtpOptions): Promise<PhoneAuthResult>
  linkPhoneOtp(options: LoginWithPhoneOtpOptions): Promise<PhoneAuthResult>  // Same type as logInWithPhoneOtp
  reset(): void
  isRequesting: boolean
  isLoading: boolean
  isError: boolean
  isSuccess: boolean
  isAwaitingInput: boolean
  error?: OpenfortError | null
}

type PhoneAuthResult = {
  user?: User
  wallet?: UserWallet
  error?: OpenfortError
}
```

## Hook options

Configure default behavior when initializing the hook.

```ts
type UsePhoneHookOptions = {
  // Log out the user if wallet recovery fails. Defaults to true.
  logoutOnError?: boolean
  // Automatically recover the wallet after authentication. Defaults to true.
  recoverWalletAutomatically?: boolean
  onSuccess?: (data: PhoneAuthResult) => void
  onError?: (error: OpenfortError) => void
  throwOnError?: boolean
}
```

## Parameters

### requestPhoneOtp

Request an OTP code to be sent to the user's phone via SMS.

```ts
type RequestPhoneOtpOptions = {
  phoneNumber: string
  // Inherited from CreateWalletPostAuthOptions
  logoutOnError?: boolean
  recoverWalletAutomatically?: boolean
  // Inherited from OpenfortHookOptions
  onSuccess?: (data: PhoneAuthResult) => void
  onError?: (error: OpenfortError) => void
  throwOnError?: boolean
}
```

### logInWithPhoneOtp

Sign in with the phone number and OTP code.

```ts
type LoginWithPhoneOtpOptions = {
  phoneNumber: string
  otp: string
  // Overrides the hook-level default.
  logoutOnError?: boolean
  // Overrides the hook-level default.
  recoverWalletAutomatically?: boolean
  onSuccess?: (data: PhoneAuthResult) => void
  onError?: (error: OpenfortError) => void
}
```

### linkPhoneOtp

Link a phone number to an existing authenticated user. The user must already be authenticated (for example, via email or OAuth) before linking a phone number.

`linkPhoneOtp` uses the same `LoginWithPhoneOtpOptions` type as `logInWithPhoneOtp`. Wallet recovery fields (`logoutOnError`, `recoverWalletAutomatically`) are present in the type but ignored by `linkPhoneOtp`.

Note: Unlike `logInWithPhoneOtp`, the `linkPhoneOtp` function does not create or recover a wallet—it only links the phone number to the existing user account.

#### Link phone example

```tsx
import { usePhoneOtpAuth, useUser } from '@openfort/react';

function LinkPhoneNumber() {
  const { user } = useUser();
  const { requestPhoneOtp, linkPhoneOtp, isRequesting, isLoading } = usePhoneOtpAuth();
  const [phoneNumber, setPhoneNumber] = useState('');
  const [otp, setOtp] = useState('');
  const [otpSent, setOtpSent] = useState(false);

  if (!user) return <p>Please sign in first</p>;

  const handleRequestOtp = async () => {
    const { error } = await requestPhoneOtp({ phoneNumber });
    if (!error) setOtpSent(true);
  };

  const handleLinkPhone = async () => {
    const { user, error } = await linkPhoneOtp({ phoneNumber, otp });
    if (user) console.log('Phone linked successfully');
  };

  return (
    <div>
      <input value={phoneNumber} onChange={(e) => setPhoneNumber(e.target.value)} placeholder="+1234567890" />
      {otpSent && (
        <input value={otp} onChange={(e) => setOtp(e.target.value)} placeholder="Enter OTP" />
      )}
      {!otpSent ? (
        <button onClick={handleRequestOtp} disabled={isRequesting}>
          {isRequesting ? 'Sending...' : 'Send OTP'}
        </button>
      ) : (
        <button onClick={handleLinkPhone} disabled={isLoading}>
          {isLoading ? 'Linking...' : 'Link Phone'}
        </button>
      )}
    </div>
  );
}
```

## Related

* [useEmailOtpAuth](/docs/products/embedded-wallet/react/hooks/useEmailOtpAuth) - Email OTP authentication
* [useEmailAuth](/docs/products/embedded-wallet/react/hooks/useEmailAuth) - Email/password authentication
