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:
- http://localhost:8080 : Web Service Provider (using django-piston for the webservice)
- http://localhost:8000 : Web Service Consumer
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):
- The consumer requests a token from the provider (key, secret)
- If the consumer is valid, the provider returns it a token (oauth_token, oauth_token_secret)
- The consumer redirects the User to the provider to login/grant access (oauth_token)
- The user grant access to the consumer for the resource.
- The provider gives the consumer a token verifier (token_verifier)
- The consumer requests an access_token (key, secret, oauth_token, oauth_token_secret, oauth_verifier)
- The provider gives the consumer an access_token (oauth_token)
- 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
andoauth_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 therequest.session
dictionary)
Thank you!