Bitter Coder
sour code and astringent experiences
Wednesday, June 11, 2008
OAuth for Beginners
OAuth for Beginners
For those unfamiliar with OAuth, here's a very short run-down... I'm skipping over some of the details but I think this should give you a taste for what it's all about - for a more well rounded introduction, check out this
article
on the
OAuth.Net
website.
The participants
Consumer - "weitu.googlepages.com" - that application that wants to see protected information the provider has for a user.
Provider - "google.com" - the keeper of a users protected information.
User - a user who stores protected information with the provider (say contacts in gmail)
The goal
To allow the user to give a consumer access to their data on the provider without the user having to disclose their credentials (username & password) and to allow for fine-grained control over access granted to an individual consumer - i.e. putting power in the hands of the user to revoke access when they want to, and having it only affect one consumer.
A consumer needs to be known to a provider before they can request a token.
How it works
(For this example we'll use google, for more info on the google implementation see this
thread
)
The provider publishes 3 Urls for their service and documents them on their site somewhere:
Request Token Url -
https://www.google.com/accounts/OAuthGetRequestToken
User Authorize Url -
https://www.google.com/accounts/accounts/OAuthAuthorizeToken
Access Token Url -
https://www.google.com/accounts/OAuthGetAccessToken
The consumer is known to google by it's consumer key (which in the case of a google api is normally a host address, like www.test.com) and this relationship is established in a proprietary manor (i.e. it's not covered by the OAuth spec).
Getting a Request Token
The start the ball rolling the consumer makes a request to the Request Token Url, they get back some form-encoded parameters in the body of the response which contains the token information.
As an example, here's an http request to get a new request token:
GET /accounts/OAuthGetRequestToken?
scope=http%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds
&oauth_nonce=759437c3-3edf-4098-ac14-58d4f162b0e6
&oauth_consumer_key=weitu.googlepages.com
&oauth_signature_method=RSA-SHA1
&oauth_timestamp=1213129078
&oauth_version=1.0
&oauth_token=
&oauth_signature=peUZigwq1BLs%2Bb721vcct2vzA3Odk1j...
HTTP/1.1
Host: www.google.com
Connection: Keep-Alive
And here's the response:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Date: Tue, 10 Jun 2008 20:18:01 GMT
Expires: Tue, 10 Jun 2008 20:18:01 GMT
Cache-Control: private, max-age=0
Content-Length: 51
Server: GFE/1.3
oauth_token=CMiJx-LdFxD56bOXAQ&oauth_token_secret=
Notice the oauth_signature and other oauth_ etc. parameters - as part of the OAuth core specification it requires that requests be "signed" so that a provider can ensure they haven't been tampered with - this is one of the aspects my library will take care of for you (signing and verifying requests).
User Authorization
At that point the consumer now needs to send the user off to the providers site - this involves using the second of the 3 urls, the User Authorize Url... we just append the scope (required by google, identifies the service you wish to access - not part of OAuth spec itself) and the request token (CMiJx-LdFxD56bOXAQ)
Note that the User Authorize Url isn't signed like the other requests... this is because this step may be manual i.e. a user typing or copying a link into their browser or some hand held device.
GET /accounts/accounts/OAuthAuthorizeToken?
scope=http://www.google.com/m8/feeds
&oauth_token=CMiJx-LdFxD56bOXAQ
HTTP/1.1
In this case, google takes us to a universal login page:
Once authenticated it then takes us to a page where we can authorize the consumer to have access:
By granting access at this point the consumer can then use the last of the 3 Urls, the Access Token Url, to exchange their request token for an access token. Upon granting access a few things should happen:
An access token should be created.
The access token should be related to the request token.
The currently logged in user should be associated with the access token.
The last point is important - because you're passing tokens around, rather than account names, you need to have the provider implementation record the association between the access token and the user granting access - and it should be easy for your API implementation to fetch the associated user when a protected resource is accessed.
Exchanging Tokens
Once the user has authorized the consumers access request, the consumer can then exchange their request token for an access token - generally a request token can only be used once - so if the request failed for some reason they would need to start the authorization process again from scratch.
here's the http request for exchanging tokens:
GET /accounts/OAuthGetAccessToken?
scope=http%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds
&oauth_token=CMiJx-LdFxD56bOXAQ
&oauth_nonce=19fe6f62-8b2c-4a40-b055-210d279ba770
&oauth_consumer_key=weitu.googlepages.com
&oauth_signature_method=RSA-SHA1
&oauth_timestamp=1213129477
&oauth_version=1.0
&oauth_signature=hagokrS1W%2BcBXdRwTIlOd84PSO56OT...
HTTP/1.1 Host: www.google.com
And the corresponding response from the google server:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Date: Tue, 10 Jun 2008 20:24:39 GMT
Expires: Tue, 10 Jun 2008 20:24:39 GMT
Cache-Control: private, max-age=0
Content-Length: 57
Server: GFE/1.3
oauth_token=CNO384n8BRD6pZTT_P____8B&oauth_token_secret=
Accessing a Protected Resource
Now that the consumer has an access token they can then make requests for protected resources - they just need to use the access token, here's an example of doing just that:
GET /m8/feeds/contacts/default/base?
scope=http%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds
&oauth_token=CNO384n8BRD6pZTT_P____8B
&oauth_nonce=3ae44855-9d27-4b80-8b4f-2f68d1531657
&oauth_consumer_key=weitu.googlepages.com
&oauth_signature_method=RSA-SHA1
&oauth_timestamp=1213129479
&oauth_version=1.0
&oauth_signature=kTFRbcD1IKzjPADfgF%2B3...
HTTP/1.1 Host: www.google.com
Obviously once the request has been validated (i.e. valid signature, valid token, valid timestamp range, nonce is unique etc.) the provider implementation needs to fetch the user associated with the access token, so it can then return the correct data back to the consumer - normally you would want to automatically associate the token's user with the current request / controller / channel so that OAuth is basically transparent (i.e. it's just like getting a request from a user who's authenticated normally).
Risks & Issues
One obvious risk is that of phishing... if the consumer sends you to a site that looks like googles authentication page, but isn't google then you're in trouble. Of course this kind of phishing is more a general problem, then something isolated to OAuth.
Another potential risk are that some signature methods are risky/flawed to the
consumer
due to implementation i.e. if you have a flickr uploader winforms application, and you use RSA-SHA1, the uploader will need to ship with the x509 certificate (including the private key) in their application ... this basically invalidates the strength of that certificate, because anyone could extract and use the private key themselves (so it's as bad as a plain text signature) - on the flip side for a website RSA-SHA1 is very strong because the private key is kept private.
OAuth
posted @ Tuesday, June 10, 2008 9:26:02 PM (New Zealand Standard Time, UTC+12:00)
Comments [6]
|
Trackback
|
Tracked by:
"OAuth .Net implementation" (Bitter Coder)
[Trackback]
"OAuth for Beginners" (DotNetKicks.com)
[Trackback]
"OAuth channel for WCF RESTful services" (Pablo M. Cibraro (aka Cibrax) )
[Trackback]
Wednesday, June 11, 2008 7:33:26 AM (New Zealand Standard Time, UTC+12:00)
>Note that the User Authorize Url isn't signed like the other requests...
>this is because this step may be manual i.e. a user typing or copying a link
>into their browser or some hand held device.
This kind of behavior looks similar to OpenID: anyway it's possible to use AFAIK OAuth for WebServices, like RESTful Web Services? I mean a machine-to-machine authentication mechanism, that not involves the user (that of course must specify your user/pw in the client app).
Diego Guidi
Wednesday, June 11, 2008 8:03:59 AM (New Zealand Standard Time, UTC+12:00)
The user is involved in the initial granting or denying of access - but beyond that OAuth is definitely a machine-to-machine authentication mechanism, the signing procedure is too complex for a user to handle themselves for starters.
Once the initial relationship is established the client (consumer) can store and continue using a previously fetched access token for as long as it's valid (i.e. until it either expires, or the user revoked it) - the initial dance of exchanging request and access tokens and user authorization is a "once off" that just needs to occur to establish trust/authorization between consumer and provider for a users data.
Make sense?
Alex Henderson
Wednesday, June 11, 2008 1:21:22 PM (New Zealand Standard Time, UTC+12:00)
Thanks a lot for the response, I need to know in deep how to OAuth work before to ask for other questions... BTW All I want to do is a REST webservice that is accessible both from WebApps and from J2ME apps, so I hope that J2ME could fit into my needs ;)
Diego Guidi
Wednesday, June 11, 2008 8:18:58 PM (New Zealand Standard Time, UTC+12:00)
I think OAuth can certainly help you achieve that - the only thing is to be careful of which signature method you use depending on the platform - worth checking out on the OAuth google group, there have been a few discussions there about this.
Alex Henderson
Thursday, July 10, 2008 4:15:19 PM (New Zealand Standard Time, UTC+12:00)
Great article. Really clarified the flow. Thanks for this!
Pat Niemeyer
Thursday, July 10, 2008 7:46:11 PM (New Zealand Standard Time, UTC+12:00)
Glad it helped Pat :)
Alex Henderson
Comments are closed.
© Copyright 2008 Alex Henderson
Theme design by
Bryan Bell
newtelligence dasBlog 1.9.6264.0
| Page rendered at Saturday, November 22, 2008 4:36:17 AM (New Zealand Daylight Time, UTC+13:00)
Search
FeedCount
Tags...
.Net (82)
.Net Reactor (4)
.net user groups (9)
2008SummerRoadTrip (1)
ActiveRecord (1)
architecture chat (54)
ArchitectureCamp2007 (2)
asp.net (1)
Astoria (1)
Auckland (1)
base4 (9)
batching (1)
binsor (1)
blog (4)
books (1)
C# 3.0 (9)
cambodia (9)
CAML.Net (1)
castle (39)
china (8)
codecamp (2)
codeplex (3)
dapper.net (1)
DevDefined Ltd. (4)
DirectShow.Net (1)
DLR (1)
DSL (3)
EAUG (1)
Enterprise Architect (5)
Enterprise Library (1)
F# (1)
feedburner (2)
Friendster (1)
generics (1)
googlegears (1)
hacks (3)
hardware (3)
hongkong (2)
hyper-v (1)
ideas (1)
IoC (21)
IronPython (13)
IronRuby (2)
jobs (1)
Languages (2)
laos (8)
LINQ (7)
LiveId (1)
LLU (1)
Local Government (1)
MDA (1)
MDD (1)
microsoft (1)
Model Driven Development (1)
mono (1)
monorail (2)
Movies (1)
Music (1)
nDepend (1)
news (1)
NHibernate (2)
NUnit (2)
nvelocity (1)
OAuth (6)
office (1)
OpenSocial (1)
orcon (1)
photos (1)
php (1)
PostSharp (1)
powerpoint (1)
presentations (1)
ReSharper (1)
REST (2)
rhino commons (2)
rhinomocks (5)
Ruby (1)
SaaS (1)
scm (1)
Screen Architect (1)
SharePoint (5)
silverlight (1)
Splicer (4)
SQL2008 (1)
supcom (1)
svn (1)
Syzmk (4)
thailand (6)
Tools (2)
Tortoise SVN (1)
trac (2)
Travel (36)
Unity (2)
vietnam (7)
vista (2)
vmware (1)
volta (3)
VS2008 (1)
WCF (3)
wiki (2)
wikipedia (1)
Windows Server 2008 (1)
windsor (6)
WinForms (1)
wix (2)
WPF (2)
xmlrpc (1)
yahoo pipes (1)
Who am I?
Alex Henderson
Auckland
, New Zealand
Managing Director at
Dev|Defined Limited
"Self Confessed Coding Junky for 15 years"
Mobile:
+64-21-402-969
Email:
bittercoder 'at' gmail 'dot' com
MSN:
bittercoder_nz@hotmail
Skype:
alex.devdefined
Navigation
My Bookmarks (Delicious)
My GoogleReader - shared items
My Photos on Flickr
My Wiki
Catch NZ Limited
DevDefined Limited
tools.devdefined.com (Trac site)
New Zealand DotNet User Group
Screen Architect
Seismic Technologies (Syzmk)
Splicer - The .Net Video Splicing Library
On this page....
Blogs I read by New Zealanders...
Alex James
André Meurer @ Olympic Software
Andrew Dixon
Andrew Peters
Bennie Johnston
Blog:: Craig Pringle
Blogging is probably just a fad, but just in case...
Buzzrick's TileEngine Game Platform
Chris Auld
Chris Crowe's Blog
Chris Johnson
Clifton Johnston
Code Climber
Craig Box
Daniel
Daniel Wissa
Darryl Burling
Dave Dustin
Duncan Bayne
Floyd Burgess
Gabriel Smith
Geekzone blog
Grant Archibald
Grant Drake
Ivan Porto Carrero
Ivan Towlson
Jeremy Boyd
Jithen Singh
John-Daniel Trask
Josh Hektor
Juha Saarinen
Keith Nicholas
Kevin Daly
Mark Rees
Maruis Marais
Mauricio Freitas
Mindscape
My Blog (Alex Henderson)
Nathan Mercer
Nic Wise
Nick's Blog
Nigel Parker
Paul Andrew
Paul Lo
Peter Jones
Phil Cockfield
Public Address
Rod Drury
Sean McBreen
Simeon Pilgrim
Software Development and stuff
Stefan Schulz
Steve Schapel
Steven Kempton
The Blog of Dave5
The Book Diary
The Voice Of Reason New Zealand
Thoughts from Mirality
Tim Haines
Blogs I read on Castle...
Andrew Hallock
Ayende
Brian Romanko
Dan Bunea
Dru Sellers
Eleutian SpeakENG Development Blog
Gabriel Schenker
Hamilton Verissimo
Insane World
Insert Catchy Title Here
Jeff Brown
Ken Egozi
Marc-André Cournoyer's blog
Matt Berther
Nick Parker
Roy Osherove
Roy Tate
Technorati: http://castleproject.org
Wendy Friedlander
BlogMap
Del.icio.us
Wishlists
Sign In