Lesson 74 of 158 – Protected API
74%

Protected API

A protected API is an API endpoint that requires valid authentication before allowing access to protected data or operations. In this lesson, we will protect a PHP REST API using JWT authentication and connect it with a React Native application.

Note: A protected API should verify the JWT before using the authenticated user's identity to access private resources.

1. What is a Protected API?

A protected API is an endpoint that cannot be used successfully without valid authentication.

Client
  ↓
Protected API
  ↓
Authentication Check
  ↓
Valid?
 ┌───┴───┐
Yes      No
 ↓        ↓
Data     401

2. Why Protect an API?

Many applications contain private information that should only be available to authenticated users.

  • User profiles
  • Student information
  • Payment information
  • Private messages
  • Orders
  • Personal dashboard data
  • Administrative operations

3. Public API vs Protected API

Public API Protected API
May be accessed without login Requires authentication
No JWT may be required JWT is commonly required
Example: Public courses Example: Student profile
Limited sensitive data Private data

4. Protected API Flow

React Native
     ↓
JWT Token
     ↓
Authorization Header
     ↓
Protected PHP API
     ↓
Verify JWT
     ↓
Identify User
     ↓
Return Protected Data

5. Authorization Header

The React Native application can send the JWT using the Authorization header.

Authorization:
Bearer YOUR_JWT_TOKEN

6. Read Authorization Header in PHP

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

if ($authorization === '') {

    http_response_code(401);

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

    exit;
}

7. Extract the 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]);

8. Install JWT Library

Use a maintained JWT library for creating and verifying JWTs.

composer require firebase/php-jwt

The library provides the classes required for JWT verification.

9. Include JWT Library

require_once
    __DIR__ . '/vendor/autoload.php';

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

10. JWT Secret Key

The protected API needs the same verification key that corresponds to the signing method used when the JWT was created.

$secretKey =
    "YOUR_SECURE_SERVER_SECRET";
Important: Keep the secret key on the server. Never send it to the React Native application.

11. Verify the JWT

try {

    $decoded = JWT::decode(
        $token,
        new Key($secretKey, 'HS256')
    );

} catch (Throwable $e) {

    http_response_code(401);

    echo json_encode([
        "success" => false,
        "message" => "Invalid token"
    ]);

    exit;
}

12. Read User ID from JWT

Suppose the login API placed the user ID in the sub claim.

$userId = $decoded->sub ?? null;

if (!$userId) {

    http_response_code(401);

    echo json_encode([
        "success" => false,
        "message" =>
            "Invalid token payload"
    ]);

    exit;
}

13. Find Authenticated User

$stmt = $pdo->prepare(
    "SELECT id, name, email
     FROM users
     WHERE id = ?
     LIMIT 1"
);

$stmt->execute([$userId]);

$user = $stmt->fetch(
    PDO::FETCH_ASSOC
);

14. Check User Exists

if (!$user) {

    http_response_code(401);

    echo json_encode([
        "success" => false,
        "message" => "User not found"
    ]);

    exit;
}

This prevents the API from continuing when the JWT refers to a user that does not exist.

15. Return User Profile

After successful authentication, the API can return the user's protected profile information.

echo json_encode([
    "success" => true,
    "message" =>
        "Profile loaded",
    "user" => $user
]);

16. Complete Protected Profile 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')
    );

    $userId =
        $decoded->sub ?? null;

    if (!$userId) {

        http_response_code(401);

        echo json_encode([
            "success" => false,
            "message" =>
                "Invalid token payload"
        ]);

        exit;
    }

    $stmt = $pdo->prepare(
        "SELECT id, name, email
         FROM users
         WHERE id = ?
         LIMIT 1"
    );

    $stmt->execute([$userId]);

    $user =
        $stmt->fetch(
            PDO::FETCH_ASSOC
        );

    if (!$user) {

        http_response_code(401);

        echo json_encode([
            "success" => false,
            "message" => "User not found"
        ]);

        exit;
    }

    http_response_code(200);

    echo json_encode([
        "success" => true,
        "message" =>
            "Profile loaded successfully",
        "user" => $user
    ]);

} catch (Throwable $e) {

    http_response_code(401);

    echo json_encode([
        "success" => false,
        "message" =>
            "Invalid or expired token"
    ]);

}

?>

17. Protected Student API

The same authentication process can protect a student API.

GET /api/student.php

Authorization:
Bearer JWT

After verification, the API can use the authenticated user's ID to retrieve the appropriate student information.

18. Protected Student Data

JWT
 ↓
User ID
 ↓
Student Table
 ↓
Find Student
 ↓
Return Student Data

For example, the API could return a student's name, course, attendance, or other information that the authenticated user is permitted to access.

