Skip to main content
PHP for Beginners
CHAPTER 23 Beginner

PHP Authentication System

Updated: May 12, 2026
40 min read

# Chapter 23: PHP Authentication System

1. Introduction

Welcome to Chapter 23! This is a milestone chapter. Every major application—Facebook, Netflix, Amazon—requires users to create an account, log in securely, and maintain their session. By combining everything we have learned so far (Forms, POST requests, Sessions, Databases, and CRUD), we are going to build a complete Authentication System. The most critical part of this chapter is learning how to securely hash passwords so that even if your database is stolen, user passwords remain safe.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand the concept of one-way Password Hashing.
  • Securely hash passwords using password_hash().
  • Verify user passwords using password_verify().
  • Build a Registration script to save new users.
  • Build a Login script that creates a secure Session.
  • Protect pages so only logged-in users can view them.

3. The Golden Rule of Passwords

NEVER STORE PASSWORDS IN PLAIN TEXT. If you store "mypassword123" in your database, and your server gets hacked, the hacker now has the passwords for all your users. Since people reuse passwords, you just compromised their bank accounts too. Instead, we use Hashing. Hashing is a one-way mathematical algorithm that scrambles a password into an unrecognizable string. It cannot be reversed or "decrypted."

4. Password Hashing in PHP

PHP makes hashing incredibly easy with the built-in password_hash() function. It automatically uses the industry-standard bcrypt algorithm and generates a unique "salt" to prevent rainbow table attacks.
php
123456789
<?php
$user_password = "mypassword123";

// Generate the hash
$hashed_password = password_hash($user_password, PASSWORD_DEFAULT);

echo $hashed_password; 
// Outputs something like: $2y$10$U5.8tH/... random 60 character string
?>

5. Password Verification

If hashing is a one-way street, how do we log someone in? When the user attempts to log in, we pull the hashed string from the database and use password_verify() to see if the password they just typed matches the hash.
php
12345678910
<?php
$attempted_password = "mypassword123";
// $hashed_password is the string we pulled from the database

if (password_verify($attempted_password, $hashed_password)) {
    echo "Login successful!";
} else {
    echo "Incorrect password.";
}
?>

6. Building the Registration System

First, we need a table in our database.
sql
12345
CREATE TABLE accounts (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL
);

Now, the PHP logic for register.php:

