API custom authentication with django-rest-framework

Long time since I blogged about anything in here! This time I am working on building a python-django powered dashboard for browser test result analysis with Igalia, and came across this the frist day! Let me get into this straight, following my usual template of blog posts

Scenario
You have a default User login model, but have some bot POSTing at say yourwebsite/bot-api. Your bot has its own authentication details sent as parameters in the POST as

{bot_name: fooboot, password: bar}

and you want to authenticate this from a Bot model in your django application, and make sure that this thing go throgh only after a green flag.

Solution
The best method here is to write a custom authentication in your views.py which would look like

from rest_framework import authentication
from your_models import Bot 

class BotAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):
        bot_name = request.POST.get('bot_name')
        bot_password = request.POST.get('password')

        if not bot_name or not bot_password:
            return None

        try:
            bot = Bot.objects.get(name=bot_name)
        
        # If you have some other methods to auth, use here
        if bot.password != bot_password:
                return None
        except Bot.DoesNotExist:
            raise exceptions.AuthenticationFailed('The bot failed to authenticate')

        return (bot, None)

and you can directly use this in your ApiView which should be ran on recieving a hit on the API.

from django.http import HttpResponse
from rest_framework.views import APIView
from rest_framework import authentication, permissions

class BotReportView(APIView):
    authentication_classes = (BotAuthentication,)
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

    def post(self, request, format=None):
         return HttpResponse("If it reached here, the bot was authenticated = yay")

Well. There are issues with using such a plain-text authentication, and doing a 1:1 password comparison. In real world, you might want to use django password field and authentication functions to compute hash of the recieved password, and compare with the one in the database table.

Hope this helps!