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

# Social Login

> Authenticate users with OAuth providers like Google, Apple, and Discord in React Native and Expo

export const Link = ({href, label, newTab = false}) => {
  const [isHovered, setIsHovered] = useState(false);
  return <a href={href} target={newTab ? '_blank' : '_self'} rel={newTab ? 'noopener noreferrer' : undefined} className="not-prose inline-block relative text-black font-semibold cursor-pointer border-b-0 no-underline" onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
      {label}
      <span className={`absolute left-0 bottom-0 w-full rounded-sm bg-gradient-to-r from-orange-600 to-purple-600 transition-all duration-300 ${isHovered ? 'h-0.5' : 'h-px'}`} />
    </a>;
};

Para supports OAuth authentication with providers like Google, Apple, Discord, X, and Facebook. Use `authenticateWithOAuth()` to handle the entire OAuth flow in a single call -- it manages the redirect, polls for completion, and creates wallets for new users.

<Info>
  Have your own OpenID Connect provider? Once you [set up Custom OIDC](/v3/general/developer-portal-custom-oidc), pass `"CUSTOM_OIDC"` as the method here — it works like any other provider.
</Info>

## Prerequisites

Before implementing OAuth authentication, ensure you have completed the basic Para setup for your React Native or Expo application.

<CardGroup cols={2}>
  <Card horizontal title="React Native Setup" imgUrl="/images/v3/framework-react-native.png" href="/v3/react-native/setup/react-native" description="Complete the basic Para setup for React Native before implementing OAuth" />

  <Card horizontal title="Expo Setup" imgUrl="/images/v3/framework-expo.png" href="/v3/react-native/setup/expo" description="Complete the basic Para setup for Expo before implementing OAuth" />
</CardGroup>

## Standard OAuth

Use `para.authenticateWithOAuth()` to authenticate a user via a third-party OAuth provider. The method manages the OAuth redirect, polls for completion, waits for session establishment, and creates wallets for new signups.

For standard OAuth providers, use the `onOAuthUrl` callback to open the OAuth URL in an in-app browser.

<Tabs>
  <Tab title="React Native">
    ### Installation

    Install the In-App Browser package to handle OAuth redirects:

    ```bash theme={null}
    npm install react-native-inappbrowser-reborn
    # or
    yarn add react-native-inappbrowser-reborn
    ```

    For iOS, add the following to your `Info.plist` to define your URL scheme:

    ```xml theme={null}
    <key>CFBundleURLTypes</key>
    <array>
      <dict>
        <key>CFBundleURLSchemes</key>
        <array>
          <string>your-app-scheme</string>
        </array>
      </dict>
    </array>
    ```

    For Android, add your URL scheme to `AndroidManifest.xml`:

    ```xml theme={null}
    <activity
        android:name=".MainActivity"
        android:launchMode="singleTask">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="your-app-scheme" />
        </intent-filter>
    </activity>
    ```

    ### Implementation

    ```typescript theme={null}
    import { para } from "../your-para-client";
    import { OAuthMethod } from "@getpara/react-native-wallet";
    import { InAppBrowser } from "react-native-inappbrowser-reborn";

    const APP_SCHEME = "your-app-scheme";

    async function handleOAuthLogin(provider: OAuthMethod) {
      try {
        const result = await para.authenticateWithOAuth({
          method: provider,
          appScheme: APP_SCHEME,
          redirectCallbacks: {
            onOAuthUrl: async (url) => {
              await InAppBrowser.openAuth(url, APP_SCHEME, {
                ephemeralWebSession: false,
                showTitle: false,
                enableUrlBarHiding: true,
              });
            },
          },
        });

        if (result.hasCreatedWallets && result.recoverySecret) {
          console.log("Recovery secret:", result.recoverySecret);
        }

        console.log("Auth info:", result.authInfo);
        // Navigate to your authenticated screen
      } catch (error) {
        console.error("OAuth failed:", error);
      }
    }
    ```
  </Tab>

  <Tab title="Expo">
    ### Installation

    Install the Expo Web Browser package:

    ```bash theme={null}
    npx expo install expo-web-browser
    ```

    Configure your `app.json` with the URL scheme:

    ```json theme={null}
    {
      "expo": {
        "scheme": "your-app-scheme",
        "ios": {
          "bundleIdentifier": "com.yourcompany.yourappname"
        },
        "android": {
          "package": "com.yourcompany.yourappname"
        }
      }
    }
    ```

    After updating your `app.json`, rebuild native files:

    ```bash theme={null}
    npx expo prebuild --clean
    ```

    ### Implementation

    ```typescript theme={null}
    import { para } from "../your-para-client";
    import { OAuthMethod } from "@getpara/react-native-wallet";
    import { openAuthSessionAsync } from "expo-web-browser";

    const APP_SCHEME = "your-app-scheme";

    async function handleOAuthLogin(provider: OAuthMethod) {
      try {
        const result = await para.authenticateWithOAuth({
          method: provider,
          appScheme: APP_SCHEME,
          redirectCallbacks: {
            onOAuthUrl: async (url) => {
              await openAuthSessionAsync(url, APP_SCHEME, {
                preferEphemeralSession: false,
              });
            },
          },
        });

        if (result.hasCreatedWallets && result.recoverySecret) {
          console.log("Recovery secret:", result.recoverySecret);
        }

        console.log("Auth info:", result.authInfo);
        // Navigate to your authenticated screen
      } catch (error) {
        console.error("OAuth failed:", error);
      }
    }
    ```
  </Tab>
