Wednesday, August 4, 2010

Simple introduction to oauth protocol at the developement level. (with twitter and foursquare examples)

Oauth is basically a protocol for inter-application exchange of tokens, allowing one application to use resources and APIs of the other application, by authenticating between them with these tokens. One application being the Oauth Server, and the other one being the Oauth client.

The first step in configuring an oauth “contract” between the two applications is in the configuration of the server application, by registering the client application.

The server creates an “ID” for the client application from which it will identify it. This ID is formed by two strings known as the “key” and the “secret” . This ID strings are immediately made available to the client application.

The server must also provide 3 URLs to the client:
Request Token URL
Authorize URL
Access Token URL


It also must register a client callback URL

How it works

Request Token URL: URL where the client will request a first token, to identify a “user” within the client application. When accessing this URL with the id and key of the client application, it will return a token (oauth_token) (a String basically) which will then be used to authorize the client, with that particular token to access the server application. It returns another token (oauth_secret_token) that must be used later, so it has to be stored somehow (usually in the session). The first token will then be used to call the Authorize URL.

Authorize URL: This is the URL that is called from the client to give authorization to a specific account on the server application. This means that by accessing this URL, normally the authentication mechanism of the server application will pop, and after filling it, a dialog will pop requesting the acceptance or denying of the authorizations from the client application. After the permission is granted, the server application will call a callback URL on the client application (defined in the server configuration at the begining of the process) sending it a new token (oauth_token). The final Step will be calling the access token URL and..

Access Token URL: When the client application receives the callback call from the server, it takes the new oauth_token from the request, combine it with the saved oauth_token_secret from the first request and call the access token URL with that. The response is yet another two tokens known as the access tokens. These tokens must be stored persistently somewhere for future use, and usually will be associated with some user within the client application.

Now users within the client application can access their resources on the server application, sending their two tokens in every request for identifying them. And of course sending also the key and secret that identify the application.

Seeing it on the wire

This is the exchange using foursquare as an example of Oauth server

1. First the client request a request token, givinf the key of the application and the encrypted secret

GET /oauth/request_token?oauth_nonce=62603210&oauth_timestamp=1280930229&oauth_consumer_key=NO2ML1KLHEEPWMUQZPZSIOIGWX3LEBOTBYXTSIHECZ02WVL1&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_signature=PRFQvAJngqdrrj3RIM%

2. The server answers OK and returns the tokens. Also returned Sessions cookies XSESSIONID and more (omited).

Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n
oauth_token=2BTJEXPZHWRY2CJD5YVHOQUEMD0WVPNKASLP2WDCLMGYN2ZB&oauth_token_secret=GBMKJYOK0C4EVWMISZHQQPC3POPJADECRNABKT1SX2ZNB0DO


3. The client sends the authorize request with the oauth_token:

/oauth/authorize?oauth_token=2BTJEXPZHWRY2CJD5YVHOQUEMD0WVPNKASLP2WDCLMGYN2ZB


4. The server redirects the client to the server’s authentication page, still referencing the oauth_token.

Request URI: /login?continue=%2Foauth%2Fauthorize%3Foauth_token%3D2BTJEXPZHWRY2CJD5YVHOQUEMD0WVPNKASLP2WDCLMGYN2ZB

5. After the user login into the server application it is redirected to the allow/deny page.

http://foursquare.com/oauth/authorize?oauth_token=2BTJEXPZHWRY2CJD5YVHOQUEMD0WVPNKASLP2WDCLMGYN2ZB

6. When the user allows the permission, the server calls the callback URL on the client sending it the new access token.


http://tripsqr.appspot.com/foursquare/callback?oauth_token=2BTJEXPZHWRY2CJD5YVHOQUEMD0WVPNKASLP2WDCLMGYN2ZB

7. With this new token, and with the secret token from step 2. A call is made to the Access Url on the server.

