Django OAuth Toolkit Integration

909 views
Skip to first unread message

Federico Frenguelli

unread,
Jun 6, 2013, 4:42:14 AM6/6/13
to django-res...@googlegroups.com
Hi all,

we're developing an oauth app for django that uses oauthlib as its backend. This is the repo: https://github.com/evonove/django-oauth-toolkit, we just released 0.2.0 on pypi.

I'd like to discuss with you details for a possible integration. 
I have a proof of concept here https://github.com/synasius/django-rest-framework/tree/oauth-toolkit-integration where oauth2 authentication tests pass, 
excluding those that involve read/write scope permission which should be adapted to work with oauth toolkit. 
We also provided an implementation for a generic TokenHasScope permission class that don't rely on a predefined set of scopes such as 'read' 'write', according to the OAuth2 RFC.

Django-oauth-toolkit support python2.7, python3.3 and django 1.4, 1.5, 1.6, the goal is providing a turnkey solution for those who need Oauth2 support in a django project, and the first step of our roadmap is to work on integration with django-rest-framework.

Thanks :)

gar...@reakes.com

unread,
Jun 8, 2013, 11:40:31 AM6/8/13
to django-res...@googlegroups.com
Hi Federico,

can you expand a bit more on what you doing? The framework already has oauth2 support via https://github.com/caffeinehit/django-oauth2-provider. Will you being doing something different to this?

Cheers,

Gareth

Federico Frenguelli

unread,
Jun 9, 2013, 6:58:06 PM6/9/13
to django-res...@googlegroups.com

Hi Federico,

Hi Gareth 
 
can you expand a bit more on what you doing? 
The framework already has oauth2 support via https://github.com/caffeinehit/django-oauth2-provider. Will you being doing something different to this?

I'll try to be more accurate :)
django-oauth-toolkit provides oauth2 functionalities such as django-oauth2-provider. I think that django-oauth-toolkit could be a good choice for the following reasons:
1. django-oauth-toolkit is built upon oauthlib https://github.com/idan/oauthlib, a generic library that implements the logic of OAuth without assuming a specific HTTP request object. 
Oauthlib project is pretty active, developers answer quickly to issues and PR and they effectively fix bugs. 
2. django-oauth-toolkit has python3 support
3. django-oauth2-provider is a good project but at the moment there is no activity and no feedback on future plans
4. django-oauth-toolkit has a roadmap

I don't want to replace django-oauth2-provider with django-oauth-toolkit but i think that django REST framework should support both libraries so that developers can choice which one to use. I'm here to discuss if this integration is desirable/possible and how it can be achieved.

And now some technical details.
At the moment django-oauth2-provider imports are wrapped in a try except block and module name aliasing is used to provide a kind of abstraction layer. This is not enough.
To be able to easily support both libraries I think we need to define an interface that exposes the oauth2 functionalities that the framework needs. Specific implementations will perform the correct imports and logic.
I'm currently working on a PR that attempts to realize the idea explained above.

Any feedback will be appreciated

thanks a lot

--
Federico Frenguelli

Tom Christie

