Login & Authentication Basics
Authentication is the process of confirming that a visitor really is who they claim to be, usually by checking a password against one stored for that account. In plain PHP this comes down to a handful of pieces working together: a login form, a lookup against stored user data, a password comparison that never touches a plaintext password, a session that remembers the result, and a way to protect pages so only logged-in visitors can reach them. This page walks through a complete, minimal version of that flow.
Never store or compare plaintext passwords
A user's real password should never be saved anywhere, including in your database. Instead, PHP's password_hash() turns a password into a salted, one-way hash at signup time, and password_verify() checks a login attempt against that hash without ever needing the original password back. Both functions currently use the bcrypt algorithm by default and handle the salt automatically, so there is no separate salt to generate, store, or lose track of.
Hashing a password at signup time
<?php $plainPassword = $_POST['password']; // from the signup form $hash = password_hash($plainPassword, PASSWORD_DEFAULT); // $hash is what gets saved in the database — never $plainPassword // e.g. INSERT INTO users (email, password_hash) VALUES (?, ?)
The login form
A simple login form
<form method="post" action="/login.php"> <label for="email">Email</label> <input type="email" id="email" name="email" required> <label for="password">Password</label> <input type="password" id="password" name="password" required> <button type="submit">Log in</button> </form>
Verifying the credentials
The login script looks the account up by email (never by trusting an id or role sent from the client), then hands the submitted password and the stored hash to password_verify(). Only if that returns true is the visitor considered authenticated. The database lookup below is mocked for clarity — in a real application it would be a parameterized query against your users table.
login.php
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = trim($_POST['email'] ?? '');
$password = $_POST['password'] ?? '';
// Mocked DB lookup — in real code this is a prepared statement, e.g.
// SELECT id, email, password_hash FROM users WHERE email = ?
$user = findUserByEmail($email);
if ($user !== null && password_verify($password, $user['password_hash'])) {
// Correct credentials: rotate the session id before trusting it
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
$_SESSION['email'] = $user['email'];
header('Location: /dashboard.php');
exit;
}
$error = 'Invalid email or password.';
}Why session_regenerate_id() runs right after login
This is the same defense covered on the session security page: calling session_regenerate_id(true) the moment a visitor proves who they are prevents session fixation, where an attacker could otherwise have handed the victim a known session id before login and then reused that same id afterward. It costs one function call and closes off an entire class of attack.
Guarding protected pages
Every page that should only be visible to logged-in visitors needs to check for a valid session before rendering anything sensitive. A small reusable guard function keeps that check consistent across the whole application instead of it being copied, and possibly forgotten, on individual pages.
A reusable requireLogin() guard
<?php
function requireLogin(): void
{
if (empty($_SESSION['user_id'])) {
header('Location: /login.php');
exit;
}
}dashboard.php
<?php session_start(); require_once 'guards.php'; requireLogin(); // exits early if not logged in echo 'Welcome back, ' . htmlspecialchars($_SESSION['email'], ENT_QUOTES, 'UTF-8');
Welcome back, aisha@example.com
Logging out
Logging out should undo everything the login flow set up: clear the session data, destroy the server-side session, and remove the session cookie so a copied or reused cookie value cannot be replayed afterward.
logout.php
<?php
session_start();
$_SESSION = [];
session_unset();
session_destroy();
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(
session_name(),
'',
time() - 42000,
$params['path'],
$params['domain'],
$params['secure'],
$params['httponly']
);
}
header('Location: /login.php');
exit;Putting the whole flow together
Store only a
password_hash()output at signup, never the plaintext password.On login, look the user up server-side and check their password with
password_verify().Call
session_regenerate_id(true)immediately after a successful login.Store only an internal identifier (like
user_id) in$_SESSION, not sensitive data.Protect every restricted page with a shared
requireLogin()-style guard, called before any output.On logout, clear
$_SESSION, callsession_destroy(), and expire the session cookie.