Lesson 76 of 158 – Logout Token
76%

Logout Token

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.

Note: A JWT is normally self-contained. Simply deleting a JWT from the mobile application prevents that client from using it locally, but a previously issued JWT may remain cryptographically valid until it expires unless the server uses a revocation strategy.

1. What is Logout?

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.

2. Logout in JWT Authentication

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.

3. Two Parts of Logout

Part Purpose
Client Logout Remove the token from the mobile application
Server Revocation Prevent a previously issued token from being accepted

4. Basic Logout Flow

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.

5. Why Delete the JWT?

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

6. Local Token Removal

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'
);

7. Clear User State

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.

8. Navigate to Login Screen

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.

9. Server-Side Logout

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

10. Logout API URL

Suppose our logout API is:

POST /api/logout_token.php

The logout request can include the JWT in the Authorization header.

11. Send JWT to Logout API

Authorization:
Bearer YOUR_JWT_TOKEN

The server can verify the token and determine which authenticated user is requesting logout.

12. Logout API HTTP Method

A logout operation changes the authentication state, so an API can use POST for a logout endpoint.

POST /api/logout_token.php

13. Read Authorization Header

$authorization =
    $_SERVER['HTTP_AUTHORIZATION'] ?? '';

if ($authorization === '') {

    http_response_code(401);

    echo json_encode([
        "success" => false,
        "message" => "Token required"
    ]);

    exit;
}

14. Extract JWT

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]);

15. Verify JWT Before Logout

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')
);

16. JWT Revocation Concept

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?

17. Token Revocation Table

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.

18. JWT jti Claim

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.

19. Store Revoked JWT ID

$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.

20. Check Whether JWT is 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;
}

21. Simple Logout API Response

After successful server-side logout, the API can return:

{
    "success": true,
    "message": "Logout successful"
}

22. React Native Logout Function

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.

23. Logout Without Server Revocation

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.

24. Logout with Server Revocation

Mobile App
     ↓
Logout API
     ↓
Verify JWT
     ↓
Revoke JTI
     ↓
Success Response
     ↓
Remove Local JWT
     ↓
Login Screen

25. What Happens After Logout?

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.

26. Logout Security Rules

  • Remove the JWT from local storage.
  • Clear the authenticated user state.
  • Navigate to the login screen.
  • Use HTTPS.
  • Do not put JWTs in URLs.
  • Use short-lived tokens when appropriate.
  • Consider server-side revocation when immediate invalidation is required.
  • Never expose the JWT signing secret.
  • Do not log sensitive authentication tokens unnecessarily.
  • Protect the logout API when server-side token revocation is used.

27. Complete Logout Architecture

                 React Native
                      ↓
                User Logout
                      ↓
                Logout API
                      ↓
                 Verify JWT
                      ↓
              Revoke Token/JTI
                      ↓
                JSON Response
                      ↓
             Remove Local Token
                      ↓
             Clear User State
                      ↓
                Login Screen

28. Complete PHP Logout API

<?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"
    ]);

}

?>

29. Test Logout API in Postman

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.

30. Logout Token Summary

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

📌 Key Points

  • Logout ends the authenticated state of the user.
  • React Native should remove the locally stored JWT during logout.
  • The authenticated user state should also be cleared.
  • The application should navigate the user back to the login screen.
  • A JWT may remain cryptographically valid after local deletion.
  • Server-side revocation can be used when immediate token invalidation is required.
  • The jti claim can provide a unique identifier for a JWT.
  • A revoked JWT should be rejected by protected APIs.
  • The logout API can receive the JWT through the Authorization header.
  • The logout API should use HTTPS in production.
  • Never expose the JWT signing secret.
  • Short-lived tokens can reduce the impact of a leaked token.
  • The next lesson will cover API search.

🧠 Quick Quiz

Question: What should a React Native application do with the locally stored JWT during logout?