Wocha Docs

React Native quickstart

Add Wocha sign-in to a React Native or Expo app using @wocha/react-native with OAuth PKCE and deep link callbacks.

Add Wocha sign-in to a React Native or Expo app using @wocha/react-native with OAuth PKCE and deep link callbacks.

Prerequisites

  • Node.js 18+
  • Expo SDK 49+ or React Native 0.71+
  • A Wocha project with a public OAuth application (Wocha Console)
  • Redirect URI registered: myapp://auth/callback

What you'll build

A mobile app with deep-link OAuth callbacks, secure session storage, and sign-in screens.

your-app.local

Welcome back

After sign-in

✓ Session stored securely

✓ User profile available in your app

✓ Organisation context ready for multi-tenant features

Installation

pnpm add @wocha/react-native

Then install Expo peer dependencies:

npx expo install expo-web-browser expo-secure-store expo-linking

Environment variables

Expo supports public env vars prefixed with EXPO_PUBLIC_. Create .env:

EXPO_PUBLIC_WOCHA_ISSUER=https://your-tenant.auth.wocha.ai
EXPO_PUBLIC_WOCHA_CLIENT_ID=your-client-id
 
# Optional — self-hosted or custom API host
EXPO_PUBLIC_WOCHA_API_URL=https://your-tenant.api.wocha.ai/v1

App configuration

Add your URL scheme to app.json:

{
  "expo": {
    "scheme": "myapp",
    "ios": {
      "bundleIdentifier": "com.example.myapp"
    },
    "android": {
      "package": "com.example.myapp"
    }
  }
}

Register myapp://auth/callback as a redirect URI in the Wocha Console.

Provider setup

Wrap your app in App.tsx:

import { WochaProvider } from "@wocha/react-native";
import { NavigationContainer } from "@react-navigation/native";
import { RootNavigator } from "./navigation";
 
const greetConfig = {
  issuer: process.env.EXPO_PUBLIC_WOCHA_ISSUER!,
  clientId: process.env.EXPO_PUBLIC_WOCHA_CLIENT_ID!,
  redirectUri: "myapp://auth/callback",
  apiUrl: process.env.EXPO_PUBLIC_WOCHA_API_URL,
  onRedirectCallback: (appState) => {
    console.log("Signed in", appState);
  },
};
 
export default function App() {
  return (
    <WochaProvider config={greetConfig}>
      <NavigationContainer>
        <RootNavigator />
      </NavigationContainer>
    </WochaProvider>
  );
}

WochaProvider automatically:

  • Restores sessions from secure storage on launch
  • Listens for deep link callbacks via expo-linking (or React Native Linking)
  • Refreshes access tokens in the background

Sign-in screen

Create screens/HomeScreen.tsx:

import { useWochaAuth, useSession, useOrg } from "@wocha/react-native";
import { ActivityIndicator, Button, Text, View } from "react-native";
 
export function HomeScreen() {
  const { signIn, signUp, signOut } = useWochaAuth();
  const { data, status, error } = useSession();
  const { orgId, orgIds, switchOrg, isSwitching } = useOrg();
 
  if (status === "loading") {
    return <ActivityIndicator />;
  }
 
  if (status === "authenticated" && data) {
    return (
      <View style={{ padding: 24, gap: 12 }}>
        <Text>Signed in as {data.email}</Text>
        <Text>Organisation: {orgId ?? "—"}</Text>
        {orgIds?.map((id) => (
          <Button
            key={id}
            title={`Switch to ${id}`}
            disabled={isSwitching || id === orgId}
            onPress={() => void switchOrg(id)}
          />
        ))}
        <Button title="Sign out" onPress={() => void signOut()} />
      </View>
    );
  }
 
  return (
    <View style={{ padding: 24, gap: 12 }}>
      {error ? <Text>{error.message}</Text> : null}
      <Button title="Sign in" onPress={() => void signIn()} />
      <Button title="Create account" onPress={() => void signUp()} />
    </View>
  );
}

Calling your API

Attach the access token to API requests:

import { useAccessToken } from "@wocha/react-native";
 
export function useAuthenticatedFetch() {
  const { getAccessToken } = useAccessToken();
 
  return async (url: string, init?: RequestInit) => {
    const token = await getAccessToken();
    if (!token) throw new Error("Not authenticated");
 
    return fetch(url, {
      ...init,
      headers: {
        ...init?.headers,
        Authorization: `Bearer ${token}`,
      },
    });
  };
}

Testing the integration

  1. Start the app:

    npx expo start
  2. Open on a device or simulator (deep links behave most reliably on a real device).

  3. Tap Sign in — the in-app browser opens the hosted Wocha login UI.

  4. Complete login — the app receives myapp://auth/callback?code=…&state=… and exchanges the code for tokens.

  5. Force-quit and reopen the app — the session should restore from secure storage.

Troubleshooting

IssueFix
redirect_uri_mismatchEnsure myapp://auth/callback is registered in the Console
Session not persistingInstall expo-secure-store
Callback not receivedVerify scheme in app.json matches your redirect URI

Next steps

On this page