# Authentication Methods

Openfort React supports multiple authentication methods. Pick the one that fits your UX and security requirements.

:::info
For an overview of all authentication methods and response types, see [Authentication methods](/docs/products/embedded-wallet/authentication).
:::

* Prefer the prebuilt UI? Configure providers and flows in the dashboard, then follow the setup guide at [Openfort UI Configuration](/docs/products/embedded-wallet/react/ui/configuration).
* Building a custom flow? The hooks below cover every scenario, and [`useAuthCallback`](/docs/products/embedded-wallet/react/hooks/useAuthCallback) simplifies OAuth and email verification callbacks.

:::info
Authentication is chain-agnostic. All auth hooks below work the same whether your OpenfortProvider is configured for Ethereum or Solana. The only exception is `useConnectWithSiwe`, which is Ethereum-only.
:::

## Using Email Authentication

Use [`useEmailAuth`](/docs/products/embedded-wallet/react/hooks/useEmailAuth) for traditional email/password authentication. It covers sign up, login, password reset, and email linking.

```tsx
import { useEmailAuth } from "@openfort/react"

function EmailLogin() {
  const { signInEmail, signUpEmail, isLoading } = useEmailAuth()

  const handleSignIn = async () => {
    const result = await signInEmail({
      email: "user@example.com",
      password: "password123",
    })

    if (result.requiresEmailVerification) {
      // Prompt the user to check their inbox for a verification code
    }
  }

  return (
    <button onClick={handleSignIn} disabled={isLoading}>
      Sign in
    </button>
  )
}
```

[View full documentation →](/docs/products/embedded-wallet/react/hooks/useEmailAuth)

## Using Email OTP Authentication

Use [`useEmailOtpAuth`](/docs/products/embedded-wallet/react/hooks/useEmailOtpAuth) for passwordless email authentication with one-time passwords.

```tsx
import { useEmailOtpAuth } from "@openfort/react"
import { useState } from "react"

function EmailOtpLogin() {
  const { requestEmailOtp, signInEmailOtp, isRequesting, isLoading } = useEmailOtpAuth()
  const [email, setEmail] = useState("")
  const [otp, setOtp] = useState("")
  const [otpSent, setOtpSent] = useState(false)

  const handleRequestOtp = async () => {
    const { error } = await requestEmailOtp({ email })
    if (!error) setOtpSent(true)
  }

  const handleSignIn = async () => {
    const { user, error } = await signInEmailOtp({ email, otp })
    if (user) console.log("Signed in:", user.id)
  }

  return (
    <div>
      <input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" />
      {otpSent && (
        <input value={otp} onChange={(e) => setOtp(e.target.value)} placeholder="Enter OTP" />
      )}
      {!otpSent ? (
        <button onClick={handleRequestOtp} disabled={isRequesting}>
          Send OTP
        </button>
      ) : (
        <button onClick={handleSignIn} disabled={isLoading}>
          Sign In
        </button>
      )}
    </div>
  )
}
```

[View full documentation →](/docs/products/embedded-wallet/react/hooks/useEmailOtpAuth)

## Using Phone OTP Authentication

Use [`usePhoneOtpAuth`](/docs/products/embedded-wallet/react/hooks/usePhoneOtpAuth) for passwordless SMS authentication with one-time passwords.

```tsx
import { usePhoneOtpAuth } from "@openfort/react"
import { useState } from "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}>
          Send OTP
        </button>
      ) : (
        <button onClick={handleSignIn} disabled={isLoading}>
          Sign In
        </button>
      )}
    </div>
  )
}
```

[View full documentation →](/docs/products/embedded-wallet/react/hooks/usePhoneOtpAuth)

## Using Social Authentication

Use [`useOAuth`](/docs/products/embedded-wallet/react/hooks/useOAuth) for social login (Google, Facebook, Twitter, etc.) and account linking.

`useOAuth` only authenticates. The wallet appears reactively on [`useEthereumEmbeddedWallet`](/docs/products/embedded-wallet/react/hooks/useEthereumEmbeddedWallet) or [`useSolanaEmbeddedWallet`](/docs/products/embedded-wallet/react/hooks/useSolanaEmbeddedWallet) once `isConnected` flips true. Both hooks expose the same connection-state shape (`isConnected`, `isConnecting`, `isDisconnected`, `isReconnecting`). Recovery is automatic via the `recoverWalletAutomatically` option (default `true`) and uses the `walletConfig.chainType` set on `OpenfortProvider` — set it to `ChainTypeEnum.SVM` for Solana, otherwise EVM is used.

