22
votes

I am trying to make DRF work with oAuth2 (django-oauth-toolkit).

I was focusing on http://httplambda.com/a-rest-api-with-django-and-oauthw-authentication/

First I followed that instruction, but later, after getting authentication errors, I setup this demo: https://github.com/felix-d/Django-Oauth-Toolkit-Python-Social-Auth-Integration

Result was the same: I couldn't generate access token using this curl:

curl -X POST -d "grant_type=password&username=<user_name>&password=<password>" -u "<client_id>:<client_secret>" http://127.0.0.1:8000/o/token/

I got this error:

{"error": "unsupported_grant_type"}

The oAuth2 application was set with grant_type password. I changed grant_type to "client credentials" and tried this curl:

curl -X POST -d "grant_type=client_credentials" -u "<client_id>:<client_secret>" http://127.0.0.1:8000/o/token/

This worked and I got generated auth token.

After that I tried to get a list of all beers:

curl -H "Authorization: Bearer <auth_token>" http://127.0.0.1:8000/beers/

And I got this response:

{"detail":"You do not have permission to perform this action."}

This is the content of views.py that should show the beers:

from beers.models import Beer
from beers.serializer import BeerSerializer
from rest_framework import generics, permissions

class BeerList(generics.ListCreateAPIView):
    serializer_class = BeerSerializer
    permission_classes = (permissions.IsAuthenticated,)

    def get_queryset(self):
        user = self.request.user
        return Beer.objects.filter(owner=user)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

I am not sure what can be the problem here. First with "unsuported grant type" and later with other curl call. This also happen to me when I did basic tutorial from django-oauth-toolkit. I am using Django 1.8.2 and python3.4

Thanks for all help!

My settings.py looks like this

import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))

SECRET_KEY = 'hd#x!ysy@y+^*%i+klb)o0by!bh&7nu3uhg+5r0m=$3x$a!j@9'

DEBUG = True

TEMPLATE_DEBUG = True

ALLOWED_HOSTS = []

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
)

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'oauth2_provider',
    'rest_framework',
    'beers',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
)
ROOT_URLCONF = 'beerstash.urls'

WSGI_APPLICATION = 'beerstash.wsgi.application'

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

STATIC_URL = '/static/'

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'oauth2_provider.ext.rest_framework.OAuth2Authentication',
    )
}

OAUTH2_PROVIDER = {
    # this is the list of available scopes
    'SCOPES': {'read': 'Read scope', 'write': 'Write scope'}
}
2
what does your settings look like? have you added all the settings for oauth to be used as REST Framework API authentication?Alex T
@AlexT I added my settings.py fileBob
newer version uses : from oauth2_provider.contrib.rest_framework import OAuth2Authenticationjmunsch

2 Answers

13
votes

I have tried the demo you mentioned and everything was fine.

$ curl -X POST -d "grant_type=password&username=superuser&assword=123qwe" -u"xLJuHBcdgJHNuahvER9pgqSf6vcrlbkhCr75hTCZ:nv9gzOj0BMf2cdxoxsnYZuRYTK5QwpKWiZc7USuJpm11DNtSE9X6Ob9KaVTKaQqeyQZh4KF3oZS4IJ7o9n4amzfqKJnoL7a2tYQiWgtYPSQpY6VKFjEazcqSacqTx9z8" http://127.0.0.1:8000/o/token/
{"access_token": "jlLpKwzReB6maEnjuJrk2HxE4RHbiA", "token_type": "Bearer", "expires_in": 36000, "refresh_token": "DsDWz1LiSZ3bd7NVuLIp7Dkj6pbse1", "scope": "read write groups"}
$ curl -H "Authorization: Bearer jlLpKwzReB6maEnjuJrk2HxE4RHbiA" http://127.0.0.1:8000/beers/
[]

In your case, I think, you have created an application with wrong "Authorization grant type".

Use this application settings:

Name: just a name of your choice
Client Type: confidential
Authorization Grant Type: Resource owner password-based

This https://django-oauth-toolkit.readthedocs.org/en/latest/rest-framework/getting_started.html#step-3-register-an-application helped me a lot.

Here the database file I've created: https://www.dropbox.com/s/pxeyphkiy141i1l/db.sqlite3.tar.gz?dl=0

You can try it yourself. No source code changed at all. Django admin username - superuser, password - 123qwe.

4
votes

When you use "client credentials" it doesn't set the user on the generated access token, this is the root of that you do not have permission error you are seeing.

When using the client credentials grant type, you need to set the Rest Framework permission handler to look at tokens as client credentials does not set the user on the generated token. Django OAuth Toolkit provides custom permissions for this purpose:

https://django-oauth-toolkit.readthedocs.org/en/latest/rest-framework/permissions.html

Or if your entire API is subject to the same type of permissions you can just set the permission handler globally in your settings.pyfile, for example:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'oauth2_provider.ext.rest_framework.OAuth2Authentication',
    ),

    'DEFAULT_PERMISSION_CLASSES': (
        'oauth2_provider.ext.rest_framework.TokenHasReadWriteScope',
    )
}

This assumes of course that you grant read write permissions at the time.

More info about scopes here:

https://django-oauth-toolkit.readthedocs.org/en/latest/settings.html