
Managing user authentication is a must-have in almost every mobile app. While libraries like Redux or Zustand are popular for state management, the built-in Context API is more than enough for handling simple and secure authentication flows in React Native.
In this post, weβll walk you through how to implement a clean login and register flow using React Native and the Context API. We’ll also include token storage, global state access, and protected route handling β all without external dependencies.
π Why Use Context API for Auth?
The Context API is ideal for lightweight global state like auth because:
- It’s built into React (no extra packages)
- You can expose and consume state anywhere in your app
- Works well with hooks like
useContext
anduseReducer
- Perfect for apps that donβt need heavy global state logic
π Learn more: Passing Data Deeply with Context β react.dev
π¦ Project Structure (Recommended)
/src
/auth
AuthContext.tsx
authReducer.ts
authAPI.ts
/screens
LoginScreen.tsx
RegisterScreen.tsx
HomeScreen.tsx
/navigation
AppNavigator.tsx
We follow a feature-first structure for clean separation.
π Why You Should Use Feature-First Folder Structure
π§ Step 1: Create the Context
import React, { createContext, useContext, useReducer } from 'react';
const AuthContext = createContext(null);
const initialState = { isAuthenticated: false, user: null, token: null };
function authReducer(state, action) {
switch (action.type) {
case 'LOGIN':
return { ...state, isAuthenticated: true, user: action.payload.user, token: action.payload.token };
case 'LOGOUT':
return initialState;
default:
return state;
}
}
export const AuthProvider = ({ children }) => {
const [state, dispatch] = useReducer(authReducer, initialState);
const login = async (email, password) => {
const token = 'fake-jwt-token'; // Replace with API call
const user = { email };
dispatch({ type: 'LOGIN', payload: { user, token } });
};
const logout = () => dispatch({ type: 'LOGOUT' });
return (
{children}
);
};
export const useAuth = () => useContext(AuthContext);
π Step 2: Create Login/Register Screens
import React, { useState } from 'react';
import { View, TextInput, Button, Text } from 'react-native';
import { useAuth } from '../auth/AuthContext';
const LoginScreen = () => {
const { login } = useAuth();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
return (
For registration, you can use the same logic with a register()
method in context.
π§ Step 3: Create Protected Navigation
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { useAuth } from '../auth/AuthContext';
import LoginScreen from '../screens/LoginScreen';
import HomeScreen from '../screens/HomeScreen';
const Stack = createNativeStackNavigator();
const AppNavigator = () => {
const { isAuthenticated } = useAuth();
return (
{isAuthenticated ? (
) : (
)}
);
};
export default AppNavigator;
πΎ Optional: Persist Tokens with AsyncStorage
import AsyncStorage from '@react-native-async-storage/async-storage';
const login = async (email, password) => {
const token = 'real-token'; // From API
const user = { email };
await AsyncStorage.setItem('token', token);
dispatch({ type: 'LOGIN', payload: { user, token } });
};
And on app start, use useEffect
to restore login state.
π§ͺ Bonus: Logout Button Example
const HomeScreen = () => {
const { logout } = useAuth();
return (
Welcome!
β οΈ Security Tips
- Never store sensitive tokens in plain AsyncStorage (consider
SecureStore
orKeychain
) - Invalidate session on the server when logging out
- Handle token expiry and refresh securely
β Final Thoughts
Using React Native with the Context API is a simple and effective way to manage authentication in 2025. It keeps your code light, modular, and easy to test. For apps that donβt need complex global state, Context is more than enough.
You can always migrate to Redux, Zustand, or Firebase Auth later β but this pattern is a great foundation.