Check credentials using Django Rest Framework

This post will cover how to authenticate a user’s username and password using a Django Rest Framework endpoint. This functionality allows checking credentials without the need for refreshing the browser.

This is a follow up to my previous post, which covered how to create a User model DRF endpoint (allowing creating, listing, deleting users).

Create the endpoint

note my folder strucure is like so:

apps/
    accounts/
        urls.py
        api/
            views.py
            serializers.py
            authentication.py

In views.py we need to create the AuthView which we will call to check credentials:

from . import authentication, serializers  # see previous post[1] for user serializer.

class AuthView(APIView):
    authentication_classes = (authentication.QuietBasicAuthentication,)
    serializer_class = serializers.UserSerializer

    def post(self, request, *args, **kwargs):
        return Response(self.serializer_class(request.user).data)

[1] https://richardtier.com/2014/02/25/django-rest-framework-user-endpoint/

Then in authenticaiton.py we define our authenticator: We inherit DRF’s BasticAuthentication to check the HTTP_AUTHORIZATION header for correct username and password.

from rest_framework.authentication import BasicAuthentication

class QuietBasicAuthentication(BasicAuthentication):
    # disclaimer: once the user is logged in, this should NOT be used as a
    # substitute for SessionAuthentication, which uses the django session cookie,
    # rather it can check credentials before a session cookie has been granted.
    def authenticate_header(self, request):
        return 'xBasic realm="%s"' % self.www_authenticate_realm

Notice we’re also overriding BasicAuthentication’s authenticate_header method to prevent undesirable behaviour: by default with Basic authentication if user provides wrong credentials the browser prompts the user for their credentials again using a native dialogue box. Rather ugly and bad user experience. To avoid this we ensure the schema returns a custom value other than ‘Basic‘.

We of course need to define the url in urls.py:

from django.conf.urls import patterns, url

from api import views as api_views

urlpatterns = patterns(
    '',
    url(r'^api/auth/$',
        api_views.AuthView.as_view(),
        name='authenticate')
)

Using the endpoint

Now we can do some fun stuff – attempt to authenticate using the endpoint. We need to set the header of the ajax request. We can do this by hooking in with $.ajax’s beforeSend:


function checkCredentials(username, password){
    function setHeader(xhr) {
        // as per HTTP authentication spec [2], credentials must be
        // encoded in base64. Lets use window.btoa [3]
        xhr.setRequestHeader ("Authorization", "Basic " +
                               btoa(username + ':' password));
    }

    $.ajax({type: "POST",  url: "/api/auth/",  beforeSend: setHeader}).
        fail(function(resp){
            console.log('bad credentials.')
        }).
        done(function(resp){
            console.log('welcome ' + resp.email)
        });

[2] https://tools.ietf.org/html/rfc2617
[3] https://developer.mozilla.org/en-US/docs/Web/API/Window.btoa

and to finally use it:


// pass in bad credentials...
checkCredentials('AzureDiamond', 'password');
// ...prints 'bad credentials.'

// pass in good credentials...
checkCredentials('AzureDiamond', 'hunter2');
// ...prints 'welcome AzureDiamond@bash.org'

Security considerations

Only serve this endpoint over HTTPS, in the same way you should serve a conventional login page using HTTPS. We dont wan’t a man in the middle attack getting our auth header!

In a future post we cover how to use this functionality to have persistent login.

Advertisements

4 thoughts on “Check credentials using Django Rest Framework

  1. Can’t wait to hear about the next post. I’m following this tutorial to make an app. It is great. There aren’t many examples about all this. Thank you.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s