In this lesson, we will create the login API for our Student Management mobile application.
The login API will receive the user's email and password, find the corresponding user in MySQL, verify the password, and prepare the authentication response.
React Native Login Screen
↓
Axios POST
↓
PHP API
↓
Find User by Email
↓
Verify Password
↓
Create Response
↓
React Native
JWT authentication will be added to the login process in the next project lesson.
Create a PHP file named:
login.php
The mobile application will send:
POST /api/login.php
The React Native application will send email and password as JSON.
{
"email": "rahul@example.com",
"password": "secret123"
}
header(
"Content-Type: application/json"
);
This tells the client that the API response is JSON.
require_once '../config/database.php';
The PHP API will use the PDO connection created for the
student_management database.
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode([
"success" => false,
"message" => "Method not allowed"
]);
exit;
}
Login creates an authentication response, so POST is appropriate.
$input = json_decode(
file_get_contents("php://input"),
true
);
The JSON request body is converted into a PHP associative array.
$email = trim($input['email'] ?? '');
$password = $input['password'] ?? '';
The null coalescing operator prevents errors when fields are missing.
if ($email === '' || $password === '') {
http_response_code(422);
echo json_encode([
"success" => false,
"message" => "Email and password are required"
]);
exit;
}
if (!filter_var(
$email,
FILTER_VALIDATE_EMAIL
)) {
http_response_code(422);
echo json_encode([
"success" => false,
"message" => "Invalid email address"
]);
exit;
}
The API should find the registered user using a prepared statement.
$stmt = $pdo->prepare(
"SELECT id, name, email, password, role
FROM users
WHERE email = ?"
);
$stmt->execute([$email]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
If no user is found, the login should fail.
if (!$user) {
http_response_code(401);
echo json_encode([
"success" => false,
"message" => "Invalid email or password"
]);
exit;
}
A generic message is preferable to revealing whether a particular email address exists.
The stored password is a hash. We should use
password_verify() to compare the submitted password
with that hash.
if (!password_verify(
$password,
$user['password']
)) {
http_response_code(401);
echo json_encode([
"success" => false,
"message" => "Invalid email or password"
]);
exit;
}
At this point:
Email exists
+
Password is correct
↓
Authentication successful
The next step is to create a safe response for the mobile application.
We can return information such as:
id
name
email
role
The password hash must never be included in the API response.
http_response_code(200);
echo json_encode([
"success" => true,
"message" => "Login successful",
"data" => [
"id" => $user['id'],
"name" => $user['name'],
"email" => $user['email'],
"role" => $user['role']
]
]);
{
"success": true,
"message": "Login successful",
"data": {
"id": 1,
"name": "Rahul Kumar",
"email": "rahul@example.com",
"role": "user"
}
}
JWT authentication will later add a token to this response.
{
"success": false,
"message": "Invalid email or password"
}
The same generic message can be used for an unknown email or an incorrect password.
| Status | Meaning |
|---|---|
| 200 | Login successful |
| 401 | Invalid authentication credentials |
| 422 | Invalid request data |
| 405 | Method not allowed |
| 500 | Server error |
<?php
header(
"Content-Type: application/json"
);
require_once '../config/database.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode([
"success" => false,
"message" => "Method not allowed"
]);
exit;
}
$input = json_decode(
file_get_contents("php://input"),
true
);
$email = trim($input['email'] ?? '');
$password = $input['password'] ?? '';
if ($email === '' || $password === '') {
http_response_code(422);
echo json_encode([
"success" => false,
"message" =>
"Email and password are required"
]);
exit;
}
if (!filter_var(
$email,
FILTER_VALIDATE_EMAIL
)) {
http_response_code(422);
echo json_encode([
"success" => false,
"message" => "Invalid email address"
]);
exit;
}
try {
$stmt = $pdo->prepare(
"SELECT id, name, email, password, role
FROM users
WHERE email = ?"
);
$stmt->execute([$email]);
$user = $stmt->fetch(
PDO::FETCH_ASSOC
);
if (!$user ||
!password_verify(
$password,
$user['password']
)) {
http_response_code(401);
echo json_encode([
"success" => false,
"message" =>
"Invalid email or password"
]);
exit;
}
http_response_code(200);
echo json_encode([
"success" => true,
"message" => "Login successful",
"data" => [
"id" => $user['id'],
"name" => $user['name'],
"email" => $user['email'],
"role" => $user['role']
]
]);
} catch (PDOException $e) {
error_log($e->getMessage());
http_response_code(500);
echo json_encode([
"success" => false,
"message" => "Server error"
]);
}
const [email, setEmail] =
useState("");
const [password, setPassword] =
useState("");
const [loading, setLoading] =
useState(false);
These states can be connected to TextInput controls and a login button.
interface LoginRequest {
email: string;
password: string;
}
This interface describes the JSON data sent to the login API.
interface LoginResponse {
success: boolean;
message: string;
data?: {
id: number;
name: string;
email: string;
role: string;
};
}
Later, a JWT token property will be added to the response interface.
const response =
await api.post<LoginResponse>(
"/login.php",
{
email,
password
}
);
console.log(response.data);
The Axios request sends the login credentials to the PHP API.
if (response.data.success) {
const user =
response.data.data;
console.log(user);
// Navigate to student screen
}
Once the login is successful, the application can navigate to the authenticated part of the application.
try {
const response =
await api.post<LoginResponse>(
"/login.php",
{
email,
password
}
);
} catch (error) {
console.log(
"Login failed"
);
}
A reusable Axios error handler can later display API validation or authentication messages.
Test the login API before connecting it to React Native.
Method: POST
URL:
https://example.com/api/login.php
Body → raw → JSON:
{
"email": "rahul@example.com",
"password": "secret123"
}
A valid user should receive HTTP 200 with safe user information.
password_verify() for password checking.Login Screen
↓
Email + Password
↓
Axios POST
↓
PHP login.php
↓
Find User
↓
password_verify()
↓
Authentication Success
↓
User JSON
↓
React Native
In the next lesson, we will improve this flow by generating a JWT after successful authentication.
The login API is responsible for verifying the identity of a registered user.
password_verify() checks the password.After JWT is added, the mobile application will be able to access protected student APIs securely.
php://input.password_verify() checks the submitted password against the stored hash.Question: Which PHP function should be used to verify a user's submitted password against the stored password hash?