4

I am trying to implement a web service with filtered resources access (OAuth authentication) with Django and I had a couple of questions.

I created two webservers:

I am trying to use the version 1.0a of OAuth to authenticate the consumer against the provider. The workflow of this protocol is described here.

In a nutshell, here are the different steps (name of the resource exchanged):

  1. The consumer requests a token from the provider (key, secret)
  2. If the consumer is valid, the provider returns it a token (oauth_token, oauth_token_secret)
  3. The consumer redirects the User to the provider to login/grant access (oauth_token)
  4. The user grant access to the consumer for the resource.
  5. The provider gives the consumer a token verifier (token_verifier)
  6. The consumer requests an access_token (key, secret, oauth_token, oauth_token_secret, oauth_verifier)
  7. The provider gives the consumer an access_token (oauth_token)
  8. The consumer uses its oauth_token to access the resource

Here is the code of the views of my consumer:

from django.shortcuts import render_to_response
from django.http import HttpResponse, HttpResponseRedirect
import oauth2 as oauth
import urlparse

REQUEST_TOKEN_URL = 'http://127.0.0.1:8080/api/authentication/request_token/'
AUTHORIZATION_URL = 'http://127.0.0.1:8080/api/authentication/authorize/'
ACCESS_TOKEN_URL = 'http://127.0.0.1:8080/api/authentication/access_token/'
CONSUMER_CALLBACK_URL = 'http://127.0.0.1:8000/request_access_token/'

CONSUMER_KEY = 'key'
CONSUMER_SECRET = 'secret'

consumer = oauth.Consumer(CONSUMER_KEY, CONSUMER_SECRET)
client = oauth.Client(consumer)

def request_token(request):
    """
    Contacts the service provider to get a token.
    """ 
    resp, content = client.request(REQUEST_TOKEN_URL, 'GET')
    oauth_token = dict(urlparse.parse_qsl(content)).get('oauth_token', None)
    oauth_token_secret = dict(urlparse.parse_qsl(content)).get('oauth_token_secret',
                                                          None)

    if oauth_token is None:
        return render_to_response('home.html', {'data': 'NO TOKEN FOUND'})
    else:
        request.session['oauth_token'] = oauth_token
        request.session['oauth_token_secret'] = oauth_token_secret
        return HttpResponseRedirect('request_user_permission/')

def request_user_permission(request):
    """
    Redirects the user to the service provider to get permission if
    token provided.
    """
    oauth_token = request.session['oauth_token']

    if oauth_token is None:
        return render_to_response('home.html', {'data': 'NO TOKEN FOUND'})
    else:
        return HttpResponseRedirect("%s?oauth_token=%s&oauth_callback=%s"
             % (AUTHORIZATION_URL, oauth_token, CONSUMER_CALLBACK_URL))


def request_access_token(request):
    """
    Requests an access token from the service provider
    if the user granted permission.
    """
    error = request.GET.get('error', None)

    if error is None:
        oauth_verifier = request.GET.get('oauth_verifier', None)

        if oauth_verifier is None:
            return render_to_response('home.html',
                                       {'data': 'UNKNOWN ERROR HAPPENED'})
        else:
            # User permission granted, requesting access token
            oauth_token = request.session['oauth_token']
            oauth_token_secret = request.session['oauth_token_secret']

            token = oauth.Token(oauth_token, oauth_token_secret)
            token.set_verifier(oauth_verifier)
            client.token = token

            resp, content = client.request(ACCESS_TOKEN_URL, 'POST')
            access_token = dict(urlparse.parse_qsl(content))
            return render_to_response('home.html', {'data': access_token})
    else:
        return render_to_response('home.html', {'data': error})

General OAuth Questions

  • How many token should the consumer have? One? One per User? One per Resource?
  • How is the consumer supposed to store its token(s)?
  • How do you specify which resources the consumer can access with its token? Shouldn't the consumer be able to provide the id of the resource it wants to get access to when redirecting the user to the service provider (step 3)?
  • If a consumer wants to access a resource for which the user has already granted the access in the past, should it redirect the user to the service provider anyway (and let the service provider return the oauth_verifier instantly, instead of asking the User for permission)?

Technical problems

Right now, I am using local memory cached sessions to store the token, but it doesn't work:

  • When the sessions are activated on the consumer server, the User has to login every time on the service provider server (even if he was already logged in).
  • In the first view (requesting the token) I store the oauth_token and oauth_token_secret in the request's session. When I try to access it in the second view (before redirecting the user), it works. But when I try to access it in the last view (after the redirection) it doesn't (KeyError, oauth_token is not found in the request.session dictionary)

Thank you!

nbarraille
  • 9,926
  • 14
  • 65
  • 92

1 Answers1

1

I'm in the same-ish boat (implementing an API with OAuth authentication), and I came across the django-oauth-plus project in my research. The tutorial does a good job of walking through each step of the process outlined in the diagram you linked to. The code itself seems a pretty complete implementation of OAuth (not sure if I know what I'm talking about tho, just learning this stuff).

Also, this guy has a pretty great tutorial about the basics of OAuth (I struggled with that).

btk
  • 3,158
  • 2
  • 29
  • 30