Friday, May 4, 2007

AOL OpenAuth and Atom Publishing Protocol

I'm looking to see how best to implement Atom-compatible authentication for AOL's OpenAuth service.  The service provides ways for users to authenticate themselves and to grant permissions to services to do things such as read buddy lists on behalf of a user.  These permissions are encapsulated in a portable token which can be passed around.  The primary use cases for this involve pure web based AJAX applications, so making this something that a generic application can deal with isn't fully specified.

So, here are my thoughts.  Let's say the client has a token string which encapsulates authentication and authorization.  They need to send this along with an Atom Publishing Protocol (APP) request. 

Windows Live and GData both implement custom RFC 2617 WWW-Authenticate: header schemes.  Unfortunately they don't follow exactly the same pattern, or I'd just copy it.  But using RFC 2617 is clearly the right approach if the server can support it.  So here's a proposal:

If a client has an OpenAuth token, it sends an Authorization: header.  The format looks like this:
Authorization: OpenAuth token="..."
where ... contains the base64-encoded token data (an opaque string, essentially).

When there is a problem, or the Authorization: header is missing, a 401 response is returned with a WWW-Authenticate: header.
401 Need user consent
...
WWW-Authenticate: OpenAuth realm="RealmString", fault="NeedConsent", url="http://my.screenname.aol.com/blah?a=boof&b=zed&...."
where the status code contains a human readable message, and the WWW-Authenticate header contains the precise fault code -- NeedToken, NeedConsent, ExpiredToken.  If present, the url parameter gives the URL of an HTML page which can be presented to the end user to login or grant permissions.  For example it can point to a login page if the fault is NeedToken.  A client would then need to do the following in response:
  1. Append a "&succUrl=..." parameter to the url, telling the OpenAuth service where to go when the user successfully logs in or grants permission. 
  2. Open a web browser or browser widget control with the given composed URL, and present to the user.
  3. Be prepared to handle an invocation of the succUrl with an appended token parameter, giving a new token to use for subsequent requests.
Note that the succUrl can be a javascript: URL, or a custom scheme (e.g., aim:) if your destination client is not a web browser.  Or it could be pointing to a local web server (http://localhost:1080/openauthcallback.cgi) or perhaps other schemes to get the token from point A to point B.  Whatever method is chosen, eventually the client will receive an OpenAuth token that it can use to try (or re-try) the Atom request.

As a wrinkle, to enhance autodiscovery, perhaps we should allow an "Authorization: OpenAuth" header with no token on any request (including HEAD).  The server could then respond with a 401 and fault="NeedToken", telling the client what URL to use for login authentication.  The interesting thing about this is that the protocol is then truly not tied to any particular authentication service -- anyone who implements this fairly simple protocol with opaque tokens can then play with anyone else.  The whole thing could be built on top of OpenID, for example. 

Perhaps this doesn't quite work.  I notice that the Flickr APIs don't do this, and instead have non-browsers establish a session with a client-generated unique key ("frob").  But this requires that users end up looking at a browser screen that tells them to return to their application to re-try the request.  Which the above scheme could certainly do as well, by making the succUrl point at such a page.  So is there a reason why Flickr doesn't redirect?  There's likely a gaping security hole here that I'm just missing.




No comments: