From c0f7e7dfd1b9483821bb3d05067ce5db6787084d Mon Sep 17 00:00:00 2001 From: Chris Chinchilla Date: Mon, 23 Feb 2026 08:54:17 +0100 Subject: [PATCH] docs: Rework Expo React native social auth (#43017) ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES Reworks Expo React native social to use appropriate auth methods and restructures to use external code. --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../with-expo-react-native-social-auth.mdx | 918 +- .../expo-social-auth/app/(tabs)/_layout.tsx | 24 +- .../expo-social-auth/app/(tabs)/explore.tsx | 110 - .../expo-social-auth/app/(tabs)/index.tsx | 26 +- .../auth/expo-social-auth/app/+not-found.tsx | 2 +- .../auth/expo-social-auth/app/_layout.tsx | 35 +- examples/auth/expo-social-auth/app/login.tsx | 44 +- .../assets/fonts/SpaceMono-Regular.ttf | Bin 93252 -> 99356 bytes .../assets/images/android-icon-background.png | Bin 0 -> 17549 bytes .../assets/images/android-icon-foreground.png | Bin 0 -> 78796 bytes .../assets/images/android-icon-monochrome.png | Bin 0 -> 4140 bytes .../assets/images/favicon.png | Bin 1466 -> 1129 bytes .../expo-social-auth/assets/images/icon.png | Bin 22380 -> 393493 bytes .../assets/supabase-logo-icon.svg | 15 - .../components/collapsible.tsx | 45 - .../components/external-link.tsx | 24 - .../components/haptic-tab.tsx | 18 - .../components/hello-wave.tsx | 6 +- .../components/parallax-scroll-view.tsx | 9 +- .../apple/apple-sign-in-button.android.tsx | 12 +- .../apple/apple-sign-in-button.ios.tsx | 18 +- .../apple/apple-sign-in-button.tsx | 98 +- .../apple/apple-sign-in-button.web.tsx | 68 + .../apple/expo-apple-sign-in-button.tsx | 69 - .../google/google-sign-in-button.tsx | 8 +- .../google/google-sign-in-button.web.tsx | 16 +- .../social-auth-buttons/sign-out-button.tsx | 27 +- .../components/splash-screen-controller.tsx | 15 +- .../components/themed-text.tsx | 5 +- .../components/ui/icon-symbol.ios.tsx | 32 - .../components/ui/icon-symbol.tsx | 41 - .../components/ui/tab-bar-background.ios.tsx | 19 - .../components/ui/tab-bar-background.tsx | 6 - .../auth/expo-social-auth/constants/colors.ts | 26 - .../auth/expo-social-auth/constants/theme.ts | 53 + ...e-auth-context.ts => use-auth-context.tsx} | 7 +- .../expo-social-auth/hooks/use-theme-color.ts | 2 +- .../auth/expo-social-auth/lib/supabase.ts | 2 +- .../auth/expo-social-auth/lib/supabase.web.ts | 7 +- .../auth/expo-social-auth/package-lock.json | 3948 +++-- examples/auth/expo-social-auth/package.json | 74 +- .../providers/auth-provider.tsx | 38 +- .../expo-react-native-social-auth/.gitignore | 7 + .../expo-react-native-social-auth/app.json | 49 + .../app/(tabs)/_layout.tsx | 23 + .../app/(tabs)/index.tsx | 56 + .../app/+not-found.tsx | 32 + .../app/_layout.tsx | 51 + .../app/login.tsx | 32 + .../assets/fonts/SpaceMono-Regular.ttf | Bin 0 -> 99356 bytes .../assets/images/android-icon-background.png | Bin 0 -> 17549 bytes .../assets/images/android-icon-foreground.png | Bin 0 -> 78796 bytes .../assets/images/android-icon-monochrome.png | Bin 0 -> 4140 bytes .../assets/images/favicon.png | Bin 0 -> 1129 bytes .../assets/images/icon.png | Bin 0 -> 393493 bytes .../assets/images/partial-react-logo.png | Bin 0 -> 5075 bytes .../assets/images/react-logo.png | Bin 0 -> 6341 bytes .../assets/images/react-logo@2x.png | Bin 0 -> 14225 bytes .../assets/images/react-logo@3x.png | Bin 0 -> 21252 bytes .../assets/images/splash-icon.png} | Bin .../components/hello-wave.tsx | 40 + .../components/parallax-scroll-view.tsx | 77 + .../apple/apple-sign-in-button.android.tsx | 67 + .../apple/apple-sign-in-button.ios.tsx | 51 + .../apple/apple-sign-in-button.tsx | 51 + .../apple/apple-sign-in-button.web.tsx | 68 + .../google/google-sign-in-button.tsx | 126 + .../google/google-sign-in-button.web.tsx | 73 + .../social-auth-buttons/sign-out-button.tsx | 15 + .../components/splash-screen-controller.tsx | 14 + .../components/themed-text.tsx | 61 + .../components/themed-view.tsx | 14 + .../constants/theme.ts | 53 + .../eslint.config.js | 10 + .../hooks/use-auth-context.tsx | 17 + .../hooks/use-color-scheme.ts | 1 + .../hooks/use-color-scheme.web.ts | 21 + .../hooks/use-theme-color.ts | 21 + .../lib/supabase.ts | 31 + .../lib/supabase.web.ts | 34 + .../package-lock.json | 13070 ++++++++++++++++ .../package.json | 56 + .../providers/auth-provider.tsx | 77 + .../tsconfig.json | 17 + 84 files changed, 16510 insertions(+), 3672 deletions(-) delete mode 100644 examples/auth/expo-social-auth/app/(tabs)/explore.tsx mode change 100755 => 100644 examples/auth/expo-social-auth/assets/fonts/SpaceMono-Regular.ttf create mode 100644 examples/auth/expo-social-auth/assets/images/android-icon-background.png create mode 100644 examples/auth/expo-social-auth/assets/images/android-icon-foreground.png create mode 100644 examples/auth/expo-social-auth/assets/images/android-icon-monochrome.png delete mode 100644 examples/auth/expo-social-auth/assets/supabase-logo-icon.svg delete mode 100644 examples/auth/expo-social-auth/components/collapsible.tsx delete mode 100644 examples/auth/expo-social-auth/components/external-link.tsx delete mode 100644 examples/auth/expo-social-auth/components/haptic-tab.tsx create mode 100644 examples/auth/expo-social-auth/components/social-auth-buttons/apple/apple-sign-in-button.web.tsx delete mode 100644 examples/auth/expo-social-auth/components/social-auth-buttons/apple/expo-apple-sign-in-button.tsx delete mode 100644 examples/auth/expo-social-auth/components/ui/icon-symbol.ios.tsx delete mode 100644 examples/auth/expo-social-auth/components/ui/icon-symbol.tsx delete mode 100644 examples/auth/expo-social-auth/components/ui/tab-bar-background.ios.tsx delete mode 100644 examples/auth/expo-social-auth/components/ui/tab-bar-background.tsx delete mode 100644 examples/auth/expo-social-auth/constants/colors.ts create mode 100644 examples/auth/expo-social-auth/constants/theme.ts rename examples/auth/expo-social-auth/hooks/{use-auth-context.ts => use-auth-context.tsx} (72%) create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/.gitignore create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/app.json create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/app/(tabs)/_layout.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/app/(tabs)/index.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/app/+not-found.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/app/_layout.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/app/login.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/assets/fonts/SpaceMono-Regular.ttf create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/assets/images/android-icon-background.png create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/assets/images/android-icon-foreground.png create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/assets/images/android-icon-monochrome.png create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/assets/images/favicon.png create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/assets/images/icon.png create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/assets/images/partial-react-logo.png create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/assets/images/react-logo.png create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/assets/images/react-logo@2x.png create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/assets/images/react-logo@3x.png rename examples/auth/{expo-social-auth/assets/images/adaptive-icon.png => quickstarts/expo-react-native-social-auth/assets/images/splash-icon.png} (100%) create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/components/hello-wave.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/components/parallax-scroll-view.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/components/social-auth-buttons/apple/apple-sign-in-button.android.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/components/social-auth-buttons/apple/apple-sign-in-button.ios.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/components/social-auth-buttons/apple/apple-sign-in-button.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/components/social-auth-buttons/apple/apple-sign-in-button.web.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/components/social-auth-buttons/google/google-sign-in-button.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/components/social-auth-buttons/google/google-sign-in-button.web.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/components/social-auth-buttons/sign-out-button.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/components/splash-screen-controller.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/components/themed-text.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/components/themed-view.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/constants/theme.ts create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/eslint.config.js create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/hooks/use-auth-context.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/hooks/use-color-scheme.ts create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/hooks/use-color-scheme.web.ts create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/hooks/use-theme-color.ts create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/lib/supabase.ts create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/lib/supabase.web.ts create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/package-lock.json create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/package.json create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/providers/auth-provider.tsx create mode 100644 examples/auth/quickstarts/expo-react-native-social-auth/tsconfig.json diff --git a/apps/docs/content/guides/auth/quickstarts/with-expo-react-native-social-auth.mdx b/apps/docs/content/guides/auth/quickstarts/with-expo-react-native-social-auth.mdx index 2f6e0a9206f..daa535e479a 100644 --- a/apps/docs/content/guides/auth/quickstarts/with-expo-react-native-social-auth.mdx +++ b/apps/docs/content/guides/auth/quickstarts/with-expo-react-native-social-auth.mdx @@ -53,42 +53,11 @@ Now, create a helper file to initialize the Supabase client for both web and Rea queryGroup="auth-store" > -{/* TODO: Future task to extract to repo and transclude */} - <$CodeTabs> - - ```ts name=lib/supabase.web.ts - import AsyncStorage from '@react-native-async-storage/async-storage'; - import { createClient } from '@supabase/supabase-js'; - import 'react-native-url-polyfill/auto'; - - const ExpoWebSecureStoreAdapter = { - getItem: (key: string) => { - console.debug("getItem", { key }) - return AsyncStorage.getItem(key) - }, - setItem: (key: string, value: string) => { - return AsyncStorage.setItem(key, value) - }, - removeItem: (key: string) => { - return AsyncStorage.removeItem(key) - }, - }; - - export const supabase = createClient( - process.env.EXPO_PUBLIC_SUPABASE_URL ?? '', - process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY ?? '', - { - auth: { - storage: ExpoWebSecureStoreAdapter, - autoRefreshToken: true, - persistSession: true, - detectSessionInUrl: false, - }, - }, - ); - ``` - - + <$CodeSample + path="/auth/expo-social-auth/lib/supabase.web.ts" + lines={[[1, -1]]} + meta="name=lib/supabase.web.ts" +/> @@ -102,43 +71,12 @@ Now, create a helper file to initialize the Supabase client for both web and Rea Implement a `ExpoSecureStoreAdapter` to pass in as Auth storage adapter for the `supabase-js` client: - <$CodeTabs> + <$CodeSample + path="/auth/expo-social-auth/lib/supabase.ts" + lines={[[1, -1]]} + meta="name=lib/supabase.ts" - ```ts name=lib/supabase.ts - import { createClient } from '@supabase/supabase-js'; - import { deleteItemAsync, getItemAsync, setItemAsync } from 'expo-secure-store'; - - const ExpoSecureStoreAdapter = { - getItem: (key: string) => { - console.debug("getItem", { key, getItemAsync }) - return getItemAsync(key) - }, - setItem: (key: string, value: string) => { - if (value.length > 2048) { - console.warn('Value being stored in SecureStore is larger than 2048 bytes and it may not be stored successfully. In a future SDK version, this call may throw an error.') - } - return setItemAsync(key, value) - }, - removeItem: (key: string) => { - return deleteItemAsync(key) - }, - }; - - export const supabase = createClient( - process.env.EXPO_PUBLIC_SUPABASE_URL ?? '', - process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY ?? '', - { - auth: { - storage: ExpoSecureStoreAdapter as any, - autoRefreshToken: true, - persistSession: true, - detectSessionInUrl: false, - }, - }, - ); - ``` - - +/> @@ -150,14 +88,11 @@ These variables are safe to expose in your Expo app since Supabase has [Row Leve Create a `.env` file containing these variables: -<$CodeTabs> - -```bash name=.env -EXPO_PUBLIC_SUPABASE_URL=YOUR_SUPABASE_URL -EXPO_PUBLIC_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY -``` - - +<$CodeSample +path="/auth/expo-social-auth/.env" +lines={[[1, -1]]} +meta="name=.env" +/> ### Set up protected navigation @@ -167,279 +102,59 @@ Next, you need to protect app navigation to prevent unauthenticated users from a Create [a React context](https://react.dev/learn/passing-data-deeply-with-context) to manage the authentication session, making it accessible from any component: -<$CodeTabs> - -```tsx name=hooks/use-auth-context.tsx -import { Session } from '@supabase/supabase-js' -import { createContext, useContext } from 'react' - -export type AuthData = { - session?: Session | null - profile?: any | null - isLoading: boolean - isLoggedIn: boolean -} - -export const AuthContext = createContext({ - session: undefined, - profile: undefined, - isLoading: true, - isLoggedIn: false, -}) - -export const useAuthContext = () => useContext(AuthContext) -``` - - +<$CodeSample +path="/auth/expo-social-auth/hooks/use-auth-context.tsx" +lines={[[1, -1]]} +meta="name=hooks/use-auth-context.tsx" +/> #### Create the `AuthProvider` Next, create a provider component to manage the authentication session throughout the app: -<$CodeTabs> - -```tsx name=providers/auth-provider.tsx -import { AuthContext } from '@/hooks/use-auth-context' -import { supabase } from '@/lib/supabase' -import type { Session } from '@supabase/supabase-js' -import { PropsWithChildren, useEffect, useState } from 'react' - -export default function AuthProvider({ children }: PropsWithChildren) { - const [session, setSession] = useState() - const [profile, setProfile] = useState() - const [isLoading, setIsLoading] = useState(true) - - // Fetch the session once, and subscribe to auth state changes - useEffect(() => { - const fetchSession = async () => { - setIsLoading(true) - - const { - data: { session }, - error, - } = await supabase.auth.getSession() - - if (error) { - console.error('Error fetching session:', error) - } - - setSession(session) - setIsLoading(false) - } - - fetchSession() - - const { - data: { subscription }, - } = supabase.auth.onAuthStateChange((_event, session) => { - console.log('Auth state changed:', { event: _event, session }) - setSession(session) - }) - - // Cleanup subscription on unmount - return () => { - subscription.unsubscribe() - } - }, []) - - // Fetch the profile when the session changes - useEffect(() => { - const fetchProfile = async () => { - setIsLoading(true) - - if (session) { - const { data } = await supabase - .from('profiles') - .select('*') - .eq('id', session.user.id) - .single() - - setProfile(data) - } else { - setProfile(null) - } - - setIsLoading(false) - } - - fetchProfile() - }, [session]) - - return ( - - {children} - - ) -} -``` - - +<$CodeSample +path="/auth/expo-social-auth/providers/auth-provider.tsx" +lines={[[1, -1]]} +meta="name=providers/auth-provider.tsx" +/> #### Create the `SplashScreenController` Create a `SplashScreenController` component to display the [Expo `SplashScreen`](https://docs.expo.dev/versions/latest/sdk/splash-screen/) while the authentication session is loading: -<$CodeTabs> - -```tsx name=components/splash-screen-controller.tsx -import { useAuthContext } from '@/hooks/use-auth-context' -import { SplashScreen } from 'expo-router' - -SplashScreen.preventAutoHideAsync() - -export function SplashScreenController() { - const { isLoading } = useAuthContext() - - if (!isLoading) { - SplashScreen.hideAsync() - } - - return null -} -``` - - +<$CodeSample +path="/auth/expo-social-auth/components/splash-screen-controller.tsx" +lines={[[1, -1]]} +meta="name=components/splash-screen-controller.tsx" +/> ### Create a logout component Create a logout button component to handle user sign-out: -<$CodeTabs> - -```tsx name=components/social-auth-buttons/sign-out-button.tsx -import { supabase } from '@/lib/supabase' -import React from 'react' -import { Button } from 'react-native' - -async function onSignOutButtonPress() { - const { error } = await supabase.auth.signOut() - - if (error) { - console.error('Error signing out:', error) - } -} - -export default function SignOutButton() { - return