Reputation: 8714
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'}
}
Upvotes: 21
Views: 8599
Reputation: 3651
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.
Upvotes: 13
Reputation: 4922
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.py
file, 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
Upvotes: 4