Using Basic HTTP access authentication in Django testing framework

PythonDjangoUnit TestingHttp AuthenticationDjango Testing

Python Problem Overview


For some of my Django views I've created a decorator that performs Basic HTTP access authentication. However, while writing test cases in Django, it took me a while to work out how to authenticate to the view. Here's how I did it. I hope somebody finds this useful.

Python Solutions


Solution 1 - Python

Here's how I did it:

from django.test import Client
import base64
auth_headers = {
    'HTTP_AUTHORIZATION': 'Basic ' + base64.b64encode('username:password'),
}
c = Client()
response = c.get('/my-protected-url/', **auth_headers)

Note: You will also need to create a user.

Solution 2 - Python

In your Django TestCase you can update the client defaults to contain your HTTP basic auth credentials.

import base64
from django.test import TestCase

class TestMyStuff(TestCase):

    def setUp(self):
        credentials = base64.b64encode('username:password')
        self.client.defaults['HTTP_AUTHORIZATION'] = 'Basic ' + credentials

Solution 3 - Python

For python3, you can base64-encode your username:password string:

base64.b64encode(b'username:password')

This returns bytes, so you need to transfer it into an ASCII string with .decode('ascii'):

Complete example:

import base64

from django.test import TestCase

class TestClass(TestCase):
   def test_authorized(self):
       headers = {
           'HTTP_AUTHORIZATION': 'Basic ' + 
                base64.b64encode(b'username:password').decode("ascii")
       }
       response = self.client.get('/', **headers)
       self.assertEqual(response.status_code, 200)

Solution 4 - Python

Assuming I have a login form, I use the following technique to login through the test framework:

    client = Client()
    client.post('/login/', {'username': 'john.smith', 'password': 'secret'})

I then carry the client around in my other tests since it's already authenticated. What is your question to this post?

Solution 5 - Python

(python3) I'm using this in a test:

credentials_string = '%s:%s' % ('invalid', 'invalid')
credentials = base64.b64encode(credentials_string.encode())
self.client.defaults['HTTP_AUTHORIZATION'] = 'Basic ' + credentials.decode()

and the following in a view:

import base64
[...]
type, auth = request.META['HTTP_AUTHORIZATION'].split(' ', 1)
auth = base64.b64decode(auth.strip()).decode()

Solution 6 - Python

Another way to do it is to bypass the Django Client() and use Requests instead.

class MyTest(TestCase):
    def setUp(self):
        AUTH = requests.auth.HTTPBasicAuth("username", "password")

    def some_test(self):
        resp = requests.get(BASE_URL + 'endpoint/', auth=AUTH)
        self.assertEqual(resp.status_code, 200)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHumphreyView Question on Stackoverflow
Solution 1 - PythonHumphreyView Answer on Stackoverflow
Solution 2 - PythonRyan NowakowskiView Answer on Stackoverflow
Solution 3 - Pythonmarkus-hinscheView Answer on Stackoverflow
Solution 4 - PythonThierry LamView Answer on Stackoverflow
Solution 5 - PythonobotezatView Answer on Stackoverflow
Solution 6 - PythonDavid DahanView Answer on Stackoverflow