Diff for "API/SigningRequests"

Not logged in - Log In / Register

Differences between revisions 5 and 7 (spanning 2 versions)
Revision 5 as of 2008-07-31 23:31:05
Size: 9232
Editor: cpe-24-193-113-134
Comment:
Revision 7 as of 2008-08-01 01:42:11
Size: 20449
Editor: cpe-24-193-113-134
Comment:
Deletions are marked like this. Additions are marked like this.
Line 10: Line 10:
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

---- /!\ '''Edit conflict - other version:''' ----
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

---- /!\ '''Edit conflict - your version:''' ----
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

---- /!\ '''End of edit conflict''' ----
Line 16: Line 24:
some other program. If a program proves untrustworthy, you only have
to revoke its key.

---- /!\ '''Edit conflict - other version:''' ----
some other program. If a program proves untrustworthy, the user only
needs to revoke that program's key.

---- /!\ '''Edit conflict - your version:''' ----
some other program. If a program proves untrustworthy, the user only
needs to revoke that program's key.

---- /!\ '''End of edit conflict''' ----
Line 30: Line 46:
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.
---- /!\ '''Edit conflict - other version:''' ----
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. The actual request signing is a mechanical process and there
are lots of libraries to help you with it.

---- /!\ '''Edit conflict - your version:''' ----
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. T
he actual request signing is a mechanical process and there
are lots of libraries to help you with it.

---- /!\ '''End of edit conflict''' ----
Line 36: Line 65:
visiting http://www.launchpad.net/~{name}/+oauth-tokens. It's
---- /!\ '''Edit conflict - other version:''' ----
visiting http://www.launchpad.net/people/+me/+oauth-tokens. It's

---- /!\ '''Edit conflict - your version:''' ----
visiting http://www.launchpad.net/people/+me/+oauth-tokens. It's

---- /!\ '''End of edit conflict''' ----
Line 45: Line 81:


---- /!\ '''Edit conflict - other version:''' ----


---- /!\ '''Edit conflict - your version:''' ----

---- /!\ '''End of edit conflict''' ----
Line 63: Line 107:
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.

---- /!\ '''Edit conflict - other version:''' ----
https://edge.launchpad.net/+request-token. (Note: *not*
api.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-URLencoded format.

---- /!\ '''Edit conflict - your version:''' ----
https://edge.launchpad.net/+request-token. (Note: *not*
api.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-URLencoded format.

---- /!\ '''End of edit conflict''' ----
Line 76: Line 130:
    Host: www.launchpad.net
---- /!\ '''Edit conflict - other version:''' ----
    Host: edge.launchpad.net
Line 79: Line 135:
    oauth_consumer_key=myconsumerkey&signature_method=PLAINTEXT&oauth_signature=%26
}}}

The response should look like this:
    oauth_consumer_key=just+testing&signature_method=PLAINTEXT&oauth_signature=%26
}}}

The response should look something like this:

---- /!\ '''Edit conflict - your version:''' ----
    Host: edge.launchpad.net
    Content-type: application/x-www-form-urlencoded

    oauth_consumer_key=just+testing&signature_method=PLAINTEXT&oauth_signature=%26
}}}

The response should look something like this:

---- /!\ '''End of edit conflict''' ----
Line 87: Line 154:
    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.

---- /!\ '''Edit conflict - other version:''' ----
    oauth_token=9kDgVhXlcVn52HGgCWxq&oauth_token_secret=jMth55Zn3pbkPGNht450XHNcHVGTJm9Cqf5ww5HlfxfhEEPKFflMqCXHNVWnj2sWgdPjqDJNRDFlt92f
}}}

Save these two pieces of information, ''oauth_token'' and
''oauth_token_secret'': you'll need them to sign the request in step
3.

---- /!\ '''Edit conflict - your version:''' ----
    oauth_token=9kDgVhXlcVn52HGgCWxq&oauth_token_secret=jMth55Zn3pbkPGNht450XHNcHVGTJm9Cqf5ww5HlfxfhEEPKFflMqCXHNVWnj2sWgdPjqDJNRDFlt92f
}}}

Save these two pieces of information, ''oauth_token'' and
''oauth_token_secret'': you'll need them to sign the request in step
3.

---- /!\ '''End of edit conflict''' ----
Line 100: Line 180:
    http://www.launchpad.net/+authorize-token?oauth_token={request token}
}}}

---- /!\ '''Edit conflict - other version:''' ----
    https://edge.launchpad.net/+authorize-token?oauth_token={oauth_token}
}}}