:::code-group

```tsx [Prebuilt]
import { useUI } from "@openfort/react"

function SocialLogin() {
  const { open } = useUI()
  return <button onClick={open}>Sign in</button>
}
```

```tsx [Ethereum (custom)]
import { OAuthProvider, useOAuth } from "@openfort/react"
import { useEthereumEmbeddedWallet } from "@openfort/react/ethereum"

function SocialLogin() {
  const { initOAuth, isLoading } = useOAuth()
  const { isConnected, address } = useEthereumEmbeddedWallet()

  if (isConnected) return <p>Wallet: {address}</p>

  return (
    <button
      onClick={() => initOAuth({ provider: OAuthProvider.GOOGLE })}
      disabled={isLoading}
    >
      Sign in with Google
    </button>
  )
}
```

```tsx [Solana (custom)]
import { OAuthProvider, useOAuth } from "@openfort/react"
import { useSolanaEmbeddedWallet } from "@openfort/react/solana"

function SocialLogin() {
  const { initOAuth, isLoading } = useOAuth()
  const { isConnected, address } = useSolanaEmbeddedWallet()

  if (isConnected) return <p>Wallet: {address}</p>

  return (
    <button
      onClick={() => initOAuth({ provider: OAuthProvider.GOOGLE })}
      disabled={isLoading}
    >
      Sign in with Google
    </button>
  )
}
```

:::

:::warning
One `chainType` per provider. An app cannot headlessly OAuth into both EVM and Solana from the same `OpenfortProvider` instance.
:::

Working examples:

* [Headless EVM quickstart](https://github.com/openfort-xyz/openfort-react/tree/main/examples/quickstarts/headless) – minimal headless EVM setup
* [Headless Solana quickstart](https://github.com/openfort-xyz/openfort-react/tree/main/examples/quickstarts/solana-headless) – minimal headless Solana setup with `chainType: SVM`

[View full documentation →](/docs/products/embedded-wallet/react/hooks/useOAuth)

## Using Wallet Authentication (Ethereum only)

Wallet authentication (Sign-In with Ethereum, SIWE) with external wallets (MetaMask, WalletConnect, etc.) is **Ethereum-only** and requires wagmi provider setup. Full setup, provider config, and API are in [useWalletAuth](/docs/products/embedded-wallet/react/hooks/useWalletAuth).

:::code-group

```tsx [Prebuilt]
import { useUI } from "@openfort/react"

function WalletLogin() {
  const { open } = useUI()
  return <button onClick={open}>Sign in with Ethereum wallet</button>
}
```

```tsx [Custom]
import { useWalletAuth } from "@openfort/react/wagmi"
import { useState } from "react"

function WalletLogin() {
  const { availableWallets, connectWallet } = useWalletAuth()
  const [loading, setLoading] = useState(false)

  const handleConnect = async (walletId: string) => {
    setLoading(true)
    try {
      await connectWallet(walletId, {
        onConnect: () => console.log("Connected"),
        onError: (err) => console.error(err),
      })
    } finally {
      setLoading(false)
    }
  }

  return (
    <>
      {availableWallets.map((w) => (
        <button key={w.id} onClick={() => handleConnect(w.id)} disabled={loading}>
          {w.name}
        </button>
      ))}
    </>
  )
}
```

:::

[View full documentation →](/docs/products/embedded-wallet/react/hooks/useWalletAuth#usewalletauth-siwe-connection-flow)

## Using Guest Authentication

Use [`useGuestAuth`](/docs/products/embedded-wallet/react/hooks/useGuestAuth) for anonymous users and instant onboarding.

```tsx
import { useGuestAuth } from "@openfort/react"

function GuestLogin() {
  const { signUpGuest, isLoading } = useGuestAuth()

  return (
    <button onClick={() => signUpGuest()} disabled={isLoading}>
      Continue as guest
    </button>
  )
}
```

[View full documentation →](/docs/products/embedded-wallet/react/hooks/useGuestAuth)

## Using Your Own Authentication

Openfort integrates with external authentication providers like Firebase, Supabase, Auth0, and custom auth systems so you can keep your existing login flow while issuing embedded wallets for users.

[View full documentation →](/docs/products/embedded-wallet/react/auth/third-party)
