This document describes how a 3rd party site (consumer) can authenticate users using their FreedomConnector (provider) account. FreedomWorks uses this technique to implement single sign-on between sub-sites, but it may also be usable to non-FreedomWorks sites as well.
Terra Eclipse has developed a simple JSONP-based service, which can expose a limited amount of profile data to 3rd party sites via javascript.
The consumer embeds a javascript on their site, passing a callback name of their choice:
<script type="text/javascript" src="http://connect.freedomworks.org/session.json?callback=myCallback"></script>
The response, if the user is logged in, will look like:
HTTP/1.1 200 OK
Content-Type: text/javascript; charset=utf-8
myCallback({"uid":61,"name":"carlos8f","picture":"http:\/\/connect.freedomworks.org\/picture\/61?size=tiny","first":"Carlos","last":"Rodriguez"});
The consumer implements a javascript callback to receive the user data and treat the user as authenticated. If the user is not logged in, the response becomes:
HTTP/1.1 200 OK
Content-Type: text/javascript; charset=utf-8
myCallback({"uid":0,"name":"Anonymous"});
The consumer may then choose to redirect the user to log in via the provider site, as described below.
The server-side API is a modified OAuth workflow. It depends on the consumer receiving a challenge code, generating a cryptographic signature from it using a private key, which is then validated by the provider server.
Terra Eclipse generates a key pair for the consumer. Example:
client_id: f634c36fc3dac73ce03829f52ac35e38
private key: 0816c4b121b9065a81c1eb23defdadc6
Consumer server, upon receiving an authentication request, generates a cryptographic nonce (random string). Every nonce must be unique. The server responds with a 302 redirect, containing the client_id, redirect_uri, and nonce (parameters must be url-encoded, they are shown in plaintext here for reference):
Location: http://connect.freedomworks.org/oauth/authenticate
?client_id = f634c36fc3dac73ce03829f52ac35e38
&redirect_uri = http://my.server/process_return
&nonce = 1f75abde356ded945228f2b66203e82a
The consumer server stores the nonce in the session for later reference.
At the provider site, the user is authenticated. This might happen immediately if a session is active, or the user may have to log in or register. Upon completion, the user is redirected back to the redirect_uri. The consumer server is passed a challenge code as a GET variable:
Location: http://my.server/process_return
?code = AvEjvyT2oMi8jCdZmPfk5ivyQJI=
The consumer must then create a server-side HTTP request to the provider, containing a cryptographic signature of the code generated with the nonce and private key.
GET http://connect.freedomworks.org/oauth/access_token
?code = AvEjvyT2oMi8jCdZmPfk5ivyQJI=
&nonce = 1f75abde356ded945228f2b66203e82a
&signature = fIDhp5ibCLP4+L6jYnAsuuNbmD4=
The signature is generated with these steps:
- Concatenate the nonce with the private key.
- Generate a raw HMAC-SHA1 (binary) of the code, using the result of step 1 as the key.
- Base64-encode the result.
The provider server will send 200 OK response if the signature is correct:
HTTP/1.1 200 OK
Content-Type: text/javascript; charset=utf-8
{"access_token":"RtrDxq+\/vguM3PoHWPCY3HgKCP8=","account":{"uid":"61","name":"carlos8f","mail":"[email protected]",...}}
The response is a JSON object containing an access token and an account object. The user's UID, user name, first + last name, email address, and zip code can all be extracted from this object.
The access_token can be used to fetch the user data at a later time:
GET http://connect.freedomworks.org/api/me
?access_token = RtrDxq+/vguM3PoHWPCY3HgKCP8=
The response will be the same as above, only without the access_token.
Upon a validation error, the server will respond:
HTTP/1.1 400 Bad Request