Want some programming help? [close]

HTTP Basic Authentication with PHP

Introduction

There many ways of performing authentication over the web. You can use a token and pass it as a special header. This is commonly done with API tokens. You can also use a cookie to store a session token. This is common for webservers that have a database session in the backend.

One simple method is to use HTTP Basic Access Authentication. This involves adding a header that contains your username and password. The proper format for the header is:

Authorization: Basic XXXXXX

Where XXXXXX is your credentials in the form of username:password with base64 encoding.

PHP automatically decodes and splits the username and password into special named constants:

  • PHP_AUTH_USER with the username as a plain-text string
  • PHP_AUTH_PW with the password as a plain-text string

We will look at how to restrict a page using HTTP basic authentication in PHP.

Example of HTTP Basic Auth

<?php

// https://www.php.net/manual/en/features.http-auth.php

// First check if a username was provided.
if (!isset($_SERVER['PHP_AUTH_USER'])) {
    // If no username provided, present the auth challenge.
    header('WWW-Authenticate: Basic realm="My Website"');
    header('HTTP/1.0 401 Unauthorized');
    // User will be presented with the username/password prompt
    // If they hit cancel, they will see this access denied message.
    echo '<p>Access denied. You did not enter a password.</p>';
    exit; // Be safe and ensure no other content is returned.
}

// If we get here, username was provided. Check password.
if ($_SERVER['PHP_AUTH_PW'] == '$ecret') {
    echo '<p>Access granted. You know the password!</p>';
} else {
    echo '<p>Access denied! You do not know the password.</p>';
}

Hashing passwords

Really, you should never be storing passwords in plain-text. If you are storing user account information in a file or a database, the password should be hashed with a salt and each user should have a unique salt. The salt will be useful if the database is ever compromised by making it harder to crack the passwords by reducing the effectiveness of rainbow tables. It will also reduce the amount of identical hashes caused by people using the same password.

PHP's password_hash() can take care of the hashing and the salt generation. Here is a quick example, but you can read more about Safe Password Hashing.

You use password_hash() to generate the hash that you want to store in your database or password file. This will include the salt.

When a user attempts to authenticate and they provide a password, you use crypt() and pass it the user-supplied password along with your stored hash and then compare that to the stored hash. See the example below.

<?php

// Store this in your database or password file associated with the user
$hashed_password = password_hash('my_secret_password', PASSWORD_DEFAULT);

// Use the password provided from HTTP basic auth
$user_supplied_password = $_SERVER['PHP_AUTH_PW'];

// Check if password hashes match
if ($hashed_password == crypt($user_supplied_password, $hashed_password)) { 
    echo 'Password is correct';
} else {
    echo 'Password incorrect.';
}

Testing with curl

If you want to test, an easy way to send an HTTP request with a properly formatted header is with curl. It has a convenient --user option you can set like this:

curl --user my_username:my_password http://localhost:8000/

Conclusion

After reading this, you should understand how to restrict a page using simple HTTP basic authentication in PHP.

References

Advertisement