Where ''oauth_token'' is the string you got at the end of step 1.


---- /!\ '''Edit conflict - your version:''' ----
    https://edge.launchpad.net/+authorize-token?oauth_token={oauth_token}
}}}

Where ''oauth_token'' is the string you got at the end of step 1.


---- /!\ '''End of edit conflict''' ----
Line 106: Line 200:
an HTTP redirect. Be sure to also specify the 'oauth_callback' field
---- /!\ '''Edit conflict - other version:''' ----
an HTTP redirect. Be sure to also specify the ''oauth_callback'' field

---- /!\ '''Edit conflict - your version:''' ----
an HTTP redirect. Be sure to also specify the ''oauth_callback'' field

---- /!\ '''End of edit conflict''' ----
Line 110: Line 211:
    http://www.launchpad.net/+authorize-token?oauth_token={request token}&oauth_callback={URL to within your website}
---- /!\ '''Edit conflict - other version:''' ----
    https://edge.launchpad.net/+authorize-token?oauth_token={oauth_token}&oauth_callback={URL to within your website}

---- /!\ '''Edit conflict - your version:''' ----
    https://edge.launchpad.net/+authorize-token?oauth_token={oauth_token}&oauth_callback={URL to within your website}

---- /!\ '''End of edit conflict''' ----
Line 132: Line 240:
_end-user_ tell you when they're done with +authorize-token.
---- /!\ '''Edit conflict - other version:''' ----
''end-user themselves'' tell you when they're done with
the +authorize-token page.

---- /!\ '''Edit conflict - your version:''' ----
''end-user themselves'' tell you when they're done with
the +authorize-token page.

