Skip to main content

Use hosted authentication in native apps

Hosted authentication opens Clerk's Account Portal in a browser authentication session. Your users can complete any sign-in or sign-up method enabled for your Clerk application, and the Clerk SDK activates the resulting session in your native app.

The browser doesn't retain a separate active session after Clerk transfers the session to your app.

When to use hosted authentication

Hosted authentication is the fastest way to add sign-in and sign-up to a native app. The browser session opens over your app, so users stay in your app for the whole flow. Choose it when you want Clerk to host and maintain the authentication UI and you don't need that UI built from native components.

For authentication that renders with native components instead of a browser session, use Clerk's Expo native componentsExpo Icon or iOS and Android views. To control every step of the UI and authentication flow, build a custom flow.

Before you start

  1. In the Clerk Dashboard, navigate to the Native applications page, enable the Native API, and add your app. Production instances validate the callback against the registered bundle identifier or package name, so add your app before you create a production build.
  2. Install and configure the Clerk SDK for ExpoExpo Icon, iOSiOS Icon, or AndroidAndroid Icon.

Important

Account Portal runs in a browser, so social sign-in uses each provider's web OAuth flow rather than the native one. On production instances, Sign in with Apple needs an Apple Services ID and key set up through the Apple social connection.

Install the Expo packages that useHostedAuth() uses to open the browser session and create the native callback:

terminal
npx expo install expo-auth-session expo-crypto expo-web-browser

Import useHostedAuth() from @clerk/expo/hosted-auth. The following example opens Account Portal when a user selects Sign in:

import { useHostedAuth } from '@clerk/expo/hosted-auth'
import { Button } from 'react-native'

export function SignInButton() {
  const { startHostedAuth } = useHostedAuth()

  const handleSignIn = async () => {
    try {
      await startHostedAuth()
    } catch (error) {
      // Handle the error in your app.
    }
  }

  return <Button title="Sign in" onPress={handleSignIn} />
}

The default callback uses the bundle identifier or package name from your Expo configuration. In Expo Go, Expo supplies a development callback instead. Keep the @clerk/expo config plugin in your app configuration and rebuild the native project after you change either identifier.

Call startHostedAuth() from an asynchronous task. The following example opens Account Portal when a user selects Sign in:

import ClerkKit
import SwiftUI

struct SignInButton: View {
  @Environment(Clerk.self) private var clerk

  var body: some View {
    Button("Sign in") {
      Task {
        do {
          try await clerk.auth.startHostedAuth()
        } catch {
          // Handle the error in your app.
        }
      }
    }
  }
}

The iOS SDK uses <bundle-identifier>://callback as the default callback.

Call startHostedAuth() from a coroutine. The following example opens Account Portal when a user selects Sign in:

import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import com.clerk.api.Clerk
import kotlinx.coroutines.launch

@Composable
fun SignInButton() {
    val scope = rememberCoroutineScope()

    Button(
        onClick = {
            scope.launch {
                Clerk.auth.startHostedAuth()
            }
        },
    ) {
        Text("Sign in")
    }
}

The Android SDK registers the default clerk://<package-name>.callback callback for your app.

After authentication completes, the SDK closes the browser session, activates the new session, and updates its authentication state.

Open the sign-up page first

Account Portal opens the sign-in page by default. Pass the sign-up mode to open the sign-up page instead:

await startHostedAuth({ mode: 'sign-up' })
try await clerk.auth.startHostedAuth(mode: .signUp)
import com.clerk.api.auth.HostedAuthMode

Clerk.auth.startHostedAuth(mode = HostedAuthMode.SIGN_UP)

Users can still switch between sign-in and sign-up from Account Portal regardless of the initial page.

Handle cancellation and errors

Users can dismiss the browser authentication session before they finish. Each SDK reports cancellation differently:

startHostedAuth() resolves with a null session ID when the user dismisses the browser. Authentication errors throw.

try {
  const { createdSessionId, authSessionResult } = await startHostedAuth()

  if (!createdSessionId) {
    // The user dismissed the browser.
    // authSessionResult?.type is 'cancel' or 'dismiss'.
  }
} catch (error) {
  // Authentication failed.
}

startHostedAuth() throws when the user dismisses the browser or authentication fails:

do {
  try await clerk.auth.startHostedAuth()
} catch {
  // The user dismissed the browser, or authentication failed.
}

startHostedAuth() returns a failure when the user dismisses the browser or authentication fails:

import com.clerk.api.network.serialization.ClerkResult

when (val result = Clerk.auth.startHostedAuth()) {
    is ClerkResult.Success -> {
        // The session is active.
    }
    is ClerkResult.Failure -> {
        // The user dismissed the browser, or authentication failed.
    }
}

For details about platform-specific options and errors, see the useHostedAuth() referenceExpo Icon for Expo or the native authentication reference for iOS and Android.

Troubleshooting

The browser doesn't close after authentication

Check that the bundle identifier or package name in your app matches the entry on the Clerk Dashboard's Native applications page.

For Expo apps on Android, also confirm that @clerk/expo is present in the plugins array in app.json. Rebuild the native project after you add the plugin or change the Android package name.

Signing in with a social provider fails

The provider's screen appears and accepts the user, then sign-in stops without an error.

The provider is missing its credentials. Production instances require you to supply your own for each social provider. Check the provider's custom credentials on the Clerk Dashboard's SSO connections page. For Apple, that's an Apple Services ID and key, set up through the Apple social connection.

Feedback

What did you think of this content?

Last updated on