50

Using Django REST API, I'm trying to authenticate my request.

This is what I'm trying to send:

Content-Type: application/json, Authentication: token="6d82549b48a8b079f618ee9c51a6dfb59c7e2196"

This is what I get back:

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

Could someone give me the correct header?

Thanks

The Header:

Accept: application/json
Content-Type: application/json
Authorization: Token 6d82549b48a8b079f618ee9c51a6dfb59c7e2196
Connection: keep-alive
Origin: chrome-extension: //rest-console-id
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17

enter image description here

Settings.py

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.permissions.IsAdminUser',


    ),
    'PAGINATE_BY': 10
}

view.py

class ProfileList(generics.ListCreateAPIView):
    """
    API endpoint that represents a list of users.
    """
    permission_classes = (permissions.IsAuthenticated,)
    model = Profile
    serializer_class = ProfileSerializer

    def pre_save(self, obj):
        obj.owner = self.request.user
2
  • Which authentication class are you trying to use? Do you have it set in the REST_FRAMEWORK settings, or in the view's authentication_classes? Commented Feb 14, 2013 at 15:05
  • I have added both my setting.py part and the view.py if you can stop anything? Commented Feb 14, 2013 at 16:12

6 Answers 6

115

Just in case anyone else comes across this error. This can also happen if you are running Django on Apache using mod_wsgi because the authorization header is stripped out by mod_wsgi. You'll need to add the following to your VirtualHost configuration:

WSGIPassAuthorization On

Sign up to request clarification or add additional context in comments.

3 Comments

added this line to same file where I have WSGIScriptAlias fixed the issue. thank you
This should be put as a banner, not as a post. Solved my problem too.
Argh. I've been trying to debug both the API and the client to figure this out for the last day. Thanks for this!
30

Assuming you're trying to use TokenAuthentication, the header should look like this:

Authorization: Token 6d82549b48a8b079f618ee9c51a6dfb59c7e2196

As described in the documentation.

5 Comments

tried that see screen shot I just added, seem to get the same error.
Do you have TokenAuthentication set in the REST_FRAMEWORK settings? See here: django-rest-framework.org/api-guide/…
I have est_framework.authentication.TokenAuthentication in my settings.py and also permission_classes = (permissions.IsAuthenticated,) in my view
Ok, i now have access added the 'rest_framework.authentication.TokenAuthentication', as you suggested but the browser able version is now locks me out
@Falcon1 do you want to share your solution? :)
20

I was having the same trouble with my Token Authentication

This fixed the problem to me

settings.py

REST_FRAMEWORK = {
   'DEFAULT_AUTHENTICATION_CLASSES': (
       'rest_framework.authentication.TokenAuthentication',
   ),
   'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAdminUser'
   ),
   'PAGINATE_BY': 10,
}

1 Comment

Adding the DEFAULT_AUTHENTICATION_CLASSES rest_framework.authentication.TokenAuthentication key is what worked for me.
8

In my case this works:
(Django REST Framework v3)

settings.py

REST_FRAMEWORK = {
   'DEFAULT_AUTHENTICATION_CLASSES': (
       'rest_framework.authentication.TokenAuthentication',
       'rest_framework.authentication.SessionAuthentication',
   ),
   'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
   ),
}

views.py

class Test(APIView):
    def get(self, request, format=None):   
        return Response({'Result': 'OK'})

urls.py

router.add_api_view('test', url(r'^test/', views.Test.as_view(),name='test'))

Don't forget to send the token information in the header:

 Key: Authorization  
 Value: Token 76efd80cd6849ad7d35e04f1cc1eea35bdc20294

To generate tokens you can use the following (somewhere in your code):

from rest_framework.authtoken.models import Token            
user = User.objects.get(username='<username>')
token = Token.objects.create(user=user)
print(token.key)

1 Comment

This answer needs to be upvoted more. The key idea is to put rest_framework.authentication.TokenAuthentication in the DEFAULT_AUTHENTICATION_CLASSES and not DEFAULT_PERMISSION_CLASSES in DRF v3.x.x
2

For those who are on AWS elastic beanstalk and you are kind of stuck with apache and unless you have

WSGIPassAuthorization On

As mentioned by @Fiver your headers get stripped

Instead of manually fixing this and making a new image, I made a script that checks if the last line of the conf file is WSGIPassAuthorization On and if it is not we update it and restart the server

In my Django app I have a config folder with my sh file

configs/server/update-apache.sh

if [[ $(tac /etc/httpd/conf/httpd.conf | egrep -m 1 .) == $(echo 'WSGIPassAuthorization On') ]];
  then
     echo "Httpd.conf has already been updated"
  else
     echo "Updating Httpd.conf.."
     echo 'WSGIPassAuthorization On' >> /etc/httpd/conf/httpd.conf
     service httpd restart
fi

Make it excecutable before I commit it to git

chmod +x configs/server/update-apache.sh

Then in my python.config file I add the command at the end

.ebextensions/python.config

...
...
container_commands:
    01_migrate:
        command: "python manage.py migrate"
        leader_only: true
    02_collectstatic:
        command: "python manage.py collectstatic --noinput"
    03_change_perm:
        command: "chown -R wsgi:root static"
    03_update_apache:
        command: "sh configs/server/update-apache.sh"

Now any new machine that starts up will have a check done to see if the server is updated and does so if need be

Comments

0

I got bitten by a related issue, sharing the solution in case it's useful to anyone. Our test servers require HTTP Basic Auth for the whole site, i.e. users must log in via an http auth dialog before doing their personal login. This is a simple credential - just enough to keep the googlebot away. API requests to those servers handle this by embedding those credentials in the request, i.e.

url = "https://username:[email protected]

The problem is that when you do that, the embedded credential is translated invisibly into an http Authorization header. That header keyword is thus already occupied, making it impossible to also send an Authentication header for the token, and the DRF API returns a confusing "No credential provided" error.

The solution was to use DRF's Custom Authentication docs and create a new TokenAuthentication class subclassing DRF's. In it I defined two methods: def get_custom_authorization_header() and def authenticate(), where authenticate() calls get_custom_authorization_header(), which overrides the auth = line:

auth = request.headers.get("X-Ourcustom-Authorization", b"")

Calling code to test servers then replaces

headers = {"Authorization": f"Token {your_token}"}

with

headers = {"X-OurCustom-Authorization": f"Token {token}"}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.