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 URLIt 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 secretGET /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("/")
|