Authenticate a submitted password against a stored password_hash value and establish a fresh session.
The examples focus on the operation itself, including the important distinction: A login session proves an authenticated request; a database row stores account details.
What It Does
Use the examples below to observe the behavior on a small dataset before extending it to application code.
Before You Start
The examples use PHP 8.2+ features where shown. Database snippets require the corresponding PDO driver, demo tables, and credentials configured outside source code.
Example 1: Basic Use
Use HTTPS and a form that receives a session-specific CSRF token. For production also add rate limits, account lockout policy, and server-side session expiry. The users table needs a password_hash column.
<?php
session_set_cookie_params(["secure" => true, "httponly" => true, "samesite" => "Lax"]);
session_start();
if (($_SERVER["REQUEST_METHOD"] ?? "") !== "POST") { http_response_code(405); exit; }
$token = $_POST["csrf"] ?? "";
if (!is_string($token) || !hash_equals($_SESSION["csrf"] ?? "", $token) || $token === "") { http_response_code(403); exit; }
$email = filter_var($_POST["email"] ?? "", FILTER_VALIDATE_EMAIL);
$password = $_POST["password"] ?? "";
if ($email === false || !is_string($password)) { http_response_code(422); exit; }
$pdo = new PDO(
"mysql:host=" . (getenv("DB_HOST") ?: "127.0.0.1") . ";dbname=" . (getenv("DB_NAME") ?: "demo") . ";charset=utf8mb4",
getenv("DB_USER") ?: "app",
getenv("DB_PASSWORD") ?: "",
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false]
);
$stmt = $pdo->prepare("SELECT id, password_hash FROM users WHERE email = ? LIMIT 1");
$stmt->execute([$email]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user && password_verify($password, $user["password_hash"])) {
session_regenerate_id(true);
$_SESSION["user_id"] = (int) $user["id"];
echo "Authenticated";
} else { http_response_code(401); echo "Invalid credentials"; }
This example is meant for a configured application environment; output depends on the installed extension, external service, or database contents.
Example 2: Checking Behavior
Use HTTPS and a form that receives a session-specific CSRF token. For production also add rate limits, account lockout policy, and server-side session expiry. The users table needs a password_hash column. SameSite=Strict is an option for login forms that do not require cross-site navigation to retain cookies.
<?php
session_set_cookie_params(["secure" => true, "httponly" => true, "samesite" => "Strict"]);
session_start();
if (($_SERVER["REQUEST_METHOD"] ?? "") !== "POST") { http_response_code(405); exit; }
$token = $_POST["csrf"] ?? "";
if (!is_string($token) || !hash_equals($_SESSION["csrf"] ?? "", $token) || $token === "") { http_response_code(403); exit; }
$email = filter_var($_POST["email"] ?? "", FILTER_VALIDATE_EMAIL);
$password = $_POST["password"] ?? "";
if ($email === false || !is_string($password)) { http_response_code(422); exit; }
$pdo = new PDO(
"mysql:host=" . (getenv("DB_HOST") ?: "127.0.0.1") . ";dbname=" . (getenv("DB_NAME") ?: "demo") . ";charset=utf8mb4",
getenv("DB_USER") ?: "app",
getenv("DB_PASSWORD") ?: "",
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false]
);
$stmt = $pdo->prepare("SELECT id, password_hash FROM users WHERE email = ? LIMIT 1");
$stmt->execute([$email]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user && password_verify($password, $user["password_hash"])) {
session_regenerate_id(true);
$_SESSION["user_id"] = (int) $user["id"];
echo "Authenticated";
} else { http_response_code(401); echo "Invalid credentials"; }
This example is meant for a configured application environment; output depends on the installed extension, external service, or database contents.
Example 3: Practical Example
Use HTTPS and a form that receives a session-specific CSRF token. For production also add rate limits, account lockout policy, and server-side session expiry. The users table needs a password_hash column. session_write_close releases the session lock after the authentication result is stored.
<?php
session_set_cookie_params(["secure" => true, "httponly" => true, "samesite" => "Lax"]);
session_start();
if (($_SERVER["REQUEST_METHOD"] ?? "") !== "POST") { http_response_code(405); exit; }
$token = $_POST["csrf"] ?? "";
if (!is_string($token) || !hash_equals($_SESSION["csrf"] ?? "", $token) || $token === "") { http_response_code(403); exit; }
$email = filter_var($_POST["email"] ?? "", FILTER_VALIDATE_EMAIL);
$password = $_POST["password"] ?? "";
if ($email === false || !is_string($password)) { http_response_code(422); exit; }
$pdo = new PDO(
"mysql:host=" . (getenv("DB_HOST") ?: "127.0.0.1") . ";dbname=" . (getenv("DB_NAME") ?: "demo") . ";charset=utf8mb4",
getenv("DB_USER") ?: "app",
getenv("DB_PASSWORD") ?: "",
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false]
);
$stmt = $pdo->prepare("SELECT id, password_hash FROM users WHERE email = ? LIMIT 1");
$stmt->execute([$email]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user && password_verify($password, $user["password_hash"])) {
session_regenerate_id(true);
$_SESSION["user_id"] = (int) $user["id"];
echo "Authenticated";
} else { http_response_code(401); echo "Invalid credentials"; }
session_write_close();
This example is meant for a configured application environment; output depends on the installed extension, external service, or database contents.
Important Behavior and Edge Cases
Use password_verify, session_regenerate_id(true), secure cookies, CSRF protection and rate limiting; never store plaintext passwords.
Comparison with Related Approaches
| Approach | Difference |
|---|---|
| Creating a Database-Backed Login System | Authenticate a submitted password against a stored password_hash value and establish a fresh session. |
| Related API or alternative | A login session proves an authenticated request; a database row stores account details. |
Common Beginner Mistakes
| Mistake | Correct approach |
|---|---|
| Ignoring the operation-specific limits | Use password_verify, session_regenerate_id(true), secure cookies, CSRF protection and rate limiting; never store plaintext passwords. |
| Confusing it with a related API | A login session proves an authenticated request; a database row stores account details. |
Key Takeaways
- Authenticate a submitted password against a stored password_hash value and establish a fresh session.
- Use password_verify, session_regenerate_id(true), secure cookies, CSRF protection and rate limiting; never store plaintext passwords.
- A login session proves an authenticated request; a database row stores account details.
Use Creating a Database-Backed Login System when its documented behavior matches the problem. Test the relevant edge cases in your own runtime before deploying it.