Categories

AJAX and HTTP Basic Auth

Posted on: October 21, 2015 by Dimitar Ivanov

Problem

Sometimes the access to a web page or resource should be protected. To accomplish the task use a HTTP authentication. The request for such a resource through the XmlHttpRequest interface or Fetch API may hurt user experience since an alert asking for user credentials will appear.

HTTP Authentication

HTTP Authentication provides mechanism to protect web pages and resources.

  • Basic

    The browser sends the username and password as Base64-encoded text, without any encryption. Basic authentication should only be used with HTTPS, otherwise the password can be exposed to everyone.

    If the client request protected resource without providing credentials, the server will reject the request and send back 401 HTTP status and WWW-Authenticate header.

    HTTP/1.1 401 Unauthorized
    WWW-Authenticate: Basic realm="Restricted area"
    

    Then the browser will display popup asking for user credentials used to retry the request with Authorization header.

    Authorization: Basic bXl1c2VyOm15cHN3ZA==
    
  • Digest

    The client sends the hashed variant of the username and password. Encryption instead of encoding makes the digest authentication safer than basic auth.

Request

The solution is quite simple, an Authorization header sent with the request.

<script>
// using jQuery & 'beforeSend' callback
$.ajax({
    xhrFields: {
        withCredentials: true
    },
    beforeSend: function (xhr) {
        xhr.setRequestHeader('Authorization', 'Basic ' + btoa('myuser:mypswd'));
    },
    url: "https://www.example.org/protected-data.php"
});

// using jQuery & 'headers' property
$.ajax({
    xhrFields: {
        withCredentials: true
    },
    headers: {
        'Authorization': 'Basic ' + btoa('myuser:mypswd')
    },
    url: "https://www.example.org/protected-data.php"
});

// using XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://www.example.org/protected-data.php", true);
xhr.withCredentials = true;
xhr.setRequestHeader("Authorization", 'Basic ' + btoa('myuser:mypswd'));
xhr.onload = function () {
    console.log(xhr.responseText);
};
xhr.send();

// using Fetch API
var myHeaders = new Headers();
myHeaders.append("Authorization", 'Basic ' + btoa('myuser:mypswd'));
fetch("https://www.example.org/protected-data.php", {
    credentials: "include",
    headers: myHeaders
}).then(function (response) {
    return response.json();
}).then(function (json) {
    console.log(json);
});
</script>

jQuery API provides username and password parameters as part of the ajax settings object, which intends to do the job instead of sending a header by yourself, unfortunatelly they doesn't works.

Response

To trigger the basic authentication use your prefered method.

  • PHP
    <?php
    if (!(isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) 
        && $_SERVER['PHP_AUTH_USER'] == 'myuser' 
        && $_SERVER['PHP_AUTH_PW'] == 'mypswd')) {
        header('WWW-Authenticate: Basic realm="Restricted area"');
        header('HTTP/1.1 401 Unauthorized');
        exit;
    }
    ?>
    
  • Apache
    AuthType Basic
    AuthName "Restricted area"
    AuthUserFile "/var/www/.htpasswd"
    Require valid-user
    
  • Nginx
    auth_basic "Restricted area";
    auth_basic_user_file /var/www/.htpasswd;
    

htpasswd is used to create and update the flat-files used to store usernames and password for basic authentication of HTTP users.

htpasswd -c /var/www/.htpasswd myuser

Cross-Domain Requests with CORS

In case, the protected resource or page is accessible through a domain that differs from the origin, a restriction from same origin policy is applied. To circumvent the same-origin policy, use the Cross-origin resource sharing.

# Request Headers
Authorization: Basic bXl1c2VyOm15cHN3ZA==
Host: subdomain.example.org
Origin: https://www.example.org

# Response Headers
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin, Authorization
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Origin: https://www.example.org
P3P:CP="CAO PSA OUR"

Demo

To see an example of ajax basic auth check out our demo.

Make your website more secure by using the HTTP Headers for Wordpress, and never face a cross-origin issue again. Oh yes, it's FREE.
See also
Share this post

If you have questions about the ajax basic authentication, please leave a comment below. And do not be shy to share this article. Thanks so much for reading!


5 Comments

Steven Collins
Hi, thanks for this link from code crunch.
We made a business decision not to support IE9 and below.
We overcome the btoa issue by using base64.js but it was the authorization that wouldnt send in IE9.
Nikola
I am not sure why would you want to put in your username and password into ajax call. Are you crazy. Making them base64 encoded will not protect you.

Just can not belive that people are writing this kind of things.
Dimitar Ivanov
@Nikola, what's wrong with base64 encoding? This is how the specification works. Note that HTTP Basic Authentication protect server resources. To protect your credentials you need to use SSL encryption (HTTPS)
Nikola
So, i go to your website. Click View source and there base64 decode your btoa string and get username and password for protected area? Whats wrong with you?
Dimitar Ivanov
I understand your point of view and I agree that hard coded data can not be hidden. But this article aims to show how to make the request only, not how to collect user data. Do not expect just to copy/paste my example in real life app without modification. However, nothing related with base64 encoding is changed.

Leave a comment

Captcha