98

I'm working on a store site, where every user is going to be anonymous (well, until it's time to pay at least), and I'm trying to use Django REST Framework to serve the product API, but it keeps complaining about:

"detail": "Authentication credentials were not provided." 

I found some settings related to authentication, but I couldn't find anything like ENABLE_AUTHENTICATION = True. How do I simply disable authentication, and let any visitor to the site access the API?

1

10 Answers 10

91

You can give empty defaults for the permission and authentication classes in your settings.

REST_FRAMEWORK = { # other settings... 'DEFAULT_AUTHENTICATION_CLASSES': [], 'DEFAULT_PERMISSION_CLASSES': [], } 
Sign up to request clarification or add additional context in comments.

7 Comments

how can i skip authentication for only one class in DRF
@roanjain add the attribute authentication_classes = [] - the settings dict is, as its name suggests, merely a default.
@OllieFord That sounds like a recipe for disaster. If someone sets the default auth to none, and later another person forgets to specify any auth class for any endpoint, that endpoint will be potentially unprotected. I would like to stay with the "blacklisting" practice instead of a "whitelisting" and just specify a magic anonymous authentication and permission classes to the particular endpoint I want to leave open.
@CsabaToth I don't understand how my above comment isn't what you want? Leave 'DEFAULT_AUTHENTICATION_CLASSES' = ['YourAuthenticationClass'] in settings, and put authentication_classes = [] on the the view that you want to leave open. If this attribute is not supplied, the default from settings will be used - no disaster here.
@CsabaToth I think you must be misreading my suggestion - I am not saying disable auth in settings, I am saying override it on the specific endpoint you want accessible without auth. I agree the alternative (no default in settings, specifying on every view) is a nightmare waiting to happen.
|
83

You can also disable authentication for particular class or method, just keep blank the decorators for the particular method.

from rest_framework.decorators import authentication_classes, permission_classes @authentication_classes([]) @permission_classes([]) @api_view(['POST']) def items(request): return Response({"message":"Hello world!"}) 

6 Comments

Is there anyone which has succesfully implement this snippet? I tried and not working.
Yes it working fine in my case, I have used this with user registration viewset, can you please tell me what error you are getting?
This will only work if you use the @api_view decorator: django-rest-framework.org/api-guide/authentication/…
in some drf versions the decorator orders is very important. for me this order is working: @api_view(['POST']) @authentication_classes([]) @permission_classes([])
|
35

if you want to disable authentication for a certain class based view, then you can use,

class PublicEndPoint(APIView): authentication_classes = [] #disables authentication permission_classes = [] #disables permission def get(self, request): pass 

This is useful when you want to make only specific endpoints available public.

5 Comments

what if you want to disable on a specific endpoint inside the same APIView class? Such as get, but not on post?
@Bersan the simplest way is to make your view public and check permission inside the post method.
@Sumithran how?
I had to use permissions.AllowAny as it did not disable anything
This answer saved my day!
11

You can also apply it on one specific endpoint by applying it on class or method. Just need to apply django rest framework AllowAny permission to the specific method or class.

views.py

from rest_framework.permissions import AllowAny from .serializers import CategorySerializer from catalogue.models import Category @permission_classes((AllowAny, )) class CategoryList(generics.ListAPIView): serializer_class = serializers.CategorySerializer queryset = Category.objects.all() 

You can achieve the same result by using an empty list or tuple for the permissions setting, but you may find it useful to specify this class because it makes the intention explicit.

Comments

10

To enable authentication globally add this to your django settings file:

'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', ), 

then add the following decorators to your methods to enable unauthenticated access to it

from rest_framework.decorators import authentication_classes, permission_classes @api_view(['POST']) @authentication_classes([]) @permission_classes([]) def register(request): try: username = request.data['username'] email = request.data['email'] password = request.data['password'] User.objects.create_user(username=username, email=email, password=password) return Response({ 'result': 'ok' }) except Exception as e: raise APIException(e) 

Comments

7

If using APIView you can create a permission for the view, example below:

urls.py

url(r'^my-endpoint', views.MyEndpoint.as_view()) 

permissions.py

class PublicEndpoint(permissions.BasePermission): def has_permission(self, request, view): return True 

views.py

from permissions import PublicEndpoint class MyEndpoint(APIView): permission_classes = (PublicEndpoint,) def get(self, request, format=None): return Response({'Info':'Public Endpoint'}) 

3 Comments

your PublicEndpoint implementation is the same as rest_framework.permissions.AllowAny
@MikePlacentra Yes, this whole answer can be replaced by from rest_framework.permissions import AllowAny & permission_classes = (AllowAny,)
That looks very promising, and best of all, it's easy to understand! Unfortunately, when I use it in my codebase, I still get 403 FORBIDDEN. I put a logging statement in the PublicEndpoint and that log statement is not hit which means my permission_class isn't being consulted at all. :sigh:
4

Here is an alternative to simply enable the API forms for development purposes:

settings.py

REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.AllowAny' ] } 

Django REST framework v3.11.0

Comments

4

For class view you can do:

from rest_framework.permissions import AllowAny from rest_framework.response import Response from rest_framework.views import APIView class ExampleView(APIView): permission_classes = [AllowAny] def get(self, request, format=None): content = { 'status': 'request was permitted' } return Response(content) 

For function view you can do:

 from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import AllowAny from rest_framework.response import Response @api_view(['GET']) @permission_classes([AllowAny]) def example_view(request, format=None): content = { 'status': 'request was permitted' } return Response(content) 

More details at Setting the permission policy

Comments

1

Also, it can be the separate class for the dev.

class DevAuthentication(authentication.BaseAuthentication): def authenticate(self, request): return models.User.objects.first(), None 

And in settings.py:

DEFAULT_AUTHENTICATION_CLASSES = ["common.authentication.DevAuthentication"] 

Comments

0
#in settings.py REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', ), 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.AllowAny', ] } class ListView(APIView): authentication_classes = [TokenAuthentication] permission_classes = [IsAuthenticated] def get(self,request): customers = Customer.objects.filter(is_superuser=False) serializer = CustomerSerializer(customers, many=True) return Response(serializer.data, status=status.HTTP_200_OK) 

1 Comment

It looks like you're setting DEFAULT_PERMISSION_CLASSES twice, so it's confusing what the intent is. If you just want AllowAny you can omit the first instance of IsAuthenticated entirely. Or if you want both, include them in the same tuple/list.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.