unread,
Jun 10, 2013, 4:30:04 AM6/10/13
to django-res...@googlegroups.com
Hi Federico,

  Sounds great.  Make sure the oauthlib team are aware of your work.  Posting on their [G+ page](https://plus.google.com/communities/101889017375384052571) is probably the best thing to do.  I know Ib Lundgren was thinking about starting work on a Django backend.

  All this sounds like really good work, and I'd be very happy to see a well-supported py3k compatible oauthlib based backend.  I would suggest that the best plan would be to keep any authentication and/or permission classes as part of the django-oauth-toolkit package, rather than bundling them into REST framework.  We can then add a section to the docs, listing django-oauth-toolkit as a 3rd-party option.

  If the documentation, maintenance, ease-of-use is significantly better than the existing auth we can consider calling that out as the best default choice, or perhaps think about moving the existing auth out to also be a third party package.

  Sound reasonable?

  Tom

Federico Frenguelli

unread,
Jun 10, 2013, 5:54:39 AM6/10/13
to django-res...@googlegroups.com
Hi Tom,
 
  Sounds great.  Make sure the oauthlib team are aware of your work.  Posting on their [G+ page](https://plus.google.com/communities/101889017375384052571) is probably the best thing to do.  I know Ib Lundgren was thinking about starting work on a Django backend.

I'm already in contact with Ib Lundgren, I notified him I was working on django-oauth-toolkit, we talked about it on IRC and now OAuthlib docs refers to django-oauth-toolkit package if you are looking for a django based backend.
 
  All this sounds like really good work, and I'd be very happy to see a well-supported py3k compatible oauthlib based backend.  I would suggest that the best plan would be to keep any authentication and/or permission classes as part of the django-oauth-toolkit package, rather than bundling them into REST framework.  We can then add a section to the docs, listing django-oauth-toolkit as a 3rd-party option.

  If the documentation, maintenance, ease-of-use is significantly better than the existing auth we can consider calling that out as the best default choice, or perhaps think about moving the existing auth out to also be a third party package.

  Sound reasonable?

Surely! I can work on this in the next days. I'll be back when a working example is ready.

Thanks for your feedback

--
Federico Frenguelli

Federico Frenguelli

unread,
Jun 14, 2013, 6:04:01 AM6/14/13
to django-res...@googlegroups.com
Hi,

django-oauth-toolkit 0.3.0 is out with REST framework support. 
You can find an integration tutorial here https://django-oauth-toolkit.readthedocs.org/en/latest/tutorial/rest_framework_integration.html which is based on your example app.

Any feedback would be appreciated

Thnx



2013/6/10 Federico Frenguelli <syna...@gmail.com>



--
Federico Frenguelli

Tom Christie

unread,
Jun 17, 2013, 4:32:10 AM6/17/13
to django-res...@googlegroups.com
Hi Federico,

  That's really great, good work! OAuthLib seems to be really well supported, so it's great to see a decent Django backend that uses it.  I've added references to it in the authentication docs, which will go live with the next release. Feel free to issue a PR if you think any of the docs need tweaking or suchlike.

  One thing that might be worth thinking about would be scoping permissions. There's still a lack of any out-of-the box options for APIs that need to be able to provide a range of different permission types and allocate tokens only support access to the relevant parts of API. I'd be happy to talk about the design of something like that if it's something you think you might pursue.

  And again, great work :)

  Tom

Federico Frenguelli

unread,
Jun 18, 2013, 5:27:02 AM6/18/13
to django-res...@googlegroups.com
Hi Tom,

That's really great, good work! OAuthLib seems to be really well supported, so it's great to see a decent Django backend that uses it.  

thanks :)
 
I've added references to it in the authentication docs, which will go live with the next release. Feel free to issue a PR if you think any of the docs need tweaking or suchlike.
 
I'll take a look at the docs asap
 
  One thing that might be worth thinking about would be scoping permissions. There's still a lack of any out-of-the box options for APIs that need to be able to provide a range of different permission types and allocate tokens only support access to the relevant parts of API. I'd be happy to talk about the design of something like that if it's something you think you might pursue.

I'll be glad to discuss about it! 
We already provide a working implementation of token-based scoped permissions. You can use it wth your views or viewsets as follows:


from oauth2_provider.ext.rest_framework import TokenHasReadWriteScope, TokenHasScope
from oauth2_provider.views.mixins import ScopedResourceMixin

class GroupViewSet(ScopedResourceMixin, viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticated, TokenHasScope]
    required_scopes = ['myscope']
    model = Group

Now when the user makes a request for Group the token used must provide 'myscope' scope. You can also require multiple scope and use it with 'TokenHasReadWriteScope' permission. For instance:

class GroupViewSet(ScopedResourceMixin, viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticated, TokenHasScope, TokenHasReadWriteScope]
    required_scopes = ['groups', 'admin']
    model = Group