---- /!\ '''End of edit conflict''' ----
Line 141: Line 258:
For an example of good interface design around these constrains, look
---- /!\ '''Edit conflict - other version:''' ----
For an example of good interface design around these constraints, look
Line 143: Line 262:
[[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.
[[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.

---- /!\ '''Edit conflict - your version:''' ----
For an example of good interface design around these constraints, 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.

---- /!\ '''End of edit conflict''' ----
Line 156: Line 289:
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

---- /!\ '''Edit conflict - other version:''' ----
The ''oauth_token'' and ''oauth_token_secret'' you got in Step 1 are real
OAuth keys that can be used to sign requests, but you're only going to
use them once. Their only purpose is to remind Launchpad who you are;
remember, it hasn't heard from you since step 1. Once the user has
delegated some of their authority to you, you need to exchange these
temporary credentials for permanent credentials that has the
end-user's permissions associated with them.

If you're writing a website, you'll know you're ready when Launchpad
Line 165: Line 301:
'oauth_callback'. If you're writing a client-side program, you'll know ''oauth_callback''. If you're writing a client-side program, you'll know

---- /!\ '''Edit conflict - your version:''' ----
The ''oauth_token'' and ''oauth_token_secret'' you got in Step 1 are real
OAuth keys that can be used to sign requests, but you're only going to
use them once. Their only purpose is to remind Launchpad who you are;
remember, it hasn't heard from you since step 1. Once the user has
delegated some of their authority to you, you need to exchange these
temporary credentials for permanent credentials that has the
end-user's permissions associated with them.

If you're writing a website, you'll know you're ready 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

---- /!\ '''End of edit conflict''' ----
Line 170: Line 321:
Now you make a GET request to
http://www.launchpad.net/+access-token. Provide the following data in
the query string:

  * oauth_token: Your request token from step 1
  * oauth_signature: The string '&'

So the URL you GET should look like this:

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

---- /!\ '''Edit conflict - other version:''' ----
Now you make a POST request to
https://edge.launchpad.net/+access-token. The body should be a set of
form-encoded parameters, as in Step 1. You need to provide the
following parameters:


  * oauth_token: The same as ''oauth_token'' from step 1
  * oauth_consumer_key: The same as in step 1
  * oauth_signature_method: The string "PLAINTEXT"
  * oauth_signature: The OAuth signature, calculated using [[http://oauth.net/core/1.0/#anchor22| the PLAINTEXT algorithm]] and the ''oauth_token_secret' from step 1

The last one is the tricky one. The OAuth standard has the details,
but basically you take the string '&' and stick the ''oauth_token_secret''
you got at the end of step 1 onto the end. (The reason you start with
the string '&' is that Launchpad doesn't use OAuth Consumer Secrets.)

So your POST request should look like this:

{{{
    POST /+access_token
    Host: edge.launchpad.net
    Content-type: application/x-www-form-urlencoded

    oauth_signature=%26jMth55Zn3pbkPGNht450XHNcHVGTJm9Cqf5ww5HlfxfhEEPKFflMqCXHNVWnj2sWgdPjqDJNRDFlt92f&oauth_consumer_key=just+testing&oauth_token=9kDgVhXlcVn52HGgCWxq&oauth_signature_method=PLAINTEXT

---- /!\ '''Edit conflict - your version:''' ----
Now you make a POST request to
https://edge.launchpad.net/+access-token. The body should be a set of
form-encoded parameters, as in Step 1. You need to provide the
following parameters:


  * oauth_token: The same as ''oauth_token'' from step 1
  * oauth_consumer_key: The same as in step 1
  * oauth_signature_method: The string "PLAINTEXT"
  * oauth_signature: The OAuth signature, calculated using [[http://oauth.net/core/1.0/#anchor22| the PLAINTEXT algorithm]] and the ''oauth_token_secret' from step 1

The last one is the tricky one. The OAuth standard has the details,
but basically you take the string '&' and stick the ''oauth_token_secret''
you got at the end of step 1 onto the end. (The reason you start with
the string '&' is that Launchpad doesn't use OAuth Consumer Secrets.)

So your POST request should look like this:

{{{
    POST /+access_token
    Host: edge.launchpad.net
    Content-type: application/x-www-form-urlencoded

    oauth_signature=%26jMth55Zn3pbkPGNht450XHNcHVGTJm9Cqf5ww5HlfxfhEEPKFflMqCXHNVWnj2sWgdPjqDJNRDFlt92f&oauth_consumer_key=just+testing&oauth_token=9kDgVhXlcVn52HGgCWxq&oauth_signature_method=PLAINTEXT

---- /!\ '''End of edit conflict''' ----
Line 185: Line 379:
okay to delegate their authorization to you.

You should get a response that looks like this:

---- /!\ '''Edit conflict - other version:''' ----
okay to delegate their authorization to you. The request token secret
proves that you're the same client as went through step 1.

You should get a response that looks something like this:

---- /!\ '''Edit conflict - your version:''' ----
okay to delegate their authorization to you. The request token secret
proves that you're the same client as went through step 1.

You should get a response that looks something like this:

---- /!\ '''End of edit conflict''' ----
Line 191: Line 396:
    oauth_token={access token}&oauth_token_secret={access token secret}
}}}

Put those two pieces of information in some persistent storage. You'll

---- /!\ '''Edit conflict - other version:''' ----
    oauth_token=PsK9cpbll1KwehhRDckr&oauth_token_secret=M2hsnmsfEIAjS3bTWg6t8X2GKhlm152PRDjLLmtQdr9C8KFZWPl9c8QbLfWddE0qpz5L56pMKKFKEfv1&lp.context=None
}}}

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


---- /!\ '''Edit conflict - your version:''' ----

---- /!\ '''End of edit conflict''' ----

---- /!\ '''Edit conflict - other version:''' ----

---- /!\ '''Edit conflict - your version:''' ----
So your POST request should look like this:

{{{
    POST /+access_token
    Host: edge.launchpad.net
    Content-type: application/x-www-form-urlencoded

    oauth_signature=%26jMth55Zn3pbkPGNht450XHNcHVGTJm9Cqf5ww5HlfxfhEEPKFflMqCXHNVWnj2sWgdPjqDJNRDFlt92f&oauth_consumer_key=just+testing&oauth_token=9kDgVhXlcVn52HGgCWxq&oauth_signature_method=PLAINTEXT
}}}

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. The request token secret
proves that you're the same client as went through step 1.

You should get a response that looks something like this:

{{{
    200 OK

    oauth_token=PsK9cpbll1KwehhRDckr&oauth_token_secret=M2hsnmsfEIAjS3bTWg6t8X2GKhlm152PRDjLLmtQdr9C8KFZWPl9c8QbLfWddE0qpz5L56pMKKFKEfv1&lp.context=None
}}}

Put those two pieces of information, ''oauth_token' and
''oauth_token_secret'', in some persistent storage. They replace the
''oauth_token'' and ''oauth_token_secret'' you got in step 1. You'll
Line 197: Line 441:


---- /!\ '''End of edit conflict''' ----
Line 210: Line 457:
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.
HTTP request given an ''oauth_token'' and an
''oauth_token_secret''. It's also very similar to the request signing
you did in step 3. 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.

I will say that Launchpad currently only supports the first of OAuth's
[[http://oauth.net/core/1.0/#consumer_req_param| three ways of encoding the consumer request parameters].
You'll need to put your digital signatures into the Authorization
header, using the [[http://oauth.net/core/1.0/#auth_header| OAuth HTTP Authorization Scheme]].
That means making HTTP requests that look like this:

{{{
    GET /beta/bugs/11
    Accept: application/json
    Authorization: OAuth realm="https://api.launchpad.net/",
                oauth_consumer_key="just+testing",
                oauth_token="PsK9cpbll1KwehhRDckr",
                oauth_signature_method="PLAINTEXT",
                oauth_signature="%26M2hsnmsfEIAjS3bTWg6t8X2GKhlm152PRDjLLmtQdr9C8KFZWPl9c8QbLfWddE0qpz5L56pMKKFKEfv1",
                oauth_timestamp="1217548916",
                oauth_nonce="51769993",
                oauth_version="1.0"
}}}

If you put that ''oauth_*'' data into the entity-body of your POST
requests or the query strings of your GET requests, Launchpad won't
pick it up and you won't be able to access the web service.

What does all that data mean? The ''oauth_consumer_key'' identifies
your client software; it's the same string you've been using since
step 1. The ''oauth_token'' and ''oauth_signature'' identify the
Launchpad credentials your user set up for you to use; you got these
in step 3, and the PLAINTEXT algorithm for generating
''oauth_signature'' is the same as in step 3. The ''oauth_nonce'' and
''oauth_timestamp'' are as defined [[http://oauth.net/core/1.0/#nonce| here].

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.


/!\ Edit conflict - other version:


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


/!\ Edit conflict - your version:


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


/!\ End of edit conflict


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


/!\ Edit conflict - other version:


some other program. If a program proves untrustworthy, the user only needs to revoke that program's key.


/!\ Edit conflict - your version:


some other program. If a program proves untrustworthy, the user only needs to revoke that program's key.


/!\ End of edit conflict


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, 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.


/!\ Edit conflict - other version:


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. The actual request signing is a mechanical process and there are lots of libraries to help you with it.


/!\ Edit conflict - your version:


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. The actual request signing is a mechanical process and there are lots of libraries to help you with it.


/!\ End of edit conflict


Getting credentials

A user can set up an authorization token from within Launchpad, by


/!\ Edit conflict - other version:


visiting http://www.launchpad.net/people/+me/+oauth-tokens. It's


/!\ Edit conflict - your version:


visiting http://www.launchpad.net/people/+me/+oauth-tokens. It's


/!\ End of edit conflict


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.


/!\ Edit conflict - other version:



/!\ Edit conflict - your version:



/!\ End of edit conflict


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


/!\ Edit conflict - other version:


https://edge.launchpad.net/+request-token. (Note: *not* api.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-URLencoded format.


/!\ Edit conflict - your version:


https://edge.launchpad.net/+request-token. (Note: *not* api.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-URLencoded format.


/!\ End of edit conflict


  • oauth_consumer_key: Your consumer key
  • signature_method: The string "PLAINTEXT"
  • oauth_signature: The string "&".

So the HTTP request might look like this:

    POST /+request-token HTTP/1.1

---- /!\ '''Edit conflict - other version:''' ----
    Host: edge.launchpad.net
    Content-type: application/x-www-form-urlencoded

    oauth_consumer_key=just+testing&signature_method=PLAINTEXT&oauth_signature=%26

The response should look something like this:


/!\ Edit conflict - your version:


  • Host: edge.launchpad.net Content-type: application/x-www-form-urlencoded

    oauth_consumer_key=just+testing&signature_method=PLAINTEXT&oauth_signature=%26

}}}

The response should look something like this:


/!\ End of edit conflict


    200 OK


---- /!\ '''Edit conflict - other version:''' ----
    oauth_token=9kDgVhXlcVn52HGgCWxq&oauth_token_secret=jMth55Zn3pbkPGNht450XHNcHVGTJm9Cqf5ww5HlfxfhEEPKFflMqCXHNVWnj2sWgdPjqDJNRDFlt92f

Save these two pieces of information, oauth_token and oauth_token_secret: you'll need them to sign the request in step 3.


/!\ Edit conflict - your version:


  • oauth_token=9kDgVhXlcVn52HGgCWxq&oauth_token_secret=jMth55Zn3pbkPGNht450XHNcHVGTJm9Cqf5ww5HlfxfhEEPKFflMqCXHNVWnj2sWgdPjqDJNRDFlt92f

}}}

Save these two pieces of information, oauth_token and oauth_token_secret: you'll need them to sign the request in step 3.


/!\ End of edit conflict


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:

---- /!\ '''Edit conflict - other version:''' ----
    https://edge.launchpad.net/+authorize-token?oauth_token={oauth_token}

Where oauth_token is the string you got at the end of step 1.


/!\ Edit conflict - your version:


}}}

Where oauth_token is the string you got at the end of step 1.


/!\ End of edit conflict


Step 2a: If you're building a website

If your program is a website that your users visit, you can send them


/!\ Edit conflict - other version:


an HTTP redirect. Be sure to also specify the oauth_callback field


/!\ Edit conflict - your version:


an HTTP redirect. Be sure to also specify the oauth_callback field


/!\ End of edit conflict


as a URL on your website.

---- /!\ '''Edit conflict - other version:''' ----
    https://edge.launchpad.net/+authorize-token?oauth_token={oauth_token}&oauth_callback={URL to within your website}

---- /!\ '''Edit conflict - your version:''' ----
    https://edge.launchpad.net/+authorize-token?oauth_token={oauth_token}&oauth_callback={URL to within your website}

---- /!\ '''End of edit conflict''' ----

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


/!\ Edit conflict - other version:


end-user themselves tell you when they're done with the +authorize-token page.


/!\ Edit conflict - your version:


end-user themselves tell you when they're done with the +authorize-token page.


/!\ End of edit conflict


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.


/!\ Edit conflict - other version:


For an example of good interface design around these constraints, look at 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.


/!\ Edit conflict - your version:


For an example of good interface design around these constraints, look at 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.


/!\ End of edit conflict


(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


/!\ Edit conflict - other version:


The oauth_token and oauth_token_secret you got in Step 1 are real OAuth keys that can be used to sign requests, but you're only going to use them once. Their only purpose is to remind Launchpad who you are; remember, it hasn't heard from you since step 1. Once the user has delegated some of their authority to you, you need to exchange these temporary credentials for permanent credentials that has the end-user's permissions associated with them.

If you're writing a website, you'll know you're ready 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


/!\ Edit conflict - your version:


The oauth_token and oauth_token_secret you got in Step 1 are real OAuth keys that can be used to sign requests, but you're only going to use them once. Their only purpose is to remind Launchpad who you are; remember, it hasn't heard from you since step 1. Once the user has delegated some of their authority to you, you need to exchange these temporary credentials for permanent credentials that has the end-user's permissions associated with them.

If you're writing a website, you'll know you're ready 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


/!\ End of edit conflict


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.


/!\ Edit conflict - other version:


Now you make a POST request to https://edge.launchpad.net/+access-token. The body should be a set of form-encoded parameters, as in Step 1. You need to provide the following parameters:

  • oauth_token: The same as oauth_token from step 1

  • oauth_consumer_key: The same as in step 1
  • oauth_signature_method: The string "PLAINTEXT"
  • oauth_signature: The OAuth signature, calculated using the PLAINTEXT algorithm and the oauth_token_secret' from step 1

The last one is the tricky one. The OAuth standard has the details, but basically you take the string '&' and stick the oauth_token_secret you got at the end of step 1 onto the end. (The reason you start with the string '&' is that Launchpad doesn't use OAuth Consumer Secrets.)

So your POST request should look like this:

    POST /+access_token
    Host: edge.launchpad.net
    Content-type: application/x-www-form-urlencoded

    oauth_signature=%26jMth55Zn3pbkPGNht450XHNcHVGTJm9Cqf5ww5HlfxfhEEPKFflMqCXHNVWnj2sWgdPjqDJNRDFlt92f&oauth_consumer_key=just+testing&oauth_token=9kDgVhXlcVn52HGgCWxq&oauth_signature_method=PLAINTEXT

---- /!\ '''Edit conflict - your version:''' ----
Now you make a POST request to
https://edge.launchpad.net/+access-token. The body should be a set of
form-encoded parameters, as in Step 1. You need to provide the
following parameters:


  * oauth_token: The same as ''oauth_token'' from step 1
  * oauth_consumer_key: The same as in step 1
  * oauth_signature_method: The string "PLAINTEXT"
  * oauth_signature: The OAuth signature, calculated using [[http://oauth.net/core/1.0/#anchor22| the PLAINTEXT algorithm]] and the ''oauth_token_secret' from step 1

The last one is the tricky one. The OAuth standard has the details,
but basically you take the string '&' and stick the ''oauth_token_secret''
you got at the end of step 1 onto the end. (The reason you start with
the string '&' is that Launchpad doesn't use OAuth Consumer Secrets.)

So your POST request should look like this:

{{{
    POST /+access_token
    Host: edge.launchpad.net
    Content-type: application/x-www-form-urlencoded

    oauth_signature=%26jMth55Zn3pbkPGNht450XHNcHVGTJm9Cqf5ww5HlfxfhEEPKFflMqCXHNVWnj2sWgdPjqDJNRDFlt92f&oauth_consumer_key=just+testing&oauth_token=9kDgVhXlcVn52HGgCWxq&oauth_signature_method=PLAINTEXT

---- /!\ '''End of edit conflict''' ----

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


/!\ Edit conflict - other version:


okay to delegate their authorization to you. The request token secret proves that you're the same client as went through step 1.

You should get a response that looks something like this:


/!\ Edit conflict - your version:


okay to delegate their authorization to you. The request token secret proves that you're the same client as went through step 1.

You should get a response that looks something like this:


/!\ End of edit conflict


    200 OK

---- /!\ '''Edit conflict - other version:''' ----
    oauth_token=PsK9cpbll1KwehhRDckr&oauth_token_secret=M2hsnmsfEIAjS3bTWg6t8X2GKhlm152PRDjLLmtQdr9C8KFZWPl9c8QbLfWddE0qpz5L56pMKKFKEfv1&lp.context=None

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


/!\ Edit conflict - your version:



/!\ End of edit conflict



/!\ Edit conflict - other version:



/!\ Edit conflict - your version:


So your POST request should look like this:

    POST /+access_token
    Host: edge.launchpad.net
    Content-type: application/x-www-form-urlencoded

    oauth_signature=%26jMth55Zn3pbkPGNht450XHNcHVGTJm9Cqf5ww5HlfxfhEEPKFflMqCXHNVWnj2sWgdPjqDJNRDFlt92f&oauth_consumer_key=just+testing&oauth_token=9kDgVhXlcVn52HGgCWxq&oauth_signature_method=PLAINTEXT

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. The request token secret proves that you're the same client as went through step 1.

You should get a response that looks something like this:

    200 OK

    oauth_token=PsK9cpbll1KwehhRDckr&oauth_token_secret=M2hsnmsfEIAjS3bTWg6t8X2GKhlm152PRDjLLmtQdr9C8KFZWPl9c8QbLfWddE0qpz5L56pMKKFKEfv1&lp.context=None

Put those two pieces of information, oauth_token' and oauth_token_secret, in some persistent storage. They replace the oauth_token and oauth_token_secret you got in step 1. You'll need them as part of every request you make to Launchpad's web service.


/!\ End of edit conflict


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 oauth_token and an oauth_token_secret. It's also very similar to the request signing you did in step 3. 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.

I will say that Launchpad currently only supports the first of OAuth's [[http://oauth.net/core/1.0/#consumer_req_param| three ways of encoding the consumer request parameters]. You'll need to put your digital signatures into the Authorization header, using the OAuth HTTP Authorization Scheme. That means making HTTP requests that look like this:

    GET /beta/bugs/11
    Accept: application/json
    Authorization: OAuth realm="https://api.launchpad.net/",
                oauth_consumer_key="just+testing",
                oauth_token="PsK9cpbll1KwehhRDckr",
                oauth_signature_method="PLAINTEXT",
                oauth_signature="%26M2hsnmsfEIAjS3bTWg6t8X2GKhlm152PRDjLLmtQdr9C8KFZWPl9c8QbLfWddE0qpz5L56pMKKFKEfv1",
                oauth_timestamp="1217548916",
                oauth_nonce="51769993",
                oauth_version="1.0"

If you put that oauth_* data into the entity-body of your POST requests or the query strings of your GET requests, Launchpad won't pick it up and you won't be able to access the web service.

What does all that data mean? The oauth_consumer_key identifies your client software; it's the same string you've been using since step 1. The oauth_token and oauth_signature identify the Launchpad credentials your user set up for you to use; you got these in step 3, and the PLAINTEXT algorithm for generating oauth_signature is the same as in step 3. The oauth_nonce and oauth_timestamp are as defined [[http://oauth.net/core/1.0/#nonce| here].

API/SigningRequests (last edited 2016-07-19 17:28:27 by cjwatson)