HTTP Basic Auth can help you authenticate users for certain webpages without having to put too much effort in building registration or login systems. There are cases, when all you need is a simple authentication mechanism and the webpage does not contain the most sensitive types of data and adding extra dependencies or typing code for hours or day is not worth it. Then, HTTP Basic Auth comes to the rescue!
HTTP Basic Auth can be used to request a username and a password from users before showing them the page. There are several ways to do it, you can set your own .htpasswd file and request credentials for folders by adding several lines to the .htaccess file or you can just do it all with PHP and no .htpasswd or .htaccess.
We will start developing a tool that will authenticate your users with HTTP Basic Auth in incremental steps.
In the first snippet, we check if the array key in the $_SERVER superglobal called PHP_AUTH_USER is set. If it is not set, then we know that the user has not been authenticated or has not attempted to authenticate yet.
Therefore, we send the necessary headers that will instruct his browsers to show him a prompt box requesting a username and password. If he has attempted to authenticate, we first check if the username is present in the hardcoded array as a key. If it is present in the array, we check to see if the passwords match and if they do not match we stop further code execution. Otherwise, nothing happens and the page renders (in our case, Hello, Authenticated User. Is shown).
Snippet 1
<?php
//Auth 1 - HTTP Basic Auth with 1 user attempt per browsing session (only 1 if he uses a regular browser)
if (!isset($_SERVER['PHP_AUTH_USER'])) {
// send headers for the browser to show an authentication prompt box
header('WWW-Authenticate: Basic realm="My Website Auth"');
header('HTTP/1.0 401 Unauthorized');
//logic to send if the users cancels authentication
echo "Credentials are required to access the webpage!";
exit;
} else {
//we hardcode users and passwords in an array
//we can get them from a database instead
$users = array("courage" => "dog", "girls" => "
", "eric" => "cartman");
if (!array_key_exists($_SERVER["PHP_AUTH_USER"], $users) ||
$users[$_SERVER["PHP_AUTH_USER"]] !== $_SERVER['PHP_AUTH_PW']) {
//stop scripts from processing any further - best to place at the top of your scripts logic
//instead, you can set a variable and do not show some sections of the webpage or show something else
//finally you can reask for credentials instead of preventing further code execution
echo "Improper credentials";
exit;
}
}
?>
<h1>Hello, Authenticated User.</h1>
Next, we edit the case when the user has attempted to authenticate himself by adding the headers in that case as well. This will allow the user to try to authenticate as much times as he like. In the previous case, once he entered incorrect credentials he would have to restart his browser.
Snippet 2
if (!array_key_exists($_SERVER["PHP_AUTH_USER"], $users) ||
$users[$_SERVER["PHP_AUTH_USER"]] !== $_SERVER['PHP_AUTH_PW']) {
//stop scripts from processing any further - best to place at the top of your scripts logic
//instead, you can set a variable and do not show some sections of the webpage or show something else
//finally you can reask for credentials instead of preventing further code execution
header('WWW-Authenticate: Basic realm="My Website Auth"');
header('HTTP/1.0 401 Unauthorized');
echo "Improper credentials";
exit;
}
Moving to OOP
Now, let us edit the code above to use OOP and be more useful. We will create a separate namespace and create a class in it called BasicAuth. You can rename it and add more authentication mechanisms to it. We create a private variable called $users which is empty. When the class is initialized, we either set $users to be an array with default usernames and passwords or use the one given by the user. This would allow the user to request different usernames and passwords for every page and time he requests authentication. Finally, we call the authenticate method.
<?php
//Auth 3 - HTTP Basic Auth in OOP with infinite users attempts per browsing session.
namespace Authenticate;
class BasicAuth {
//we hardcode users and passwords in an array
//we can get them from a database instead
private $users = array();
public function __construct($users = array("courage" => "dog", "girls" => "powerpuff", "eric" => "cartman")) {
$this->users = $users;
$this->authenticate();
}
The authenticate method does the things we have seen before but calls another method, setAuthHeaders which would set the necessary headers so we do not have to add them in two different places.
private function authenticate() {
if (!isset($_SERVER['PHP_AUTH_USER'])) {
$this->setAuthHeaders();
//logic to send if the users cancels authentication
echo "Credentials are required to access the webpage!";
exit;
} else {
if (!array_key_exists($_SERVER["PHP_AUTH_USER"], $this->users) ||
$this->users[$_SERVER["PHP_AUTH_USER"]] !== $_SERVER['PHP_AUTH_PW']) {
$this->setAuthHeaders();
echo "Improper credentials";
exit;
}
}
}
private function setAuthHeaders() {
// send headers for the browser to show an authentication prompt box
header('WWW-Authenticate: Basic realm="My Website Auth"');
header('HTTP/1.0 401 Unauthorized');
}
Finally, to use the class and protect your page with arbitrary passwords all you have to do is add a few lines to the top of your existing page:
<?php
require_once("BasicAuth.php");
$auth = new Authenticate\BasicAuth(array("tokyo" => 'drift', "drift" => 'tokyo'), "DRQKQDDD");
//app's logic continues and will be shown only if the user is authenticated
?>
<h1>Welcome Again, Authenticated User.</h1>
HTTP Basic Auth is fast, provides a little bit of extra security and there is no reason why not to use it when the project you are working on is small and you need to prevent it from being public.