php
12345678910111213141516171819202122232425262728
<?php
require &#039;db.php';

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $username = trim($_POST[&#039;username']);
    $password = $_POST[&#039;password'];

    // 1. Hash the password
    $hash = password_hash($password, PASSWORD_DEFAULT);

    // 2. Insert into database using Prepared Statements
    $sql = "INSERT INTO accounts (username, password_hash) VALUES (:username, :hash)";
    $stmt = $pdo->prepare($sql);
    
    try {
        $stmt->execute([&#039;:username' => $username, ':hash' => $hash]);
        echo "Registration successful! You can now log in.";
    } catch (PDOException $e) {
        echo "Error: Username might already exist.";
    }
}
?>
<!-- Basic Registration Form -->
<form method="POST">
    <input type="text" name="username" required>
    <input type="password" name="password" required>
    <button type="submit">Register</button>
</form>

7. Building the Login System

For login.php, we fetch the user by their username, verify the hash, and start a session.
php
12345678910111213141516171819202122232425262728293031
<?php
session_start();
require &#039;db.php';

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $username = trim($_POST[&#039;username']);
    $password = $_POST[&#039;password'];

    // 1. Fetch user from database
    $stmt = $pdo->prepare("SELECT * FROM accounts WHERE username = :username");
    $stmt->execute([&#039;:username' => $username]);
    $user = $stmt->fetch();

    // 2. Verify user exists AND password is correct
    if ($user && password_verify($password, $user[&#039;password_hash'])) {
        // 3. Create Session!
        $_SESSION[&#039;user_id'] = $user['id'];
        $_SESSION[&#039;username'] = $user['username'];
        
        echo "Logged in! Welcome to your dashboard.";
        // Usually, you redirect here: header("Location: dashboard.php");
    } else {
        echo "Invalid username or password.";
    }
}
?>
<form method="POST">
    <input type="text" name="username" required>
    <input type="password" name="password" required>
    <button type="submit">Login</button>
</form>

8. Protecting Pages

Now that we have a session, we can easily protect dashboard.php. Put this at the very top of any protected file.
php
1234567891011
<?php
session_start();

// If the session does not exist, kick them out!
if (!isset($_SESSION[&#039;user_id'])) {
    header("Location: login.php");
    exit(); // Crucial to stop the rest of the page from loading
}

echo "Welcome to the secure area, " . $_SESSION[&#039;username'];
?>

9. Output Explanations

In the login script, $stmt->fetch() attempts to find the username. If the user doesn't exist, $user is false. The if statement checks if ($user && password_verify(...)). This means if $user is false, it instantly stops checking and echoes "Invalid username or password." It deliberately gives the exact same generic error message whether the username was wrong or the password was wrong. This prevents hackers from guessing valid usernames!

10. Common Mistakes

  • Setting the DB password column too short: password_hash() creates a string up to 60-255 characters long. If your MySQL table column is VARCHAR(50), the hash will be cut off, and password_verify will ALWAYS fail. Always use VARCHAR(255) for password columns.
  • Using MD5 or SHA1: Never use md5($password). These are ancient hashing algorithms that can be cracked in milliseconds using modern graphics cards.
  • Forgetting exit(); after a header redirect: If you redirect an unauthorized user but forget exit();, the PHP script continues running on the server, executing sensitive code silently!

11. Best Practices

  • Always trim whitespace from usernames/emails during login and registration.
  • Give generic error messages ("Invalid credentials") rather than specific ones ("Password incorrect").

12. Exercises

  1. 1. Set up the accounts table in your database.
  1. 2. Combine the registration and login code above into two separate working files.
  1. 3. Register an account, verify the hash in phpMyAdmin, and successfully log in.

13. Mini Project: Complete Login/Register System

*(The project is the culmination of the Registration, Login, and Protection scripts provided in Sections 6, 7, and 8. Implement them across register.php, login.php, dashboard.php, and a logout.php file that destroys the session.)*

14. MCQs with Answers

1. Which function securely encrypts a password one-way? A) crypt() B) md5() C) password_hash() D) encode_pass() *Answer: C*

2. Why is exit() necessary after sending a Location header redirect? A) To close the database connection. B) To stop the current script from continuing to execute code in the background. C) To force the browser to refresh. D) It is not necessary. *Answer: B*

3. If a user forgets their password, can you use PHP to un-hash it and email it to them? A) Yes, using password_unhash(). B) No. Hashing is a one-way mathematical function. You must generate a secure password reset link instead. C) Yes, if you have the secret server key. D) Only if you use md5. *Answer: B*

15. Interview Questions

Q: What is a Salt in password hashing, and do you need to generate it manually in PHP? *A:* A Salt is a random string of characters added to a password before hashing. It ensures that two users with the exact same password will have completely different hashes, preventing "Rainbow Table" attacks. In modern PHP, password_hash() automatically generates a unique, cryptographically secure salt for you and embeds it directly into the final hash string.

Q: Explain how to properly restrict access to a PHP page. *A:* Start the session (session_start()). Check if a specific session variable (like $_SESSION['user_id']) is set. If it is not isset(), immediately send an HTTP redirect header (header("Location: login.php")) and instantly terminate the script using exit().

16. FAQs

Q: Can I use $_COOKIE to keep them logged in forever? *A:* You can build a "Remember Me" system using cookies, but you must be very careful. You should store a random, long token in the cookie, hash that token in the database, and verify them against each other. Never store the user's ID or Password in the cookie directly.

17. Summary

You've unlocked the gatekeeper! You successfully built a complete Authentication System. You learned the critical necessity of one-way password hashing using password_hash(), verified user identities using password_verify(), and restricted access to secure pages using Sessions and Header redirects.

18. Next Chapter Recommendation

Users don't just want text accounts; they want avatars! In Chapter 24: PHP File Upload System, we will learn how to handle the $_FILES superglobal, validate image formats, and safely save uploaded files to the server's hard drive!

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·