I am doing auth for my React Native app. I have two methods for now, one is email and other is Google sign in. I am managing the auth using a context provider passed to the root layout file.
The page routes to main page if I log in using email but not Google sign in unless I reload the app.
Here are my files:
AuthContext.js
import AsyncStorage from '@react-native-async-storage/async-storage';
import { GoogleSignin } from '@react-native-google-signin/google-signin';
import React, { createContext, useContext, useEffect, useState } from 'react';
import { processSignIn } from '../api/auth';
const AuthContext = createContext(null);
export const AuthProvider = ({ children }) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [isSigningIn, setIsSigningIn] = useState(false);
// Configure Google Signin on mount
GoogleSignin.configure({
webClientId: '', //
offlineAccess: true,
});
const logStorage = async () => {
const authToken = await AsyncStorage.getItem('auth')
console.log("LOGGING AUTH_TOKEN", authToken)
}
useEffect(() => {
const loadAuthState = async () => {
try {
let auth = await AsyncStorage.getItem('auth');
// If 'auth' doesn't exist yet (first launch), set it to false
if (auth === null) {
await AsyncStorage.setItem('auth', 'false');
auth = 'false';
}
setIsAuthenticated(auth === 'true');
} catch (err) {
console.error('Error loading auth state', err);
setIsAuthenticated(false);
} finally {
setIsLoading(false);
}
logStorage();
};
loadAuthState();
}, []);
useEffect(() => {
console.log("Auth state changed:", isAuthenticated);
}, [isAuthenticated]);
// Google Sign-In login
const signInWithGoogle = async () => {
if (isSigningIn) return; // Block duplicate sign-ins
setIsSigningIn(true);
try {
// Make sure Play Services is available
await GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true });
// Optional: clear any unfinished sign-in state
// await GoogleSignin.signOut();
const userInfo = await GoogleSignin.signIn();
console.log("Google User Info:", userInfo);
// Store authentication
// if (userInfo.type === "success") {
await AsyncStorage.setItem('auth', 'true');
await AsyncStorage.setItem('googleUser', JSON.stringify(userInfo));
setIsAuthenticated(true);
// }
} catch (error) {
console.error('Google Sign-In Error', error);
} finally {
setIsSigningIn(false);
}
};
const login = async (data) => {
// await AsyncStorage.setItem('auth', 'true');
// await AsyncStorage.setItem('firstLogin','true')
try {
const res = await processSignIn(data);
if (res.status == 200) {
console.log("Login Success")
console.log(res)
await AsyncStorage.setItem('auth', 'true')
setIsAuthenticated(true);
} else {
console.log("Login Failed", res.message)
}
} catch (error) {
console.log(error)
}
};
const logout = async () => {
try {
// Sign out from Google
await GoogleSignin.signOut();
// Clear saved auth state
await AsyncStorage.removeItem('auth');
await AsyncStorage.removeItem('googleUser');
// Update app state so it shows login screen again
setIsAuthenticated(false);
console.log('Logged out successfully');
} catch (error) {
console.error('Error logging out', error);
}
};
if (isLoading) {
return null; // Replace with splash screen if needed
}
return (
<AuthContext.Provider value={{ isAuthenticated, login, logout, isLoading, signInWithGoogle }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => useContext(AuthContext);
_layout.jsx
import { Redirect, Stack } from 'expo-router';
import { useAuth } from '../utils/authContext';
export default function RootLayout() {
const { isAuthenticated, isLoading } = useAuth();
if (!isAuthenticated) {
return (<Redirect href="/login"/>);
}
return (
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="(drawer)" />
</Stack>
);
}