Logout is an important part of authentication in a React Native application. When a user logs out, the application should clear the locally stored authentication information and return the user to the authentication flow.
Logout is the process of ending the current authenticated session from the application's point of view.
Logout
↓
Remove Token
↓
Clear User State
↓
Clear Authentication State
↓
Show Login Screen
A JWT is normally self-contained and does not require a server-side session for every request.
Login
↓
JWT Created
↓
React Native Stores JWT
↓
Protected Requests
↓
Logout
↓
React Native Removes JWT
Removing the token locally prevents the client from using that stored token in future requests.
import AsyncStorage
from "@react-native-async-storage/async-storage";
await AsyncStorage.removeItem(
"authToken"
);
This removes the locally stored JWT.
setToken(null);
setUser(null);
Removing the token from storage is not enough if the token and user are still present in React state.
const logout = async () => {
await AsyncStorage.removeItem(
"authToken"
);
setToken(null);
setUser(null);
};
interface AuthContextType {
user: User | null;
token: string | null;
isAuthenticated: boolean;
loading: boolean;
login: (
token: string,
user: User
) => Promise<void>;
logout: () => Promise<void>;
}
The logout function can be exposed through Auth Context so any screen can use it.
const ProfileScreen = () => {
const {
user,
logout
} = useAuth();
return (
<View>
<Text>
Welcome {user?.name}
</Text>
<Button
title="Logout"
onPress={logout}
/>
</View>
);
};
Profile Screen
↓
Logout Button
↓
logout()
↓
Remove JWT
↓
Clear User
↓
isAuthenticated = false
↓
Auth Navigator
↓
Login Screen
const RootNavigator = () => {
const {
isAuthenticated,
loading
} = useAuth();
if (loading) {
return <LoadingScreen />;
}
if (isAuthenticated) {
return <AppNavigator />;
}
return <AuthNavigator />;
};
Clearing authentication state can automatically switch the application back to the authentication navigator.
Alert.alert(
"Logout",
"Are you sure you want to logout?",
[
{
text: "Cancel"
},
{
text: "Logout",
onPress: logout
}
]
);
Confirmation can prevent accidental logout actions.
import {
Alert
} from "react-native";
React Native's Alert component can be used to confirm
sensitive actions such as logout.
const handleLogout = () => {
Alert.alert(
"Logout",
"Do you want to logout?",
[
{
text: "Cancel",
style: "cancel"
},
{
text: "Logout",
onPress: async () => {
await logout();
}
}
]
);
};
Suppose the token is removed but the user state remains:
token = null;
user = {
name: "Rahul",
email: "rahul@example.com"
};
The UI could still display private user information. Therefore logout should clear both authentication credentials and user state.
Applications may store other session-specific information.
await AsyncStorage.removeItem(
"authToken"
);
await AsyncStorage.removeItem(
"currentUser"
);
await AsyncStorage.removeItem(
"selectedStudent"
);
Only remove keys that belong to the current authentication/session design.
await AsyncStorage.removeItem(
"currentUser"
);
setUser(null);
If the user object is persisted separately, it should also be removed during logout.
After logout, future Axios requests should not receive the old token from the token storage mechanism.
await AsyncStorage.removeItem(
"authToken"
);
If an Axios interceptor reads the token from AsyncStorage for every request, it will find no token after logout.
try {
const response =
await api.get(
"/profile.php"
);
} catch (error) {
if (
axios.isAxiosError(error) &&
error.response?.status === 401
) {
await logout();
}
}
A 401 response may indicate that the token is invalid, expired, or missing.
api.interceptors.response.use(
response => response,
async error => {
if (
error.response?.status === 401
) {
await AsyncStorage.removeItem(
"authToken"
);
}
return Promise.reject(error);
}
);
A centralized response interceptor can help handle authentication failures consistently.
| Client Logout | Server Revocation |
|---|---|
| Removes local token | Server rejects a revoked token |
| Changes app authentication state | Requires server-side state or token strategy |
| Simple to implement | Requires additional backend design |
These are related but different concepts.
A signed JWT normally remains valid until its expiration time unless the server has a mechanism to reject it before expiration.
JWT
↓
Signed
↓
Stored by Client
↓
Logout
↓
Client Deletes Token
If immediate server-side invalidation is required, additional revocation logic is needed.
A server can maintain a denylist of revoked token identifiers such as
the JWT jti claim.
JWT
↓
jti = ABC123
↓
Logout
↓
Store ABC123 as revoked
↓
Future API Request
↓
Check Revocation
↓
Reject if revoked
This introduces server-side state and additional database or cache work.
Another common design is to use short-lived access tokens and a separate refresh-token mechanism.
Login
↓
Access Token
↓
Short Lifetime
↓
Refresh Token
↓
New Access Token
The exact refresh-token implementation should be designed carefully for the application's security requirements.
With a stateless JWT-only design, a logout API is not automatically necessary just to delete the token from the mobile device.
A backend logout endpoint becomes useful when the server needs to revoke refresh tokens, access tokens, sessions, or other server-side authentication state.
POST /api/logout.php
const logoutFromServer =
async () => {
try {
await api.post(
"/logout.php"
);
} catch (error) {
console.log(
"Logout API error"
);
} finally {
await logout();
}
};
Clearing the local authentication state in finally ensures
the user can still be logged out locally even if the network request fails.
const logout = async () => {
try {
await AsyncStorage.removeItem(
"authToken"
);
await AsyncStorage.removeItem(
"currentUser"
);
} finally {
setToken(null);
setUser(null);
}
};
The authentication state is cleared even if local cleanup encounters an error.
const SettingsScreen = () => {
const { logout } =
useAuth();
const handleLogout = () => {
Alert.alert(
"Logout",
"Are you sure?",
[
{
text: "Cancel",
style: "cancel"
},
{
text: "Logout",
onPress: async () => {
await logout();
}
}
]
);
};
return (
<View>
<Button
title="Logout"
onPress={handleLogout}
/>
</View>
);
};
User Taps Logout
↓
Optional Logout API
↓
Remove JWT
↓
Remove Session Data
↓
setToken(null)
↓
setUser(null)
↓
isAuthenticated = false
↓
Auth Navigator
↓
Login Screen
Settings / Profile
↓
Logout Button
↓
Optional Logout API
↓
Remove Access Token
↓
Clear User State
↓
Clear Session Data
↓
isAuthenticated = false
↓
Auth Context Updates
↓
Root Navigator Updates
↓
Login Screen
For server-side revocation:
Logout
↓
Revoke Refresh Token /
Token Identifier
↓
Future Protected Request
↓
Server Rejects Revoked Credential
A complete logout implementation should clear the local authentication state and, when the application's authentication design requires it, perform server-side revocation of reusable credentials.
removeItem().Question: What should React Native normally do with a locally stored JWT when the user logs out?