118

I'm developing an API using Django Rest Framework. I'm trying to list or create an "Order" object, but when i'm trying to access the console gives me this error:

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

Views:

from django.shortcuts import render
from rest_framework import viewsets
from django.contrib.auth.models import User
from rest_framework.renderers import JSONRenderer, YAMLRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from order.models import *
from API.serializers import *
from rest_framework.permissions import IsAuthenticated

class OrderViewSet(viewsets.ModelViewSet):
    model = Order
    serializer_class = OrderSerializer
    permission_classes = (IsAuthenticated,)

Serializer:

class OrderSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = Order
        fields = ('field1', 'field2')

And my URLs:

# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from django.conf import settings
from django.contrib import admin
from django.utils.functional import curry
from django.views.defaults import *
from rest_framework import routers
from API.views import *

admin.autodiscover()

handler500 = "web.views.server_error"
handler404 = "web.views.page_not_found_error"

router = routers.DefaultRouter()
router.register(r'orders', OrdersViewSet)

urlpatterns = patterns('',
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'^api-token-auth/', 'rest_framework.authtoken.views.obtain_auth_token'),
    url(r'^api/', include(router.urls)),
)

And then I'm using this command in the console:

curl -X GET http://127.0.0.1:8000/api/orders/ -H 'Authorization: Token 12383dcb52d627eabd39e7e88501e96a2sadc55'

And the error say:

{"detail": "Authentication credentials were not provided."}
Marcos Aguayo
  • 5,393
  • 7
  • 25
  • 56

12 Answers12

185

If you are runnig Django on Apache using mod_wsgi you have to add

WSGIPassAuthorization On

in your httpd.conf. Otherwise authorization header will be stripped out by mod_wsgi.

Robert Kovac
  • 1,918
  • 1
  • 8
  • 8
  • 1
    In case if you are wondering where to write this, follow the link. https://stackoverflow.com/questions/49340534/how-to-enable-wsgipassauthorization-for-django – user2858738 Apr 18 '18 at 08:41
  • 3
    for ubuntu there seems no `httpd.conf`. so you have to add `WSGIPassAuthorization On` in `/etc/apache2/apache2.conf` – suhailvs Jun 25 '18 at 01:19
  • I was confused by an issue where my requests from Postman were working from my localhost but not when sent to the live server. Your comment solved my issue. – RommelTJ Sep 10 '19 at 14:30
  • Solved My problem, I was able to get data via api on my localhost, but when deployed on server over https:// it was giving me same error. – Mir Suhail Feb 04 '20 at 11:42
  • Is this true only in production or for local development as well? – MadPhysicist May 10 '20 at 05:15
  • Not sure for local development on Apache, I'm using Django development server locally – Robert Kovac May 11 '20 at 07:33
109

Solved by adding "DEFAULT_AUTHENTICATION_CLASSES" to my settings.py

REST_FRAMEWORK = {
   'DEFAULT_AUTHENTICATION_CLASSES': (
       'rest_framework.authentication.TokenAuthentication',
   ),
   'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAdminUser'
   ),
}
Marcos Aguayo
  • 5,393
  • 7
  • 25
  • 56
  • Thought I did this, but I had added `'rest_framework.authentication.TokenAuthentication'` to `DEFAULT_PERMISSION_CLASSES` instead of `DEFAULT_AUTHENTICATION_CLASSES` – netigger Aug 08 '16 at 08:18
  • 6
    Thanks for this solution! I don't understand however why I didn't get the "Authentication credentials were not provided." error when making the request with Postman, whereas I *did* get the error when my Angular client made requests. Both with the same token in the Authorization header... – Sander Vanden Hautte Mar 07 '18 at 12:20
  • `SessionAuthentication` is enabled by default and works with the standard session cookies, so it's likely that your Angular (or other JS framework) application was working because of the default session authentication. – Kevin Brown Jul 02 '20 at 22:57
34

This help me out without "DEFAULT_PERMISSION_CLASSES" in my settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ),
    'PAGE_SIZE': 10
}
Eric Palakovich Carr
  • 20,472
  • 8
  • 45
  • 51
uestcfei
  • 1,091
  • 10
  • 13
  • 5
    The `SessionAuthentication` was what fixed it for me – Caleb_Allen Apr 06 '18 at 23:42
  • Fixed it for me too. Wonder why the Django tutorial on this doesn't mention it. See https://www.django-rest-framework.org/tutorial/quickstart/ . – Nick T May 17 '20 at 07:42
  • 1
    has any one figured out why it behaves like this? session on a mobile device has to do nothing with having a jwt token in the header of the request !! I am surprised by this solution after 5 hours of digging. – decoder3-14 Feb 26 '21 at 04:00
