A User Profile API is a protected REST API that returns information about the currently authenticated user. In this lesson, we will create a PHP User Profile API using JWT authentication, MySQL, PDO, and a React Native client.
A User Profile API returns information about the currently authenticated user.
React Native
↓
JWT Token
↓
Profile API
↓
Verify JWT
↓
Find User
↓
Return Profile
After login, a mobile application often needs to display the user's profile information.
Suppose our profile API is:
GET /api/user_profile.php
The API will require a valid JWT.
Because the API is retrieving profile information, we use the GET method.
GET /api/user_profile.php
The React Native application sends the JWT through the Authorization header.
Authorization:
Bearer YOUR_JWT_TOKEN
header(
"Content-Type: application/json"
);
This tells the client that the API response is JSON.
The profile API needs access to the database to retrieve the authenticated user's profile.
require_once '../db.php';
The exact path depends on your project structure.
require_once
__DIR__ . '/vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
The Firebase PHP JWT library can be used to verify the JWT.
$secretKey =
"YOUR_SECURE_SERVER_SECRET";
$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]);
try {
$decoded = JWT::decode(
$token,
new Key($secretKey, 'HS256')
);
} catch (Throwable $e) {
http_response_code(401);
echo json_encode([
"success" => false,
"message" =>
"Invalid or expired token"
]);
exit;
}
The JWT generated during login can contain the user ID in the sub claim.
$userId =
$decoded->sub ?? null;
The API should use the verified token to determine the authenticated user.
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
);
The query uses a prepared statement to safely retrieve the profile.
if (!$user) {
http_response_code(404);
echo json_encode([
"success" => false,
"message" => "User not found"
]);
exit;
}
echo json_encode([
"success" => true,
"message" =>
"Profile loaded successfully",
"user" => $user
]);
The API returns the profile as JSON.
A successful response may look like this:
{
"success": true,
"message": "Profile loaded successfully",
"user": {
"id": 101,
"name": "Rahul",
"email": "student@example.com"
}
}
The profile API should never return the user's password or password hash.
For example, avoid:
{
"id": 101,
"name": "Rahul",
"email": "student@example.com",
"password": "$2y$10$..."
}
Only return fields required by the application.
Suppose the mobile application sends:
GET /api/user_profile.php?id=101
If the API trusts this value without checking authentication and authorization, a user might attempt to request another user's profile.
A safer design is to obtain the authenticated user's identity from the verified JWT.
JWT
↓
Verified User ID
↓
Database
↓
Own Profile
const response = await fetch(
"https://example.com/api/user_profile.php",
{
method: "GET",
headers: {
"Authorization":
"Bearer " + token,
"Accept":
"application/json"
}
}
);
const data =
await response.json();
console.log(data);
if (data.success) {
console.log(
"Name:",
data.user.name
);
console.log(
"Email:",
data.user.email
);
}
The returned profile information can be displayed in a React Native profile screen.
if (response.status === 401) {
console.log(
"Please login again"
);
}
A 401 response can indicate that the token is missing, invalid, or expired.
If the token is valid but the user record does not exist, the API can return HTTP 404.
http_response_code(404);
echo json_encode([
"success" => false,
"message" => "User not found"
]);
<?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(404);
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"
]);
}
?>
React Native
↓
Profile Screen
↓
GET Profile API
↓
Authorization Header
↓
PHP API
↓
Verify JWT
↓
Read User ID
↓
MySQL
↓
Fetch User
↓
JSON Response
↓
React Native
↓
Display Profile
Step 1: Login through the JWT login API.
POST
http://localhost/api/jwt_login.php
Step 2: Copy the returned JWT.
Step 3: Open:
GET
http://localhost/api/user_profile.php
Step 4: Add the header:
Authorization:
Bearer YOUR_JWT_TOKEN
Step 5: Send the request.
The API should return the authenticated user's profile.
The User Profile API is a protected endpoint that uses the verified JWT to identify the authenticated user. It retrieves that user's profile from MySQL using PDO and returns safe profile information as JSON. React Native can call this endpoint by sending the JWT in the Authorization header.
React Native
↓
Bearer JWT
↓
User Profile API
↓
Verify JWT
↓
Get User ID
↓
MySQL
↓
Get Profile
↓
JSON Response
Question: How should a protected User Profile API determine which user's profile to return?