API/SigningRequests

Not logged in - Log In / Register

Revision 3 as of 2008-07-31 17:47:07

Clear message

Signing Web Service Requests

The Launchpad web service hacking document describes a lot of requests you can send to edge.launchpad.net. But if you send them in the simple form presented in that document, you'll get a response code of 401 ("Unauthorized"). Launchpad's web service only responds to requests that have been digitally signed with a particular Launchpad user's authorization key.

This doesn't have to be *your* key. You can have a simple script that uses your own Launchpad authorization key, but you can also run a website that gathers its users' authorization keys and makes requests to the web service on their behalf. This is safe because these authorization keys have nothing to do with your Launchpad password. They're a way of delegating a limited set of privileges to some other program. If a program proves untrustworthy, you only have to revoke its key.

The standard HTTP authentication mechanisms (Basic and Digest) aren't sophisticated enough to handle these cases. That's why Launchpad has adopted the OAuth standard for authentication. It's a little more work to set up than just sending your Launchpad username and password to the web service, but it's more versatile and more secure.

If you're writing a console-based script based on [[../launchpadlib| launchpadlib]], you don't have to worry much about this. Launchpadlib will automatically open a browser window for your end-user and ask them to hit Return once they've granted your program access.

Otherwise, you'll need to implement a workflow like the one described below to get a set of Launchpad credentials for each of your users. Once you've got those credentials, the actual request signing is a mechanical process and there are lots of libraries to help you with it.

Getting credentials

A user can set up an authorization token from within Launchpad, by visiting http://www.launchpad.net/~{name}/+oauth-tokens. It's reasonable to ask your users to set up a token before they use your program, and provide their Launchpad credentials in a config file or as command-line arguments to your script. But you can also create a new set of credentials from within your application.

The basic workflow is always the same, but the details are different if you're writing a standalone application, versus creating a website.

Step 0: Pick a consumer key

The consumer key identifies your application and it should be hard-coded somewhere in your code. Everyone who uses your application will send the same consumer key.

We recommend you choose the name of your program as the consumer key. Don't append the version number unless you want your users to get new application keys for every new version. For this example I'll use the consumer key 'myconsumerkey'.

Step 1: Get a request token

Getting your program's user to create a new credential for the program is a multi-step process. The request token is a unique string that Launchpad uses to keep track of your program between steps.

To obtain a request token, send a POST request to http://www.launchpad.net/+request-token. (Note: *not* edge.launchpad.net!) This is the same kind of POST a web browser does when it submits a form. You should submit the following values in form-encoded format.

So the HTTP request might look like this:

    POST /+request-token HTTP/1.1
    Host: www.launchpad.net
    Content-type: application/x-www-form-urlencoded

    oauth_consumer_key=myconsumerkey&signature_method=PLAINTEXT&oauth_signature=%26

The response should look like this:

    200 OK

    oauth_token_secret=&oauth_token={request token}

oauth_token_secret will be empty; we don't use it. oauth_token will be a random-looking string of letters and digits. Save this for step 3.

Step 2: Authenticate the user

Now the user needs to 1) log in to Launchpad, and 2) tell Launchpad how much authority they're delegating to your program. You need to get them to visit the following URL in their web browser:

    http://www.launchpad.net/+authorize-token?oauth_token={request token}

Step 2a: If you're building a website

If your program is a website that your users visit, you can send them an HTTP redirect. Be sure to also specify the 'oauth_callback' field as a URL on your website.

    http://www.launchpad.net/+authorize-token?oauth_token={request token}&oauth_callback={URL to within your website}

Once the user delegates some of their privileges to your website Launchpad will redirect the user back to that URL, so that they can resume using your site.

Step 2b: If you're writing a stand-alone program

If your program runs on the clients' computer rather than through their web browser, you don't have to worry about redirecting back to your web page. But you do have to worry about opening the Launchpad page in their web browser in the first place. Take a look at the open_url_in_browser() function defined in launchpadlib's launchpad.py; it works well on most Linux systems. Just open up their web browser to the +authorize-token page.

If your program isn't running in the web browser, how are you supposed to know when the user is done with the +authorize-token page? There's no 'oauth_callback' equivalent that Launchpad can use to send a signal to your client-side program. What you need to do is have the _end-user_ tell you when they're done with +authorize-token.

The launchpadlib library prints an explanatory message after it opens +authorize-token in your web browser. It waits for the end-user to authorize access through their web browser, and then switch back to the launchpadlib window and hit return. If you're writing a GUI program, you can have the end-user click a button once they're done authorizing your program to talk to Launchpad on their behalf.

For an example of good interface design around these constrains, look at [[http://www.downloadsquad.com/2006/08/25/flickr-uploading-on-linux-pt-3-f-spot/| F-Spot's Flickr integration]. The first time you export a photo to Flickr you need to click an "Authorize" button. This opens up a web browser to a page on Flickr. You log in to Flickr and authorize F-Spot to access the Flickr web service on your behalf. Then you go back to F-Spot and click a "Complete Authorization" button. After that point, F-Spot can talk to Flickr with your credentials.

(Flickr doesn't use OAuth, but its system has the same architecture as OAuth, so the user interface can work the same way.)

Step 3: Exchange the request token for an access token

You can't do much with the request token. It's only good for coordinating with Launchpad while the user decides whether or not to let you make web service requests in their name. Once the user has delegated some of their authority to you, you need to exchange the request token for a new token that has their permissions associated with it.

If you're writing a website, you'll know this happens when Launchpad redirects your user back to the URL you specified as 'oauth_callback'. If you're writing a client-side program, you'll know when your user clicks the "Complete Authorization" button or hits enter or whatever it was you told them to do when they were done on the Launchpad side.

Now you make a GET request to http://www.launchpad.net/+access-token. Provide the following data in the query string:

So the URL you GET should look like this:

    http://www.launchpad.net/+access-token?oauth_token={request token}&oauth_signature=%26

Basically, you're looking up a record using the request token as a key. The record was created when the end-user told Launchpad it was okay to delegate their authorization to you.

You should get a response that looks like this:

    200 OK
    oauth_token={access token}&oauth_token_secret={access token secret}

Put those two pieces of information in some persistent storage. You'll need them as part of every request you make to Launchpad's web service.

Using the credentials

Now that you've got an access token and a secret for a particular Launchpad user, you won't have to go through that again for that user. But there's still the matter of digitally signing your requests with that token.

Unlike the process of getting credentials, which is pretty specific to Launchpad, the process of digitally signing a request is completely mechanical. The mechanics are covered in detail in the OAuth standard, and there are also OAuth libraries in most popular programming languages that can sign an HTTP request given an access token and secret. So I'm not going to go into much detail on how to actually sign a request. It's a general problem and there are plenty of places to go if you need help, and lots of sample code to look at.