jazzband / django-oauth-toolkit

OAuth2 goodies for the Djangonauts!
https://django-oauth-toolkit.readthedocs.io
Other
3.16k stars 794 forks source link

Grant type client_credentials not working with Django 1.11 #470

Closed singhharpreet658 closed 3 years ago

singhharpreet658 commented 7 years ago

Hi Team,

I've installed Django 1.11 and django-oauth-toolkit 0.12 with python 3.5 We've setup one Application with "client type: public" and "grant type: client_credentials".

We have generated a token with o/token, grant type client_credentials but the generated token is not associated with any user.

When we use this token for further API requests then it returns the error "You do not have permission to perform this action." although the scope of token is "Read Write".

Please suggest.

Thanks Harpreet

jdelight commented 7 years ago

+1 It would be useful to know how to associate client credentials grants with a User especially for DRF. I assumed that setting the user on the Application instance would associate tokens generated for that application with its user. However the tokens do not seem to have a user. Django 1.10.6 and python 3.6

ganeshab-edico commented 6 years ago

other oauth2 implementations seem to do the same https://github.com/laravel/passport/issues/143

firvida commented 5 years ago

Is there any workaround on this issue, I've been facing the same in Django 2

leiserfg commented 5 years ago

Check oauth2 specifications, the current implementation is what is expected.

JonathanHuot commented 5 years ago

Multiple issues are in the OP's initial question: 1) client_type: public + grant: client_credentials is a non-sense and must not be allowed. Bug in the DOT code ? 2) most of the time, the client_credentials generates tokens associated to a "client" (i.e. application) and not an user. However, ideally, binding a client to an user should be possible but might be a separated feature for DOT. 3) access token does not seems to allow accessing the resource, but it is not related to anything of the above ? also, the title of the issue "client_creds not working" seems to broad and does not reflect its content.

Thoughts?

hrahmadi71 commented 5 years ago

Multiple issues are in the OP's initial question:

  1. client_type: public + grant: client_credentials is a non-sense and must not be allowed. Bug in the DOT code ?
  2. most of the time, the client_credentials generates tokens associated to a "client" (i.e. application) and not an user. However, ideally, binding a client to an user should be possible but might be a separated feature for DOT.
  3. access token does not seems to allow accessing the resource, but it is not related to anything of the above ? also, the title of the issue "client_creds not working" seems to broad and does not reflect its content.

Thoughts?

I have the same problem, but mine has some differences. I'm using django 2 and the "client type" of the application I set up is "Confidential". But still the same problem! I don't know if it's my settings or it's a bug or anything else! So for more information, I have these in the settings:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
}

OAUTH2_PROVIDER = {
    'SCOPES': {'read': 'Read scope', 'write': 'Write scope',
               'groups': 'Access to your groups'}
}

Please help.

JonathanHuot commented 5 years ago

@hrahmadi71, sorry but I still don't understand what is the "same problem". Do you have at least an error, stack trace, or anything which could help to understand the issue ?

hrahmadi71 commented 5 years ago

@JonathanHuot , by the same problem I mean when I try to use a token generated by client_id and client_secret of an application with "client credential grant", I get the 403 error with this payload:

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

for example I have this view:

class LanguageDetect(generics.CreateAPIView):
    permission_classes = [permissions.IsAuthenticated]
    ...

and when I try to call this API by: curl -X POST "http://127.0.0.1:8000/api/v1/language_detect/" -H "accept: application/json" -H "authorization: Bearer [access_token]" -H "Content-Type: application/json" -d "{ \"input_text\": \"string\"}"

Depend on grant type of the application I get [access_token] from, it defers! When the [access_token] I'm using, belongs to an application with 'password' grant, it works fine. But when it belongs to an application with 'client credentials' grant, I get the error just showed. Thank you in advance, and sorry if I can't explain my problem clearly.

JonathanHuot commented 5 years ago

Thanks @hrahmadi71, that's much clearer ! I think the permissions.IsAuthenticated require for an user to be logged-in and not an application (client). However, I am not familiar enough with the Django framework to help.

hrahmadi71 commented 5 years ago

@JonathanHuot Thank you for your help. As you mentioned the problem was the permission I've been using, so I solved it by implementing a custom permission for client credential grant as I explained here. And here's the DRF guide to implement a custom permission which I've used. I hope it would be helpful.

kdazzle commented 5 years ago

I think it might be better to override the OAuth2Authentication class and pull out the application user instead of setting request.user in has_permission. Something more like...

from oauth2_provider.contrib.rest_framework import OAuth2Authentication
from oauth2_provider.models import Application
from oauth2_provider.oauth2_backends import get_oauthlib_core

class OAuth2ClientCredentialAuthentication(OAuth2Authentication):

    def authenticate(self, request):
        authentication = super().authenticate(request)

        if authentication is not None and not self.is_client_credential_request(authentication):
            return authentication

        if self.is_client_credential_request(authentication):
            access_token = authentication[1]
            user = access_token.application.user
            return user, access_token

        return None

    def is_client_credential_request(self, authentication):
        access_token = authentication[1]
        return access_token.application.authorization_grant_type == Application.GRANT_CLIENT_CREDENTIALS
mahyard commented 3 years ago

I faced with the same problem (getting HTTP 403 Forbidden response when using a client_credential granted access_token to call my APIs). So I used an authenticator like what suggested by @kdazzle. I think it would be a good feature to be added to the repository. especially for those who want to authenticate a server-to-server request. @jonatascastro12, do you agree? are you currently working on this?

jonatascastro12 commented 3 years ago

Hey @mahyard! You probably wanted to mention another "Jonatas". 😉

mahyard commented 3 years ago

my bad... excuse me @jonatascastro12 @JonathanHuot could you check my comment above, please?

jjoocceeee commented 3 years ago

@kdazzle This solution works for me, thanks!

Is the user for the application for a Client Credential type, just the user who is logged in when the application (client) is created?

Chappie74 commented 1 year ago

with some modification @kdazzle 's answer worked perfectly.