Django, mod_wsgi and HTTP Authentication

I sometimes use HTTP (Basic) Authentication to authenticate requests to an API of a website. Using cookie and form-based authentication for an API which will be used programmatically is generally a PITA. If the views are exposed via HTTPS (SSL/TLS encrypted) then I see no problem in using HTTP Basic Authentication.

There is a good snippet available on djangosnippets.org, which implements a decorator for protecting individual views with HTTP Basic Authentication. You can see the code here: Snippet 243.

The usage is pretty straightforward, just add the decorator to a view that should be accessible to clients authenticated by HTTP Basic Auth:

@logged_in_or_basicauth()
def api_view(request):
    ...

A good companion may be the require_POST decorator from django.views.decorators.http, which you can use on (api-) views, which only alter data and therefore should only receive HTTP POST requests. Decorators can be stacked, so you can write:

@require_POST
@logged_in_or_basicauth()
def api_view(request):
    ...

The decorator will handle all the details of the HTTP Basic Authentication for you, so now let's get back to the reason, why I'm writing this text: If you want to use this method to protect your views and you host your Django project on Apache with mod_wsgi, you have to add one setting to your Apache configuration:

WSGIPassAuthorization On

If you don't configure this mod_wsgi will not pass the HTTP Authentication headers to your Django application and your app will not be able to authenticate the requests.

Mod_wsgi will not pass authentication headers by default to prevent leaking passwords to WSGI applications. If Apache itself handles the authentication, it's clear that this is the right approach, but as we want Django to do the authentication be sure to configure mod_wsgi accordingly.

More details can be found in the mod_wsgi documentation about access control mechanisms.