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