How to Implement Multiple(Custom) Authentication in Django Rest Framework

·

5 min read

Problem

You might use multiple authentication scheme in DRF, for meeting your requirements such as Session, Token, Basic(username and password) Authentication etc.. However it is not that simple to use multiple authentications, because it is not applied for your every APIs, It is changing belong to your type of response.

Although multiple authentication schemes may be in use, only one scheme may be used to determine the type of response. - DRF docs

But In many cases, you want to use those authentication classes in a single request(somebody will say it is not a good practice). That means that you should write your own custom Authentication class.

When I need to use custom Authentication?

  1. I want to mix it up in a single Authentication class!
    • Fine, but you should keep the type of your request/response.
    • Or you can check the types in your custom class.
    • For example, you want to check Sessions and then Token Authentications.
  1. I have to classify the tokens per users, and also devices! (or anything)

    • You might have requirements to classify several type of tokens.
    • The TokenAuthentication provided by DRF uses only one type of token. (per users)
    • You can compose with the checking the Bearer Token first and then User Tokens.
  2. I have my Special authentication Ideas.

    • As your wish.
    • For example, you can use your special HTTP Headers, Designated IP Address.

What I have to do

  1. You need to define your custom authentication class inherited DRF's authentication class.
  2. After authentication, return Tuple with the results (user, auth). If authentication failed, raise exception error.
  3. Set default Authentication class in settings.py or implement per api view(viewsets)
#myapp/auth.py
from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions

class ExampleAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):
        try:
            # some authentication logic
        except : 
             raise exceptions.AuthenticationFailed('AUTH FAILED')
        return (user, None)

#settings.py
AUTHENTICATION_BACKENDS = (
    'myapp.auth.ExampleAuthentication',
)

Examples

I will give you s simple examples, might help.

Implement multiple authentications.

class ExampleAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):
        try:
            #BasicAuthentication
            try:
                return authentication.BasicAuthentcation.authenticate(request)
            except:
                #RemoteUserAuthentication
                try:
                    return authenticatiohn.RemoteUserAuthentication.authenticate(request)
                except:
                    raise exceptions.AuthenticationFailed('AUTH FAILED')
        except : 
             raise exceptions.AuthenticationFailed('AUTH FAILED')

Several Type of Tokens

class ExampleAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):
        try:
            api_key = request.META.get('HTTP_X_API_KEY')
            #custom bearer token
            if api_key in [YOUR_API_KEYS]:
                return (user, None)
            #token in your DB
            elif Token.objects.filter(token=api_key):
                return (Token.objects.get(token=api_key).user, None)
            else:
                raise exceptions.AuthenticationFailed('AUTH FAILED')
        except : 
             raise exceptions.AuthenticationFailed('AUTH FAILED')

Designated IP Address

class ExampleAuthentication(authentication.BaseAuthentication):
    def get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip

    def authenticate(self, request):
        try:
            ip = self.get_client_ip(request)
            user = DesignatedIPAddress.objects.get(ip=ip).user
            return (user, None)
        except: 
             raise exceptions.AuthenticationFailed('AUTH FAILED')

Conclusion

It was just simple authentication examples to fit your needs. And also I strongly recommend to implement your own Oauth2 auth server, and forget all the 'custom authentications' someday. But It will help you right away. So if you have any questions, reply me. Thanks