Lesson 67 of 158 – Password Hashing
67%

Password Hashing

Password hashing is an important security concept when building user registration and login APIs. A password should never be stored directly in the database. Instead, PHP can create a secure password hash using password_hash().

Note: Hashing is one-way. You normally do not decrypt a password hash. During login, PHP verifies the entered password against the stored hash using password_verify().

1. What is Password Hashing?

Password hashing converts a plain-text password into a hash value that can be safely stored in a database.

Plain Password
      ↓
password_hash()
      ↓
Password Hash
      ↓
MySQL Database

The original password is not stored directly.

2. Why Should Passwords Be Hashed?

If a database is exposed, storing plain-text passwords can put users' accounts at serious risk.

  • Passwords should not be stored as plain text.
  • Hashing protects stored password values.
  • Different users can have different password hashes.
  • The application can verify passwords without storing the original password.

3. Hashing vs Encryption

Hashing Encryption
Designed to be one-way Designed to be reversible with a key
Used for password storage Used when data needs to be recovered
Verified against the original input Decrypted back to readable data

For passwords, PHP's password hashing functions are the appropriate approach.

4. password_hash()

PHP provides the password_hash() function for creating password hashes.

$password = "MyPassword123";

$hash = password_hash(
    $password,
    PASSWORD_DEFAULT
);

5. PASSWORD_DEFAULT

PASSWORD_DEFAULT tells PHP to use its recommended default password hashing algorithm.

$hash = password_hash(
    $password,
    PASSWORD_DEFAULT
);

Using PASSWORD_DEFAULT also allows PHP's recommended algorithm to evolve over time.

6. Example Password Hash

$password = "Hello123";

$hash = password_hash(
    $password,
    PASSWORD_DEFAULT
);

echo $hash;

The output is a password hash rather than the original password.

7. Hashing the Same Password

Calling password_hash() multiple times can produce different hashes for the same password because the hashing process includes a unique salt.

$password = "Hello123";

$hash1 = password_hash(
    $password,
    PASSWORD_DEFAULT
);

$hash2 = password_hash(
    $password,
    PASSWORD_DEFAULT
);

Both hashes can still be verified against the same original password.

8. What is a Salt?

A salt is additional random data incorporated into the password hashing process. PHP's password hashing functions manage the salt automatically.

$hash = password_hash(
    "Hello123",
    PASSWORD_DEFAULT
);

You do not need to manually create and store a separate salt when using password_hash().

9. Store the Hash, Not the Password

During registration, store the generated hash in the password column.

$password = $data['password'];

$hashedPassword = password_hash(
    $password,
    PASSWORD_DEFAULT
);

$stmt = $pdo->prepare(
    "INSERT INTO users
    (name, email, password)
    VALUES (?, ?, ?)"
);

$stmt->execute([
    $name,
    $email,
    $hashedPassword
]);

10. Never Store Plain Passwords

Avoid storing passwords like this:

// Do NOT do this

$stmt->execute([
    $name,
    $email,
    $password
]);

Instead, create a hash first.

$hashedPassword = password_hash(
    $password,
    PASSWORD_DEFAULT
);

11. password_verify()

During login, PHP can verify a plain password against the stored hash using password_verify().

if (password_verify(
    $password,
    $storedHash
)) {

    echo "Password is correct";

}

12. How password_verify() Works

Entered Password
       ↓
password_verify()
       ↓
Stored Password Hash
       ↓
Match?
  ┌────┴────┐
 Yes       No
  ↓          ↓
Login     Reject

The application does not need to decrypt the stored hash.

13. Basic Login Verification

$password = "Hello123";

$storedHash = $user['password'];

if (password_verify(
    $password,
    $storedHash
)) {

    echo "Login successful";

} else {

    echo "Invalid password";
}

14. Fetch User During Login

During login, the API can find the user by email.

$stmt = $pdo->prepare(
    "SELECT * FROM users
     WHERE email = ?"
);

$stmt->execute([$email]);

$user = $stmt->fetch(
    PDO::FETCH_ASSOC
);

15. Check User Exists

if (!$user) {

    http_response_code(401);

    echo json_encode([
        "success" => false,
        "message" => "Invalid email or password"
    ]);

    exit;
}

It is common to use a general authentication error message rather than revealing whether an email address exists.

16. Verify Password During Login

if (!password_verify(
    $password,
    $user['password']
)) {

    http_response_code(401);

    echo json_encode([
        "success" => false,
        "message" => "Invalid email or password"
    ]);

    exit;
}

17. Successful Password Verification

if (password_verify(
    $password,
    $user['password']
)) {

    echo json_encode([
        "success" => true,
        "message" => "Password verified"
    ]);
}

In a real authentication API, successful verification would normally be followed by an authentication step such as creating a token.

18. Password Hash in Database

The database should contain the generated password hash.

Column Example Value
email rahul@example.com
password Generated password hash

The original password should not be stored in the password column.

19. Password Column Length

The password column should have enough capacity to store the hash generated by PHP.

password VARCHAR(255)