18

Just for other people landing up here with same error, this issue can arise if your request.user is AnonymousUser and not the right user who is actually authorized to access the URL. You can see that by printing value of request.user . If it is indeed an anonymous user, these steps might help:

  1. Make sure you have 'rest_framework.authtoken' in INSTALLED_APPS in your settings.py.

  2. Make sure you have this somewhere in settings.py:

    REST_FRAMEWORK = {
    
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework.authentication.TokenAuthentication',
            # ...
        ),
    
        # ...
    }
    
  3. Make sure you have the correct token for the user who is logged in. If you do not have the token, learn how to get it here. Basically, you need to do a POST request to a view which gives you the token if you provide the correct username and password. Example:

    curl -X POST -d "user=Pepe&password=aaaa"  http://localhost:8000/
    
  4. Make sure the view which you are trying to access, has these:

    class some_fancy_example_view(ModelViewSet): 
    """
    not compulsary it has to be 'ModelViewSet' this can be anything like APIview etc, depending on your requirements.
    """
        permission_classes = (IsAuthenticated,) 
        authentication_classes = (TokenAuthentication,) 
        # ...
    
  5. Use curl now this way:

    curl -X (your_request_method) -H  "Authorization: Token <your_token>" <your_url>
    

Example:

    curl -X GET http://127.0.0.1:8001/expenses/  -H "Authorization: Token 9463b437afdd3f34b8ec66acda4b192a815a15a8"
TorelTwiddler
  • 5,418
  • 2
  • 28
  • 39
sherelock
  • 364
  • 3
  • 7
  • How can one print `request.user`? It appears that the POST method of a class-based view is never getting processed. Where else can I try to print the user? – MadPhysicist May 10 '20 at 05:19
  • user has to be authenticated to be able to being getting set in request object. Otherwise it just prints anonymous user. How are you authenticating your user ? – sherelock May 10 '20 at 21:14
13

If you are playing around in the command line (using curl, or HTTPie etc) you can use BasicAuthentication to test/user your API

    REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.IsAuthenticated',
        ],
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework.authentication.BasicAuthentication',  # enables simple command line authentication
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.TokenAuthentication',
        )
    }

You can then use curl

curl --user user:password -X POST http://example.com/path/ --data "some_field=some data"

or httpie (its easier on the eyes):

http -a user:password POST http://example.com/path/ some_field="some data"

or something else like Advanced Rest Client (ARC)

lukeaus
  • 8,268
  • 5
  • 40
  • 59
10

I too faced the same since I missed adding

authentication_classes = (TokenAuthentication)

in my API view class.

class ServiceList(generics.ListCreateAPIView):
    authentication_classes = (SessionAuthentication, BasicAuthentication, TokenAuthentication)
    queryset = Service.objects.all()
    serializer_class = ServiceSerializer
    permission_classes = (IsAdminOrReadOnly,)

In addition to the above, we need to explicitly tell Django about the Authentication in settings.py file.

REST_FRAMEWORK = {
   'DEFAULT_AUTHENTICATION_CLASSES': (
   'rest_framework.authentication.TokenAuthentication',
   )
}
prashant
  • 1,622
  • 2
  • 18
  • 30
7

For me, I had to prepend my Authorization header with "JWT" instead of "Bearer" or "Token" on Django DRF. Then it started working. eg -

Authorization: JWT asdflkj2ewmnsasdfmnwelfkjsdfghdfghdv.wlsfdkwefojdfgh

kiko carisse
  • 986
  • 11
  • 17
4

I was having this problem with postman.Add this to the headers... enter image description here

mikelus
  • 685
  • 8
  • 20
3

Adding SessionAuthentication in settings.py will do the job

REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', ), }

Pritam Roy
  • 258
  • 2
  • 15
3

Try this, it worked for me.

In settings.py

SIMPLE_JWT = {
     ....
     ...
     # Use JWT 
     'AUTH_HEADER_TYPES': ('JWT',),
     # 'AUTH_HEADER_TYPES': ('Bearer',),
     ....
     ...
}

Add this too

REST_FRAMEWORK = {
    ....
    ...
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
    ...
    ..
}
Harshit Gangwar
  • 160
  • 2
  • 9
1

Since it is session Login so you need to provide you credentials so do 127.0.0:8000/admin admin and login later it will work fine

1

If you are using authentication_classes then you should have is_active as True in User model, which might be False by default.

David Medinets
  • 4,078
  • 3
  • 25
  • 39