[truncated]
oauth/access_token
oauth_nonce=83129211&oauth_timestamp=1280932954&oauth_consumer_key=NO2ML1KLHEEPWMUQZPZSIOIGWX3LEBOTBYXTSIHECZ02WVL1&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_token=URC5OUC55LZPGLMQPBRVKXGDECIH3HVGG3JWJKMPT1H4IUNM

8. The server returns the last two tokens that must be saved in the client for future use.

Te following is an example in python of Oauth against foursquare an twitter

First a couple of classes with the details















__author__ = 'cscarioni'

import oauth2 as oauth
import cgi as urlparse
from django.utils import simplejson

from StringIO import StringIO
class BaseOauth(object):
_oauthKey=None

_oauthSecret=None
_requestURL=None
_accessURL=None
_authorizeURL=None

def __init__(self,oauthKey,oauthSecret,requestURL,accessURL,authorizeURL):

self.oauthKey=oauthKey
self.oauthSecret=oauthSecret
self.requestURL=requestURL

self.accessURL=accessURL
self.authorizeURL=authorizeURL
def requestAuthorization(self,dictionary):

consumer = oauth.Consumer(self.oauthKey, self.oauthSecret)

client = oauth.Client(consumer)
resp, content = client.request(self.requestURL, "GET")

if resp['status'] != '200':
raise Exception("Invalid response %s." % resp['status'])

request_token = urlparse.parse_qs(content)
dictionary["secret"]=request_token["oauth_token_secret"][0]

return "%s?oauth_token=%s" % (self.authorizeURL, request_token['oauth_token'][0])

def getAccessTokens(self,oauthtoken,dictionary):
consumer = oauth.Consumer(self.oauthKey, self.oauthSecret)

token=oauth.Token(oauthtoken,dictionary["secret"])
client = oauth.Client(consumer,token)

resp, content = client.request(self.accessURL, "POST")

if resp['status'] != '200':
raise Exception("Invalid response %s." % resp['status'])

access_token = urlparse.parse_qs(content)
return access_token["oauth_token"][0],access_token["oauth_token_secret"][0]

def requestWithOauthJSON(url, key, secret, http_method="GET", post_body=None,http_headers=None):

consumer = oauth.Consumer(self.oauthKey, self.oauthSecret)

token = oauth.Token(key, secret)
client = oauth.Client(consumer, token)

resp, content = client.request(
url,

method=http_method,
body=post_body,
headers=http_headers

)
return simplejson.load(StringIO(content))

class FoursquareOauth(BaseOauth):

def __init__(self):
super(FoursquareOauth,self).__init__(

"xxxxxxxxxx",
"xxxxxxxxx",
"http://foursquare.com/oauth/request_token",
"http://foursquare.com/oauth/access_token",
"http://foursquare.com/oauth/authorize"

)
class TwitterOauth(BaseOauth):
def __init__(self):

super(TwitterOauth,self).__init__(
"xxxxxxxx",
"xxxxxxxxxx",

"https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
"https://api.twitter.com/oauth/authorize"
)






which can be used from client code like:












def associateFoursquareAccount(request):
return HttpResponseRedirect(foursquareOauth.requestAuthorization(request.session))

def foursquareCallback(request):
token,secretToken=foursquareOauth.getAccessTokens(request["oauth_token"],request.session)

user=User.gql("WHERE login = :login",login=request.session["userlogin"])

user[0].foursquareToken=token
user[0].foursquareTokenSecret=secretToken

user[0].put()
return HttpResponseRedirect("/")




3 comments:

Shankar Jha said...

This is a good blog to get a cick start on OAuth. Thanks

Unknown said...

Glad you liked it :)

Skylar Wells said...

I read your article on OAuth. Are you available as a consultant to join a project that requires OAuth? If so, please email me at skylar@skysuiteinc.com to schedule a call to discuss consulting role and compensation. Thank you.

Skylar Wells
http://www.skysuiteinc.com