Search code examples
pythondjangooauth-2.0django-rest-frameworkdjango-oauth

Generating single access token with Django OAuth2 Toolkit


I'm using the latest Django OAuth2 Toolkit (0.10.0) with Python 2.7, Django 1.8 and Django REST framework 3.3

While using the grant_type=password, I noticed some weird behavior that any time the user asks for a new access token:

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

A new access token and refresh token is created. The old access and refresh token are still usable until token timeout!

My Issues:

  • What I need is that every time a user asks for a new access token, the old one will become invalid, unusable and will be removed.
  • Also, is there a way that the password grunt type wont create refresh token. I don't have any use for that in my application.

One solution I found is that REST Framework OAuth provides a configuration for One Access Token at a time. I'm not eager to use that provider, but I might wont have a choice.


Solution

  • If you like to remove all previous access tokens before issuing a new one, there is a simple solution for this problem: Make your own token view provider!

    The code bellow will probably help you to achieve that kind of functionality:

    from oauth2_provider.models import AccessToken, Application
    from braces.views import CsrfExemptMixin
    from oauth2_provider.views.mixins import OAuthLibMixin
    from oauth2_provider.settings import oauth2_settings
    
    class TokenView(APIView, CsrfExemptMixin, OAuthLibMixin):
        permission_classes = (permissions.AllowAny,)
    
        server_class = oauth2_settings.OAUTH2_SERVER_CLASS
        validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
        oauthlib_backend_class = oauth2_settings.OAUTH2_BACKEND_CLASS
    
        def post(self, request):
            username = request.POST.get('username')
            try:
                if username is None:
                    raise User.DoesNotExist
                AccessToken.objects.filter(user=User.objects.get(username=username), application=Application.objects.get(name="Website")).delete()
            except Exception as e:
                return Response(e.message,status=400)
    
            url, headers, body, status = self.create_token_response(request)
            return Response(body, status=status, headers=headers)
    

    The part you should notice is the Try-Except block. In there we finding the Access tokens and removing them. All before we creating a new one.

    You can look at how to create your own Provider using OAuthLib. Also, this might be useful as well: TokenView in django-oauth-toolkit. You can see there the original Apiview. As you said, you were using this package.

    As for the refresh_token, as previously mentioned in other answers here, you can't do what you are asking. When looking at the code of oauthlib password grunt type, you will see that in its initialization, refresh_token is set to True. Unless you change the Grunt type it self, it can't be done.

    But you can do the same thing we did above with the access tokens. Create the token and then delete the refresh token.