If you try to make a POST request the access token MUST provide 'groups', 'admin' and 'write' scopes or you'll get a 403.

Where to go next?

--
Federico Frenguelli

Tom Christie

unread,
Jun 19, 2013, 4:21:23 AM6/19/13
to django-res...@googlegroups.com
Where to go next?

Firstly, is ScopedResourceMixin necessary?  It'd be nice if all the required behavior could be encapsulated in TokenHasScope.

Secondly, is TokenHasScope documented and in a PyPI released version of oauth toolkit yet?  When it is we could add an extra note in the permissions docs of REST framework, calling it out as a third-party permission for use with oauth toolkit.

Finally, out of interest, is OAuth1.0a also something you're also intending on supporting?

Federico Frenguelli

unread,
Jun 21, 2013, 6:08:18 PM6/21/13
to django-res...@googlegroups.com
Hi Tom

Firstly, is ScopedResourceMixin necessary? 

ScopedResourceMixin is not necessary until the view defines a get_scopes method on which the TokenHasScope permission relies. 

 
It'd be nice if all the required behavior could be encapsulated in TokenHasScope.

We can discuss it. I can imagine two solution:

#1 - Move ScopedResourceMixin logic inside TokenHasScope which becomes a sort of base abstract class...  
The developer is responsible to extend this class like:

class TokenHasGroupScope(TokenHasScope):
    required_scopes = ['group']

and can use this class as a permission.
But this solution has a problem: the user should define a class for every combination of scopes that he needs.

#2 - Move ScopedResourceMixin logic inside TokenHasScope (as in 1) and use a permission_class factory like

class TokenHasScope(type):
    def __new__(mcs, *required_scopes):
        return type('TokenScopedPermission', (BaseTokenHasScope,), {'required_scopes': required_scopes})

Devs can use TokenHasScope as follows:

class GroupViewSet(ScopedResourceMixin, viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticated, TokenHasScope('groups', 'admin'), TokenHasReadWriteScope]
    model = Group

But this changes how permissions behave in REST framework and I don't think it is a good idea.
mmm, need to elaborate something better....

Secondly, is TokenHasScope documented and in a PyPI released version of oauth toolkit yet?  When it is we could add an extra note in the permissions docs of REST framework, calling it out as a third-party permission for use with oauth toolkit.

TokenHasScope is already available in the last version (0.3.0) of django-oauth-toolkit but it is not yet documented. We planned a sprint at Europython (see https://ep2013.europython.eu/p3/sprints/#list) and one of main task is of course documentation. Any help would be appreciated!
 
Finally, out of interest, is OAuth1.0a also something you're also intending on supporting?

Yes, it is in our roadmap! Ib Lundgren has been working on a "OAuth1 provider revamp" with the goal to have an implementation with an API similar to OAuth2. The plan is to study his work and outline an integration strategy.
This should also be a task for the Europython sprint.




--
Federico Frenguelli

Tom Christie

unread,
Jun 25, 2013, 9:04:12 AM6/25/13
to django-res...@googlegroups.com
Wrt to removing the mixin class.

Rather than this...

class GroupViewSet(viewsets.ModelViewSet):
    permission_classes = [TokenHasGroupScope]
    model = Group

or this...

class GroupViewSet(viewsets.ModelViewSet):
    permission_classes = [TokenHasScope('groups', 'admin')]
    model = Group

I was thinking simply this...

class GroupViewSet(viewsets.ModelViewSet):
    permission_classes = [TokenHasScope]
    model = Group
    required_scopes = ('groups', 'admin')

The permission is passed the view, so it can encapsulate all the required logic without needing a mixin, and simply use `getattr` to determine which scopes are required, if any.  DjangoModelPermissions does something similar, and it's a pattern that's also used in places like the filtering classes.

Anyways, I'll be looking forward to seeing progress on Django OAuth Toolkit during the EuroPython sprints - have a great time!
Reply all
Reply to author
Forward
0 new messages