</Tabs>

<Tip>
  Both `react-native-inappbrowser-reborn` and `expo-web-browser` use secure browser implementations that leverage the device's native browser engine rather than a WebView. This provides stronger security protections and support for modern authentication methods.
</Tip>

## Telegram & Farcaster

Telegram and Farcaster authentication require a different approach than standard OAuth. These providers authenticate through Para's hosted portal, which needs to send events back to the SDK when authentication completes. On mobile, this requires opening the portal in a **WebView** (not an in-app browser) so the portal can communicate via `window.ReactNativeWebView.postMessage()`.

You must forward messages from the WebView to the SDK using `para.handleWebViewMessage()`.

<Warning>
  Telegram and Farcaster **cannot** use `InAppBrowser` or `expo-web-browser` because the portal needs a live message channel to send authentication events (`TELEGRAM_SUCCESS`, `FARCASTER_SUCCESS`) back to the SDK. Only a WebView provides this channel via `onMessage`.
</Warning>

```tsx theme={null}
import { useState } from "react";
import { Modal } from "react-native";
import { WebView, type WebViewMessageEvent } from "react-native-webview";
import { para } from "../your-para-client";
import type { OAuthMethod } from "@getpara/react-native-wallet";

const APP_SCHEME = "your-app-scheme";

function TelegramOrFarcasterAuth() {
  const [portalUrl, setPortalUrl] = useState<string | null>(null);

  const handleAuth = async (method: OAuthMethod) => {
    try {
      const result = await para.authenticateWithOAuth({
        method,
        appScheme: APP_SCHEME,
        redirectCallbacks: {
          onOAuthUrl: (url) => {
            // Show the portal URL in a WebView instead of an in-app browser
            setPortalUrl(url);
          },
        },
      });

      setPortalUrl(null);

      if (result.hasCreatedWallets && result.recoverySecret) {
        console.log("Recovery secret:", result.recoverySecret);
      }

      console.log("Auth info:", result.authInfo);
      // Navigate to your authenticated screen
    } catch (error) {
      setPortalUrl(null);
      console.error("Auth failed:", error);
    }
  };

  const handleWebViewMessage = (event: WebViewMessageEvent) => {
    try {
      const data = JSON.parse(event.nativeEvent.data);
      // Forward portal events (TELEGRAM_SUCCESS, FARCASTER_SUCCESS, etc.) to the SDK
      para.handleWebViewMessage(data);
    } catch {
      // Ignore non-JSON messages
    }
  };

  return (
    <>
      {/* Your auth buttons */}
      <Button title="Continue with Telegram" onPress={() => handleAuth("TELEGRAM")} />
      <Button title="Continue with Farcaster" onPress={() => handleAuth("FARCASTER")} />

      {/* WebView modal for portal interaction */}
      <Modal visible={!!portalUrl} animationType="slide">
        <WebView
          source={{ uri: portalUrl! }}
          onMessage={handleWebViewMessage}
          javaScriptEnabled
        />
      </Modal>
    </>
  );
}
```

<Note>
  Install `react-native-webview` if you haven't already:

  ```bash theme={null}
  npm install react-native-webview
  # or for Expo:
  npx expo install react-native-webview
  ```
