Logout is the process of ending an authenticated user's session. In a JWT-based React Native application, logout usually involves removing the JWT from the mobile application and, when the application architecture requires server-side revocation, invalidating the token on the server.
Logout means ending the user's authenticated state in the application.
Authenticated User
↓
Logout
↓
Remove Authentication State
↓
Login Screen
In a mobile application, logout should also prevent the application from continuing to use an old authentication token.
JWT authentication requires special consideration because a JWT can be verified without necessarily looking up a server-side session record.
Login
↓
JWT
↓
Mobile App
↓
Logout
↓
Delete Local JWT
For stronger server-side logout control, the application can also use token revocation.
| Part | Purpose |
|---|---|
| Client Logout | Remove the token from the mobile application |
| Server Revocation | Prevent a previously issued token from being accepted |
React Native
↓
User taps Logout
↓
Remove JWT
↓
Clear User State
↓
Navigate to Login
For many applications, removing the local authentication state is an important part of logout.
If the mobile application keeps the JWT after logout, application code could accidentally continue sending the token with API requests.
Before Logout
JWT exists
↓
Protected API works
After Logout
JWT removed
↓
Protected API cannot be called
↓
Login required
If the application stores the JWT locally, logout should remove it from that storage mechanism.
For example, if AsyncStorage is being used for a learning example:
import AsyncStorage
from '@react-native-async-storage/async-storage';
await AsyncStorage.removeItem(
'authToken'
);
The application should also clear the in-memory authenticated user state.
setUser(null);
setToken(null);
The exact implementation depends on whether the application uses Context, Redux, Zustand, or another state management solution.
After removing the authentication state, the user can be redirected to the login screen.
navigation.replace(
'Login'
);
Using a replacement navigation action can prevent the user from simply going back to a protected screen through the navigation history.
For applications that need immediate token revocation, the server can maintain a token revocation or session record.
React Native
↓
Logout API
↓
Authenticate Request
↓
Invalidate Token
↓
Return Success
↓
Remove Local Token
Suppose our logout API is:
POST /api/logout_token.php
The logout request can include the JWT in the Authorization header.
Authorization:
Bearer YOUR_JWT_TOKEN
The server can verify the token and determine which authenticated user is requesting logout.
A logout operation changes the authentication state, so an API can use POST for a logout endpoint.
POST /api/logout_token.php
$authorization =
$_SERVER['HTTP_AUTHORIZATION'] ?? '';
if ($authorization === '') {
http_response_code(401);
echo json_encode([
"success" => false,
"message" => "Token required"
]);
exit;
}
if (
!preg_match(
'/Bearer\s+(.+)/i',
$authorization,
$matches
)
) {
http_response_code(401);
echo json_encode([
"success" => false,
"message" =>
"Invalid authorization header"
]);
exit;
}
$token = trim($matches[1]);
If the server-side logout endpoint is protected, it should verify the JWT before performing token-related operations.
require_once
__DIR__ . '/vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$decoded = JWT::decode(
$token,
new Key($secretKey, 'HS256')
);
A server can maintain a list of revoked tokens or token identifiers. Protected APIs can check this information before accepting a token.
JWT
↓
Verify Signature
↓
Check Expiration
↓
Check Revocation
↓
Allowed?
A simple revocation table could contain information such as:
| Column | Purpose |
|---|---|
| id | Record ID |
| jti | JWT identifier |
| user_id | User associated with the token |
| revoked_at | Time token was revoked |
The exact design depends on the token lifecycle and application requirements.
The jti claim can be used as a unique identifier for a JWT.
$payload = [
"sub" => (string)$user['id'],
"jti" => bin2hex(
random_bytes(16)
),
"iat" => time(),
"exp" => time() + 3600
];
The server can use this identifier when implementing token revocation.
$stmt = $pdo->prepare(
"INSERT INTO revoked_tokens
(jti, user_id, revoked_at)
VALUES (?, ?, NOW())"
);
$stmt->execute([
$decoded->jti,
$decoded->sub
]);
A protected API can then reject a token whose JTI has been revoked.
$stmt = $pdo->prepare(
"SELECT id
FROM revoked_tokens
WHERE jti = ?
LIMIT 1"
);
$stmt->execute([
$decoded->jti
]);
$revoked =
$stmt->fetch(
PDO::FETCH_ASSOC
);
if ($revoked) {
http_response_code(401);
echo json_encode([
"success" => false,
"message" =>
"Token has been revoked"
]);
exit;
}
After successful server-side logout, the API can return:
{
"success": true,
"message": "Logout successful"
}
const logout = async () => {
try {
await fetch(
"https://example.com/api/logout_token.php",
{
method: "POST",
headers: {
"Authorization":
"Bearer " + token,
"Accept":
"application/json"
}
}
);
} finally {
await AsyncStorage.removeItem(
"authToken"
);
setToken(null);
setUser(null);
navigation.replace(
"Login"
);
}
};
The local token should be removed even if the logout API request fails, so that the application does not continue using the old local authentication state.
A simple JWT application may only remove the token from local storage.
await AsyncStorage.removeItem(
"authToken"
);
setToken(null);
setUser(null);
navigation.replace(
"Login"
);
This logs the user out of the current device, but a previously issued JWT may still be accepted by the server until it expires if no server-side revocation mechanism is implemented.
Mobile App
↓
Logout API
↓
Verify JWT
↓
Revoke JTI
↓
Success Response
↓
Remove Local JWT
↓
Login Screen
After logout, the mobile application should no longer have an active local authentication state.
Logout
↓
Token Removed
↓
User State Cleared
↓
Login Screen
↓
Protected API
↓
Login Required
If server-side revocation is implemented, the old token should also be rejected by protected APIs.
React Native
↓
User Logout
↓
Logout API
↓
Verify JWT
↓
Revoke Token/JTI
↓
JSON Response
↓
Remove Local Token
↓
Clear User State
↓
Login Screen
<?php
header(
"Content-Type: application/json"
);
require_once '../db.php';
require_once
__DIR__ . '/vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$secretKey =
"YOUR_SECURE_SERVER_SECRET";
try {
$authorization =
$_SERVER['HTTP_AUTHORIZATION'] ?? '';
if (
!preg_match(
'/Bearer\s+(.+)/i',
$authorization,
$matches
)
) {
http_response_code(401);
echo json_encode([
"success" => false,
"message" => "Token required"
]);
exit;
}
$token = trim($matches[1]);
$decoded = JWT::decode(
$token,
new Key($secretKey, 'HS256')
);
$jti = $decoded->jti ?? null;
$userId = $decoded->sub ?? null;
if (!$jti || !$userId) {
http_response_code(401);
echo json_encode([
"success" => false,
"message" =>
"Invalid token payload"
]);
exit;
}
$stmt = $pdo->prepare(
"INSERT INTO revoked_tokens
(jti, user_id, revoked_at)
VALUES (?, ?, NOW())"
);
$stmt->execute([
$jti,
$userId
]);
http_response_code(200);
echo json_encode([
"success" => true,
"message" =>
"Logout successful"
]);
} catch (Throwable $e) {
http_response_code(401);
echo json_encode([
"success" => false,
"message" =>
"Invalid or expired token"
]);
}
?>
Step 1: Login using the JWT login API.
POST
http://localhost/api/jwt_login.php
Step 2: Copy the JWT.
Step 3: Call the logout API.
POST
http://localhost/api/logout_token.php
Step 4: Add:
Authorization:
Bearer YOUR_JWT_TOKEN
Step 5: After logout, try the same token against a protected API.
GET
http://localhost/api/user_profile.php
If server-side revocation is implemented and the protected API checks the revocation list, the old token should be rejected.
Logout in a JWT-based mobile application involves removing the local JWT and clearing the application's authenticated state. When immediate server-side invalidation is required, the server can maintain a token revocation mechanism, such as storing revoked JWT IDs. Protected APIs must check that revocation mechanism before accepting a token.
Login
↓
JWT
↓
React Native
↓
Logout
↓
Logout API
↓
Revoke JWT
↓
Remove Local Token
↓
Clear User State
↓
Login Screen
Question: What should a React Native application do with the locally stored JWT during logout?