A 255-character VARCHAR is commonly used for password hashes generated by PHP's password hashing functions.

20. Validate Password Before Hashing

The password should be validated before it is hashed.

$password = $data['password'] ?? '';

if ($password === '') {

    sendError(
        400,
        "Password is required"
    );
}

if (strlen($password) < 6) {

    sendError(
        422,
        "Password must be at least 6 characters"
    );
}

21. Password Hashing in Registration API

$hashedPassword = password_hash(
    $password,
    PASSWORD_DEFAULT
);

$stmt = $pdo->prepare(
    "INSERT INTO users
    (name, email, password)
    VALUES (?, ?, ?)"
);

$stmt->execute([
    $name,
    $email,
    $hashedPassword
]);

This is the basic password storage process.

22. Password Verification in Login API

$stmt = $pdo->prepare(
    "SELECT * 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;
}

23. password_needs_rehash()

PHP also provides password_needs_rehash(). It can be used to determine whether an existing password hash should be updated to the current hashing configuration.

if (password_needs_rehash(
    $user['password'],
    PASSWORD_DEFAULT
)) {

    // Generate a new hash
}

24. Complete Password Flow

REGISTRATION

Plain Password
      ↓
password_hash()
      ↓
Hash
      ↓
MySQL


LOGIN

Entered Password
      ↓
password_verify()
      ↓
Stored Hash
      ↓
Match?
  ┌───┴───┐
 Yes     No
  ↓       ↓
Login   Reject

25. Test Hashing in PHP

<?php

$password = "Hello123";

$hash = password_hash(
    $password,
    PASSWORD_DEFAULT
);

echo "Hash: " . $hash;

if (password_verify(
    $password,
    $hash
)) {

    echo "<br>Password is correct";

}

?>

This simple example demonstrates the complete hashing and verification process.

26. React Native and Passwords

The React Native application sends the password securely to the API over HTTPS during registration or login.

fetch(url, {

    method: "POST",

    headers: {
        "Content-Type": "application/json"
    },

    body: JSON.stringify({
        email: email,
        password: password
    })

});

The server is responsible for hashing the password during registration.

27. Never Return the Password Hash

The password hash should not be returned in normal API responses.

// Avoid

echo json_encode([
    "success" => true,
    "user" => $user
]);

If $user contains the password field, the hash could be exposed. Select only the fields that the client actually needs.

echo json_encode([
    "success" => true,
    "user" => [
        "id" => $user['id'],
        "name" => $user['name'],
        "email" => $user['email']
    ]
]);

28. Complete Registration Password Code

<?php

$password = $data['password'] ?? '';

if ($password === '') {

    sendError(
        400,
        "Password is required"
    );
}

if (strlen($password) < 6) {

    sendError(
        422,
        "Password must be at least 6 characters"
    );
}

$hashedPassword = password_hash(
    $password,
    PASSWORD_DEFAULT
);

$stmt = $pdo->prepare(
    "INSERT INTO users
    (name, email, password)
    VALUES (?, ?, ?)"
);

$stmt->execute([
    $name,
    $email,
    $hashedPassword
]);

http_response_code(201);

echo json_encode([
    "success" => true,
    "message" => "Registration successful"
]);

?>

29. Password Hashing Best Practices

  • Never store plain-text passwords.
  • Use password_hash() for password hashing.
  • Use PASSWORD_DEFAULT unless you have a specific reason to choose another supported algorithm.
  • Use password_verify() during login.
  • Do not try to decrypt password hashes.
  • Validate passwords before hashing them.
  • Use HTTPS for registration and login requests.
  • Never return password hashes in API responses.
  • Keep the password database column large enough for the generated hash.
  • Use generic authentication error messages where appropriate.
  • Use prepared statements when storing user information.

30. Password Hashing Summary

Password hashing protects user passwords when they are stored in a database. During registration, PHP uses password_hash() to create the hash. During login, PHP uses password_verify() to compare the entered password with the stored hash.

REGISTRATION

Password
   ↓
password_hash()
   ↓
Hash
   ↓
Database


LOGIN

Password
   ↓
password_verify()
   ↓
Stored Hash
   ↓
Authentication Result

📌 Key Points

  • Password hashing protects passwords stored in a database.
  • Passwords should never be stored as plain text.
  • PHP provides password_hash() for creating password hashes.
  • PASSWORD_DEFAULT can be used with password_hash().
  • Password hashing is designed to be one-way.
  • PHP automatically handles the salt when using password_hash().
  • password_verify() checks a password against a stored hash.
  • You do not need to decrypt a password hash.
  • password_needs_rehash() can help update hashes when needed.
  • Password validation should happen before hashing.
  • Prepared statements should be used when storing user data.
  • The password hash should not be returned in API responses.
  • HTTPS should be used when sending passwords between a mobile app and API.
  • Generic login error messages can avoid revealing account information.
  • Secure password handling is an important part of REST API authentication.

🧠 Quick Quiz

Question: Which PHP function is used to verify a password against a stored password hash?