19. HTTP 401 for Invalid Authentication

If the token is missing, invalid, malformed, or expired, the API should normally return HTTP 401.

http_response_code(401);

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

20. Authentication is Not Authorization

A valid JWT proves that the request is authenticated, but the user may still not have permission to perform every operation.

JWT Valid
   ↓
Identify User
   ↓
Check Permission
   ↓
Allowed?
 ┌───┴───┐
Yes      No
 ↓        ↓
Allow    403

21. Role-Based Protected API

Suppose the JWT contains a role claim.

{
    "sub": "101",
    "role": "student"
}

An admin-only endpoint can check the user's role after authentication.

if ($decoded->role !== 'admin') {

    http_response_code(403);

    echo json_encode([
        "success" => false,
        "message" =>
            "Access denied"
    ]);

    exit;
}

22. React Native Calls Protected API

const response = await fetch(
    "https://example.com/api/profile.php",
    {
        method: "GET",

        headers: {
            "Authorization":
                "Bearer " + token,
            "Accept":
                "application/json"
        }
    }
);

const data =
    await response.json();

console.log(data);

23. Handle Protected API Response

if (response.ok) {

    console.log(
        "Protected data:",
        data
    );

} else if (
    response.status === 401
) {

    console.log(
        "Login required"
    );

} else if (
    response.status === 403
) {

    console.log(
        "Access denied"
    );
}

24. Protected API with Axios

The same JWT can be sent using Axios.

axios.get(
    "https://example.com/api/profile.php",
    {
        headers: {
            Authorization:
                "Bearer " + token
        }
    }
)
.then(response => {

    console.log(
        response.data
    );

});

25. Protect POST Requests

Authentication can protect not only GET APIs but also POST, PUT, PATCH, and DELETE operations.

POST /api/student.php

Authorization:
Bearer JWT

Content-Type:
application/json

The API should verify authentication before processing the operation.

26. Protect DELETE Requests

A DELETE API should verify the authenticated user and authorization before deleting data.

DELETE /api/student.php?id=15

Authorization:
Bearer JWT

A valid JWT alone does not necessarily mean the user has permission to delete the selected record.

27. Protected API Architecture

                 React Native
                      ↓
                Login API
                      ↓
                    JWT
                      ↓
               Token Storage
                      ↓
              Protected Request
                      ↓
             Authorization Header
                      ↓
                 PHP API
                      ↓
                Verify JWT
                      ↓
               Identify User
                      ↓
             Check Permission
                      ↓
                MySQL Query
                      ↓
                JSON Response

28. Protected API Best Practices

  • Use HTTPS.
  • Verify the JWT on protected requests.
  • Check token expiration.
  • Keep signing keys secret.
  • Use prepared SQL statements.
  • Do not return password hashes.
  • Separate authentication from authorization.
  • Return 401 for authentication failures.
  • Return 403 when an authenticated user lacks permission.
  • Validate request data before database operations.
  • Use secure token storage in React Native.
  • Do not place JWTs in URLs.

29. Test Protected API in Postman

Step 1: Login first.

POST
http://localhost/api/jwt_login.php

Step 2: Copy the JWT from the response.

Step 3: Open the protected endpoint.

GET
http://localhost/api/profile.php

Step 4: Add:

Authorization:
Bearer YOUR_JWT_TOKEN

Step 5: Send the request.

A valid token should allow the API to return protected data. Removing the token or changing it should result in an authentication error.

30. Protected API Summary

A protected API verifies the user's JWT before providing private resources. The React Native application sends the JWT in the Authorization header. The PHP server verifies the token, identifies the user, checks authorization when necessary, performs the database operation, and returns the protected JSON response.

React Native
     ↓
Bearer JWT
     ↓
Protected API
     ↓
Verify JWT
     ↓
Identify User
     ↓
Check Permission
     ↓
Database
     ↓
Protected JSON Response

📌 Key Points

  • A protected API requires authentication before providing protected resources.
  • JWT is commonly sent through the Authorization Bearer header.
  • The server must verify the JWT before trusting its claims.
  • Invalid or expired JWTs should normally result in HTTP 401.
  • The authenticated user's ID can be obtained from a verified JWT claim.
  • Prepared statements should be used for database queries.
  • A valid JWT does not automatically grant every permission.
  • Authorization should be checked separately when required.
  • HTTP 403 can be used when an authenticated user lacks permission.
  • Protected APIs can handle GET, POST, PUT, PATCH, and DELETE requests.
  • React Native can call protected APIs using Fetch or Axios.
  • JWT signing keys must remain on the server.
  • HTTPS should be used for protected API communication.
  • The next lesson will cover the User Profile API.

🧠 Quick Quiz

Question: What should a protected API do before returning private user data?