Reputation: 1677
In settings.py
file I have written this settings:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
}
When I call any API with a token from a password grant
application, then It's working fine, but when I try to call the same APIs with a token from a client credential grant
application, it doesn't work and it responses with 403 error:
{ "detail": "You do not have permission to perform this action." }.
Is it because of default permission? I don't know what permission do I have to use instead!?
Upvotes: 2
Views: 1044
Reputation: 77
I had the same problem. The issue in my case was the @authentication_classes that was originally enabled for when I was using credentials directly (not token). I removed them (see them below commented out). Idea came after reading the first answer here.
This works for me as I only want token base access, and so I don't need the other authentication classes. This is how my view decoration looks like:
@api_view(['GET'])
#@authentication_classes([SessionAuthentication, BasicAuthentication])
@permission_classes([IsAuthenticated])
def apilink(request, format=None):
.....
Upvotes: 0
Reputation: 1677
Finally solved! The problem was the permission
I was using. In fact, the IsAuthenticated
permission checks request.user
which is None
when you are using client credentials
grant. Since there's no permission
for supporting clien credentials
grant in DRF, you must use your own DRF custom permission. This is what I needed and used:
from rest_framework.permissions import BasePermission
class IsAuthenticatedOrClientCredentialPermission(BasePermission):
def has_permission(self, request, view):
if request.auth is None:
return False
grant_type = request.auth.application.get_authorization_grant_type_display()
if request.user is None:
if grant_type == 'Client credentials':
request.user = request.auth.application.user # <-- this is because I needed to get the user either the grant is 'password' or 'client credentials'
return True
else:
return False
else:
return True
But you may want to have a permission just for checking if the grant type is client credentials
and give the permission, if so, this is what you need:
from rest_framework.permissions import BasePermission
class ClientCredentialPermission(BasePermission):
def has_permission(self, request, view):
if request.auth is None:
return False
grant_type = request.auth.application.get_authorization_grant_type_display()
if request.user is None and grant_type == 'Client credentials':
return True
else:
return False
Note: if you want to use the second custom permission, be aware that the request.user
is None
and you can get the owner of the client (that is sending request to you) via request.auth.application.user
.
You can use your custom permission by adding them to proper views. (Just like using any DRF permissions under rest_framework.permissions
)
class-based views:
class ExampleView(APIView):
permission_classes = [ClientCredentialPermission] # <-- Add your permissions to this list
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
function-based views:
@api_view(['GET'])
@permission_classes([ClientCredentialPermission]) # <-- Add your permissions to this list
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Upvotes: 6
Reputation: 3318
you need to enable tokenAuthentication and run migration to apply changes in auth table DB
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication', # <-- And here
],
}
INSTALLED_APPS = [
...
'rest_framework.authtoken'
]
Here is the perfect blog for your usecase.
https://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication
Upvotes: -1