</Note>

## Method Reference

<MethodDocs
  defaultExpanded={true}
  preventCollapse={true}
  name="authenticateWithOAuth()"
  description="Handles the entire OAuth authentication flow in a single call — OAuth redirect/popup, verification, session waiting, and wallet creation. Supports Google, Apple, Discord, X, Facebook, Telegram, and Farcaster."
  async={true}
  parameters={[
{
  name: "method",
  type: "TOAuthMethod",
  required: true,
  description: "The third-party OAuth service to use (e.g. `'GOOGLE'`, `'APPLE'`, `'DISCORD'`, `'X'`, `'FACEBOOK'`, `'TELEGRAM'`, `'FARCASTER'`)."
},
{
  name: "appScheme",
  type: "string",
  optional: true,
  description: "The app scheme to redirect to after OAuth is complete. Required for mobile (React Native) flows."
},
{
  name: "redirectCallbacks",
  type: "OAuthRedirectCallbacks",
  optional: true,
  description: "Callbacks for OAuth popup/redirect handling. Includes `onOAuthPopup` (receives the popup `Window`) and `onOAuthUrl` (receives the OAuth URL string). If `onOAuthUrl` is provided, `onOAuthPopup` will not be called."
},
{
  name: "sessionPollingCallbacks",
  type: "PollingCallbacks",
  optional: true,
  description: "Callbacks fired while polling for session status. Includes `onPoll`, `onCancel`, and `isCanceled`."
},
{
  name: "oAuthPollingCallbacks",
  type: "PollingCallbacks",
  optional: true,
  description: "Callbacks fired while polling for OAuth completion status. Includes `onPoll`, `onCancel`, and `isCanceled`."
},
{
  name: "portalTheme",
  type: "Theme",
  optional: true,
  description: "The theme to apply to generated URLs, if different from your configured theme."
},
{
  name: "useShortUrls",
  type: "boolean",
  optional: true,
  description: "Whether to shorten generated URLs. This may correct any issues with generated QR codes."
}
]}
  returns={{
type: "AuthenticateResponse",
description: "An object containing `authInfo` (user's authentication info), `hasCreatedWallets` (whether wallets were auto-created), and optionally `recoverySecret` (for new signups)."
}}
/>

<Note>
  This method must be paired with `para.onStatePhaseChange()` to handle portal URLs that appear after OAuth completes (e.g. passkey or password setup for returning users). See the guide for your platform for the full state listener pattern.
</Note>

## Cancelling Authentication

Both OAuth polling and session polling accept an `isCanceled` callback. Return `true` from `isCanceled` to stop the polling loop -- for example, when the user dismisses the in-app browser or navigates away. The cancellation is clean: no error is thrown, and the optional `onCancel` callback fires.

```typescript theme={null}
const result = await para.authenticateWithOAuth({
  method: "GOOGLE",
  appScheme: APP_SCHEME,
  oAuthPollingCallbacks: {
    isCanceled: () => userClickedCancel,
    onCancel: () => console.log("OAuth polling canceled"),
  },
  sessionPollingCallbacks: {
    isCanceled: () => userClickedCancel,
    onCancel: () => console.log("Session polling canceled"),
  },
});
```

Calling `para.logout()` also cancels all active polling and resets the state phases back to `unauthenticated`. This is useful for implementing a "Cancel" button that fully resets the auth flow:

```typescript theme={null}
const handleCancel = async () => {
  await para.logout();
  // All polling stops, state phases reset to unauthenticated
};
```

## Handling Results

`authenticateWithOAuth()` returns the same `AuthenticateResponse` as email/phone auth. See the [authentication guide](/v3/react-native/guides/add-email-phone) for full response type documentation.

## Next Steps

<CardGroup cols={3}>
  <Card title="Add Passkeys" imgUrl="/images/v3/general-passwords.png" href="/v3/react-native/guides/add-passkeys" description="Add native biometric authentication." />

  <Card title="Add Password or PIN" imgUrl="/images/v3/general-passwords.png" href="/v3/react-native/guides/add-password-pin" description="Add password or PIN security." />

  <Card title="EVM Integration" imgUrl="/images/v3/network-evm.png" href="/v3/react-native/guides/evm" description="Start signing transactions." />
</CardGroup>
