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

# OAuth

> Authenticate users with OAuth social logins including Google, Apple, Twitter, Discord, GitHub, and more

export const platform_2 = "Flutter"

export const providers_2 = "Google, Apple, Twitter, Discord, and Telegram"

export const platform_1 = "Android"

export const providers_1 = "Google, Discord, Twitter, and Telegram"

export const platform_0 = "Swift"

export const providers_0 = "Google, Apple, Twitter, Discord, and Telegram"

Privy natively supports OAuth login with Google, Apple, Twitter, Discord, GitHub, LinkedIn, Spotify, TikTok, Instagram, Telegram, and LINE. OAuth providers are **delegated** authentication, meaning a third party controls the authentication flow.

Enable your desired providers in the [Privy Dashboard](https://dashboard.privy.io/apps?page=login-methods\&logins=socials) before implementing.

For providers not listed here, use [Additional OAuth providers](/authentication/user-authentication/login-methods/custom-oauth) or [JWT-based authentication](/authentication/user-authentication/jwt-based-auth/overview).

<Warning>
  Account access is wallet access. If the delegated provider suspends or deletes an account, access
  to the wallet may be permanently lost. Account compromise at the delegated provider may also allow
  attackers to access the wallet. Privy recommends requiring MFA with either a **passkey** or
  **authenticator app** to protect against these risks. [Set up MFA
  →](/authentication/user-authentication/mfa/overview) | [Security checklist
  →](/security/implementation-guide/security-checklist)
</Warning>

## Implementation

<View title="React" icon="react">
  ## Initializing the login flow

  To authenticate users with Privy's built-in UIs, see [UI components](/authentication/user-authentication/ui-component). For whitelabel implementations, use `initOAuth` from the `useLoginWithOAuth` hook to trigger the OAuth login flow.

  ```jsx theme={"system"}
  initOAuth: ({ provider: OAuthProviderType, disableSignup?: boolean }) => Promise<void>
  ```

  <ParamField path="provider" type="OAuthProviderType" required>
    The OAuth provider to use for authentication. Valid values are: `'google'`, `'apple'`, `'twitter'`,
    `'github'`, `'discord'`, `'linkedin'`, `'spotify'`, `'tiktok'`, `'instagram'`, `'telegram'`, `'line'`.
  </ParamField>

  <ParamField path="disableSignup" type="boolean">
    If set to true, the OAuth flow will only allow users to log in with existing accounts and prevent new account creation.
  </ParamField>

  ### Usage

  ```jsx theme={"system"}
  import { useLoginWithOAuth } from '@privy-io/react-auth';

  export default function LoginWithOAuth() {
      const { state, initOAuth } = useLoginWithOAuth({
          onComplete: ({ user, isNewUser }) => {
              // user has been successfully authenticated
              if (isNewUser) {
                  // Perform actions for new users
              }
          },
          onError: (error) => {
              console.error('Login failed', error);
          }
      });

      return (
          <button
              onClick={() => initOAuth({ provider: 'google' })}
              disabled={state.status === 'loading'}
          >
              {state.status === 'loading' ? 'Logging in...' : 'Log in with Google'}
          </button>
      );
  }
  ```

  ## Flow state

  The `state` variable returned by `useLoginWithOAuth` tracks the OAuth flow:

  ```tsx theme={"system"}
  state:
  | {status: 'initial'}
  | {status: 'loading'}
  | {status: 'done'}
  | {status: 'error'; error: Error | null};
  ```

  ## Callbacks

  Pass optional callbacks to `useLoginWithOAuth`:

  ```tsx theme={"system"}
  onComplete: ({user, isNewUser, wasAlreadyAuthenticated, loginMethod, linkedAccount}) => void
  onError: (error: Error) => void
  ```

  <ParamField path="user" type="User">
    The user object returned after successful login.
  </ParamField>

  <ParamField path="isNewUser" type="boolean">
    Whether the user is a new user or an existing user.
  </ParamField>

  <ParamField path="wasAlreadyAuthenticated" type="boolean">
    Whether the user was already authenticated before the OAuth flow.
  </ParamField>

  <ParamField path="loginMethod" type="string">
    The login method used ('google', 'apple', etc.).
  </ParamField>

  <ParamField path="linkedAccount" type="LinkedAccount">
    The linked account if the user was already authenticated.
  </ParamField>

  ## Security and tokens

  <Warning>
    When verifying JWTs from OAuth providers, configure the `aud` (audience) claim to ensure tokens are intended for your application. See [access tokens](/authentication/user-authentication/tokens) for details.
  </Warning>

  Google OAuth may not work in in-app browsers due to [Google's restrictions in embedded webviews](https://developers.googleblog.com/upcoming-security-changes-to-googles-oauth-20-authorization-endpoint-in-embedded-webviews/).

  * Configure [allowed OAuth redirect URLs](/recipes/react/allowed-oauth-redirects) to restrict post-login redirects.
  * Access user OAuth and refresh tokens via the [useOAuthTokens](/recipes/react/oauth-tokens) hook when using your own OAuth credentials.

  ## Resources

  <Columns cols={3}>
    <Card title="React starter repo" href="https://github.com/privy-io/examples/tree/main/privy-react-starter" icon="github" arrow="true">
      Get started with React and Privy.
    </Card>

    <Card title="Next.js starter repo" href="https://github.com/privy-io/examples/tree/main/privy-next-starter" icon="github" arrow="true">
      Get started with Next.js and Privy.
    </Card>

    <Card title="Whitelabel starter repo" href="https://github.com/privy-io/examples/tree/main/privy-react-whitelabel-starter" icon="github" arrow="true">
      Get started with a whitelabel Privy integration.
    </Card>
  </Columns>
</View>

<View title="React Native" icon="react">
  To authenticate users with Privy's built-in UIs, see [UI components](/authentication/user-authentication/ui-component#react-native). For whitelabel implementations, use `login` from the `useLoginWithOAuth` hook. Privy also supports native [Apple login](/basics/react-native/advanced/setup-apple-login) on iOS.

  ### Configure allowed URL schemes

  Prior to integrating OAuth login, make sure you have [properly configured your app's allowed URL schemes in the Privy dashboard](/basics/get-started/dashboard/app-clients#allowed-url-schemes).

  <Warning>Login with OAuth might **not** work if you have not completed this step.</Warning>

  <Info>
    If your app uses native OAuth with Privy's REST API, include `scheme` in the authenticate request
    body. Set `scheme` to one of your app's allowed URL schemes configured in the dashboard.
  </Info>

  ```tsx theme={"system"}
  login: ({
    provider: OAuthProviderType,
    disableSignup?: boolean
  }) => Promise<PrivyUser>
  ```

  <ParamField path="provider" type="OAuthProviderType" required>
    The OAuth provider to use for authentication. Valid values are: `'google'`, `'apple'`, `'twitter'`,
    `'github'`, `'discord'`, `'linkedin'`, `'spotify'`, `'tiktok'`, `'instagram'`, `'telegram'`.
  </ParamField>

  <ParamField path="disableSignup" type="boolean">
    If true, the OAuth flow will only allow existing users to log in, preventing new account creation.
  </ParamField>

  ### Usage

  ```tsx theme={"system"}
  import { useLoginWithOAuth } from '@privy-io/expo';

  export function LoginScreen() {
    const { login, state } = useLoginWithOAuth();

    const onPress = async () => {
      try {
        const user = await login({ provider: 'google' });
        console.log('Login successful', user.id);
      } catch (error) {
        console.error('Login failed', error);
      }
    };

    return (
      <Button
        disabled={state.status === 'loading'}
        onPress={onPress}
        title={state.status === 'loading' ? 'Logging in...' : 'Login with Google'}
      />
    );
  }
  ```

  ## Flow state

  The `state` variable returned by `useLoginWithOAuth` tracks the OAuth flow:

  ```tsx theme={"system"}
  state:
    | {status: 'initial'}
    | {status: 'loading'}
    | {status: 'done'}
    | {status: 'error'; error: Error | null};
  ```

  Use `hasError(state)` to check for errors and render error messages conditionally.

  ## Resources

  <Columns cols={3}>
    <Card title="Expo starter repo" href="https://github.com/privy-io/examples/tree/main/privy-expo-starter" icon="github" arrow="true">
      Get started with Expo and Privy.
    </Card>

    <Card title="Expo bare starter repo" href="https://github.com/privy-io/examples/tree/main/privy-expo-bare-starter" icon="github" arrow="true">
      Get started with Expo bare and Privy.
    </Card>
  </Columns>
</View>

<View title="Swift" icon="swift">
  <Tip>
    The {platform_0} SDK supports OAuth login with {providers_0}. For all other OAuth providers, you can
    use [JWT-based authentication](/authentication/user-authentication/jwt-based-auth/overview).
  </Tip>

  ### Configure allowed URL schemes

  Prior to integrating OAuth login, make sure you have [properly configured your app's allowed URL schemes in the Privy dashboard](/basics/get-started/dashboard/app-clients#allowed-url-schemes).

  <Warning>Login with OAuth might **not** work if you have not completed this step.</Warning>

  <Info>
    If your app uses native OAuth with Privy's REST API, include `scheme` in the authenticate request
    body. Set `scheme` to one of your app's allowed URL schemes configured in the dashboard.
  </Info>

  Call `privy.oAuth.login` to launch the OAuth flow. Privy also supports native [Apple login](/recipes/swift/apple) on iOS.

  <ParamField path="provider" type="OAuthProvider" required>
    The OAuth provider to authenticate with. Supported values: `.google`, `.apple`, `.discord`, `.twitter`, `.telegram`.
  </ParamField>

  <ParamField path="appUrlScheme" type="String">
    Your app's URL scheme. If omitted, Privy uses the first valid scheme from your app's `info.plist`.
  </ParamField>

  ### Usage

  ```swift theme={"system"}
  do {
      let privyUser = try await privy.oAuth.login(with: OAuthProvider.google, appUrlScheme: "privyiosdemo")
  } catch {
      print("OAuth login error: \(error)")
  }
  ```

  ### Errors

  The `login` method throws if:

  * The app URL scheme is not provided or set in your `info.plist`
  * The app URL scheme is not registered in the Privy Dashboard
  * There was an issue generating the OAuth provider login URL
  * The user cancelled the login attempt
</View>

<View title="Android" icon="android">
  <Tip>
    The {platform_1} SDK supports OAuth login with {providers_1}. For all other OAuth providers, you can
    use [JWT-based authentication](/authentication/user-authentication/jwt-based-auth/overview).
  </Tip>

  ### Configure allowed URL schemes

  Prior to integrating OAuth login, make sure you have [properly configured your app's allowed URL schemes in the Privy dashboard](/basics/get-started/dashboard/app-clients#allowed-url-schemes).

  <Warning>Login with OAuth might **not** work if you have not completed this step.</Warning>

  <Info>
    If your app uses native OAuth with Privy's REST API, include `scheme` in the authenticate request
    body. Set `scheme` to one of your app's allowed URL schemes configured in the dashboard.
  </Info>

  ## Android Manifest

  Add the following activity to your `AndroidManifest.xml` to handle OAuth redirects. Replace `YOUR_CUSTOM_PRIVY_OAUTH_SCHEME` with your app's custom URL scheme (must be unique to this activity).

  ```xml theme={"system"}
  <activity
      android:name="io.privy.sdk.oAuth.PrivyRedirectActivity"
      android:exported="true"
      android:launchMode="singleTask">
      <intent-filter android:autoVerify="true">
          <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_CUSTOM_PRIVY_OAUTH_SCHEME" />
      </intent-filter>
  </activity>
  ```

  ## Login

  Call `privy.oAuth.login` to launch the OAuth flow.

  <ParamField path="provider" type="OAuthProvider" required>
    The OAuth provider to authenticate with. Supported values: `Google`, `Discord`, `Twitter`, `Telegram`.
  </ParamField>

  <ParamField path="appUrlScheme" type="String" required>
    Your app's URL scheme. Must match the scheme in your `AndroidManifest.xml`.
  </ParamField>

  ### Usage

  ```kotlin theme={"system"}
  viewModelScope.launch {
      val result = privy.oAuth.login(OAuthProvider.Google, "privytestapp://")
      result
          .onSuccess { user ->
              println("OAuth login successful: ${user.id}")
          }
          .onFailure { error ->
              println("OAuth login error: ${error.message}")
          }
  }
  ```

  ### Errors

  The `Result` contains a failure if:

  * The app URL scheme is not provided or not registered in the Privy Dashboard
  * The scheme doesn't match your `AndroidManifest.xml` configuration
  * There was an issue generating the provider login URL
  * The user cancelled the login attempt
</View>

<View title="Unity" icon="unity">
  ### Configure allowed URL schemes

  Prior to integrating OAuth login, make sure you have [properly configured your app's allowed URL schemes in the Privy dashboard](/basics/get-started/dashboard/app-clients#allowed-url-schemes).

  <Warning>Login with OAuth might **not** work if you have not completed this step.</Warning>

  <Info>
    If your app uses native OAuth with Privy's REST API, include `scheme` in the authenticate request
    body. Set `scheme` to one of your app's allowed URL schemes configured in the dashboard.
  </Info>

  The Unity SDK supports OAuth login with Google, Apple, Twitter, and Discord. Call `PrivyManager.Instance.OAuth.LoginWithProvider` to launch the flow.

  <ParamField path="provider" type="OAuthProvider" required>
    The OAuth provider to authenticate with.
  </ParamField>

  <ParamField path="redirectUri" type="String" required>
    For WebGL builds, the redirect URL. For native apps, the app's URL scheme.
  </ParamField>

  ### Usage

  ```csharp theme={"system"}
  try
  {
      await PrivyManager.Instance.OAuth.LoginWithProvider(OAuthProvider.Google, "myappscheme");
  }
  catch
  {
      Debug.Log("Error logging user in.");
  }
  ```

  The method throws if `redirectUri` is not provided or the authentication network call fails.
</View>

<View title="Flutter" icon="flutter">
  <Tip>
    The {platform_2} SDK supports OAuth login with {providers_2}. For all other OAuth providers, you can
    use [JWT-based authentication](/authentication/user-authentication/jwt-based-auth/overview).
  </Tip>

  ### Configure allowed URL schemes

  Prior to integrating OAuth login, make sure you have [properly configured your app's allowed URL schemes in the Privy dashboard](/basics/get-started/dashboard/app-clients#allowed-url-schemes).

  <Warning>Login with OAuth might **not** work if you have not completed this step.</Warning>

  <Info>
    If your app uses native OAuth with Privy's REST API, include `scheme` in the authenticate request
    body. Set `scheme` to one of your app's allowed URL schemes configured in the dashboard.
  </Info>

  If your app uses native OAuth with Privy's REST API, include `scheme` in the authenticate request body set to an allowed URL scheme from your app client configuration.

  ## Platform configuration

  Configure OAuth redirects on both Android and iOS. Replace `YOUR_CUSTOM_PRIVY_OAUTH_SCHEME` with your app's custom URL scheme (must be unique to this activity).

  ### Android

  Add to `android/app/src/main/AndroidManifest.xml`:

  ```xml theme={"system"}
  <activity
      android:name="io.privy.sdk.oAuth.PrivyRedirectActivity"
      android:exported="true"
      android:launchMode="singleTask"
      android:theme="@android:style/Theme.Translucent.NoTitleBar">
      <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_CUSTOM_PRIVY_OAUTH_SCHEME" />
      </intent-filter>
  </activity>
  ```

  ### iOS

  Add to `ios/Runner/Info.plist`. Privy also supports native [Apple login](/basics/get-started/dashboard/configure-login-methods#oauth-login-methods-google-twitter-etc:apple) on iOS 13.0+.

  ```xml theme={"system"}
  <key>CFBundleURLTypes</key>
  <array>
      <dict>
          <key>CFBundleURLName</key>
          <string>privy.oauth</string>
          <key>CFBundleURLSchemes</key>
          <array>
              <string>YOUR_CUSTOM_PRIVY_OAUTH_SCHEME</string>
          </array>
      </dict>
  </array>
  ```

  ## Login

  ```dart theme={"system"}
  Future<Result<PrivyUser>> login({
    required OAuthProvider provider,
    required String appUrlScheme,
  })
  ```

  <ParamField path="provider" type="OAuthProvider" required>
    Valid values: `OAuthProvider.google`, `OAuthProvider.apple` (iOS only), `OAuthProvider.twitter`,
    `OAuthProvider.discord`, `OAuthProvider.telegram`.
  </ParamField>

  <ParamField path="appUrlScheme" type="String" required>
    Your app's custom URL scheme for redirecting back after authentication.
  </ParamField>

  ### Usage

  ```dart theme={"system"}
  final result = await privy.oAuth.login(
    provider: OAuthProvider.google,
    appUrlScheme: 'your-app-scheme',
  );

  result.fold(
    onSuccess: (user) {
      print('Login successful: ${user.id}');
    },
    onFailure: (error) {
      print('Login failed: $error');
    },
  );
  ```

  ### Errors

  The `Result` contains a failure if:

  * The app URL scheme is not provided or not registered in the Privy Dashboard
  * The `scheme` field is missing from a native OAuth REST authenticate request (returns 401)
  * There was an issue generating the provider login URL
  * The user cancelled, or Apple Sign In was attempted on Android

  ## Resources

  <Columns cols={3}>
    <Card title="Flutter starter repo" href="https://github.com/privy-io/examples/tree/main/privy-flutter-starter" icon="github" arrow="true">
      Get started with Flutter and Privy.
    </Card>
  </Columns>
</View>

## Telegram Mini App seamless login

Privy supports zero-click authentication for users who open your app from within a Telegram Mini App. When a user opens your app via a Mini App link, Privy detects the Telegram context and authenticates them automatically — no `login()` call required.

### Setup

1. Configure Telegram OAuth credentials and enable **seamless authentication** in the [Privy Dashboard](https://dashboard.privy.io/apps?page=login-methods\&logins=socials) under Telegram settings.
2. Send your app URL to users via a bot message or Mini App link:

```jsx theme={"system"}
bot.send_message(chat_id, 'Log in to demo!', {
  reply_markup: {
    inline_keyboard: [
      [
        {
          text: 'Open app',
          web_app: {url: 'https://your-website-url'}
        }
      ]
    ]
  }
});
```

You can also use a direct Mini App link (e.g., `t.me/your_bot/your_app`).

For reference:

* [KeyboardButton](https://core.telegram.org/bots/api#keyboardbutton)
* [InlineKeyboardButton](https://core.telegram.org/bots/api#inlinekeyboardbutton)

### Client implementation

No additional client code is required. Privy automatically detects the Mini App context on load and authenticates the user. Your app can read the authenticated user as usual from the `usePrivy` hook once `ready` is `true`.

### Configure login methods (optional)

If `loginMethods` is configured in `PrivyProvider`, add `"telegram"`:

```jsx theme={"system"}
<PrivyProvider
  appId={process.env.NEXT_PUBLIC_PRIVY_APP_ID || ""}
  config={{
    loginMethods: ["email", "google", "telegram"],
  }}
>
```

### Seamless linking within a Mini App

To link a Telegram account to an already-authenticated user from within a Mini App, use `linkWithOAuth`:

```jsx theme={"system"}
import {usePrivy} from '@privy-io/react-auth';

const {linkWithOAuth} = usePrivy();
await linkWithOAuth({provider: 'telegram'});
```

<Tip>
  To use your app as a Telegram Mini App in the Telegram web client, add `http://web.telegram.org`
  and `https://web.telegram.org` to your allowed domains in the dashboard
  [Settings](https://dashboard.privy.io?page=settings) page.
</Tip>
