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.
Asked
Active
Viewed 2.7k times
6 Answers
92
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.

Gilles 'SO- stop being evil'
- 104,111
- 38
- 209
- 254

Humphrey
- 4,108
- 2
- 28
- 27
-
11If you are manipulation unicode strings (typical eg: using py3) you'd need to do something like `base64.b64encode('username:password'.encode()).decode()` because base64 module do not handle unicode strings. – Jocelyn delalande Aug 12 '15 at 09:24
-
@Jocelyndelalande more like `base64.b64encode(bytes('username:password', 'utf8')).decode('utf8'),` – Ramon Moraes Jan 13 '16 at 23:58
-
@vyscond up to your taste, because it's strictly the same processing. – Jocelyn delalande Jan 17 '16 at 10:02
-
1Great answer! Just complementing: Using python 3.5 I just made `c.get('/my-protected-url/', HTTP_AUTHORIZATION='Basic username:password')` as shown in [django docs](https://docs.djangoproject.com/en/1.10/topics/testing/tools/#django.test.Client.get) and [CGI docs](https://tools.ietf.org/html/draft-robinson-www-interface-00#section-5). – lucastamoios Mar 14 '17 at 13:14
-
3Why HTTP_AUTHORIZATION and not Authorization ? – Daniel Gomez Rico Aug 14 '18 at 17:19
-
1@DanielGomezRico: Confusing, indeed. A bit late, but there's an explanation to be found in https://stackoverflow.com/q/15113248 – djvg Sep 17 '20 at 07:20
-
The process for creating a valid Basic auth header, including the Base64 encoding, is described in [RFC7617](https://tools.ietf.org/html/rfc7617#page-5). – djvg Sep 17 '20 at 07:35
-
Same structure will work for token authorization also, just replace basic with Token – Jagrut Trivedi Nov 19 '20 at 06:33
34
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

Ryan Nowakowski
- 811
- 7
- 10
-
2This can also be done a bit more succinctly using the `credentials()` method of the `Client` object: `self.client.credentials(HTTP_AUTHORIZATION='Basic ' + credentials)` (cf. http://www.django-rest-framework.org/api-guide/testing/#credentialskwargs). – Kurt Peek Jan 25 '18 at 00:42
-
@KurtPeek that only works with django-rest-framework, not with the vanilla Django test client – Salvioner Jan 18 '23 at 17:57
8
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)

smrf
- 349
- 3
- 16

markus-hinsche
- 1,372
- 15
- 26
2
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?

Thierry Lam
- 45,304
- 42
- 117
- 144
-
Yeah, that's a nice solution Thierry. Although it does not work for HTTP Authorization as that works by sending the login creditials as HTTP headers. I'm doing it this way because the view is an API call rather than a regular view. – Humphrey Apr 04 '11 at 23:32
-
This is the only solution that worked for me (for browser views). Even more straightforward: [Django client login method](https://docs.djangoproject.com/en/4.0/topics/testing/tools/#django.test.Client.login) – Beolap Jun 26 '22 at 22:51
2
(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()

obotezat
- 1,041
- 16
- 20
-1
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)

David Dahan
- 10,576
- 11
- 64
- 137
-
1the response class from `requests` is not guaranteed to be 100% compatible with the one that django uses. For example, you won't have `response.context` available. – fcurella Jul 20 '16 at 16:58
-
3This makes an actual http request across the network. This is almost never what you want to do in a unit test. – slinkp Oct 23 '17 at 05:30