Goodreads Developers discussion

OAuth setup with PHP

Comments Showing 1-31 of 31 (31 new)    post a comment »
dateDown arrow    newest »

message 1: by Scott (new)

Scott Forbes (somesmart) | 10 comments Does anyone have an example of using the api with OAuth in PHP? I've tried to get it working, but I'm not having any success so far. I'm definitely an amateur when it comes to PHP, so I figured I'd ask before I put too much time into it.

message 2: by Michael (new)

Michael Economy (michaeleconomy) Sadly, we don't have any strong php coders on staff.

message 3: by Craig (new)

Craig (digitalcraig) are you having problems with OAuth in general or the API specifically? Are you using libraries or trying to roll your own? Can you go into any more detail on what's not working?

Here's some OAuth examples in PHP, but not specific to Goodreads..

message 4: by Scott (last edited Aug 18, 2009 06:36PM) (new)

Scott Forbes (somesmart) | 10 comments I'm new to OAuth so I'm just learning that. I haven't spent a lot of time on it yet (wanted to see what was out there). Let me check that out and I'll get back to you with specifics. Thanks!

message 5: by Michael (new)

Michael Economy (michaeleconomy) Thanks Craig!

message 6: by Scott (new)

Scott Forbes (somesmart) | 10 comments I think (hope?) I'm starting to get my head around this stuff. Couple quick questions (sorry if they are obvious...) but what is the URL I should be using to authorize my key/secret to get the token? and what format (i.e. [baseurl:]?oauth_consumer_key='key'&oauth_secret='secret' ) should it be in?

message 7: by Ben (new)

Ben Weiner (lostinpatterns) | 24 comments Here are the endpoints,

get a request token: /oauth/request_token
authorize the request token: /oauth/authorize
exchange for access token: /oauth/access_token

We're using OAuth 1.0. You should use HMAC-SHA1 for signing and send parameters as the value for the Authorization header as described here:

You'll probably want to use a library to do the signing. There's code here for PHP here and I'm sure there are other projects as well:

message 8: by Scott (last edited Aug 22, 2009 07:53PM) (new)

Scott Forbes (somesmart) | 10 comments Just wanted to say thanks! I've been able to get a preliminary OAuth/php app up and running that interfaces with goodreads.

message 9: by Ben (new)

Ben Weiner (lostinpatterns) | 24 comments Excellent! Would love to check it out when it's complete.

message 10: by Rick (new)

Rick Seymour | 4 comments I can authorise an application (ie. and return a validate oauth_token but oauth doesn't return both a token and secret in the callback url.

Any tips???
PS Much of the OAuth class is from the Twitter OAuth Class (Very very well programmed!!)



require_once 'OAuth.php';

class Good{

function __construct($key, $secret, $oauth_token=NULL, $oauth_token_secret=NULL){

$this->consumer = new OAuthConsumer($key, $secret);


function AuthoriseURL($token){if(is_array($token)){

return '}}

function go($url){return header('Location: '.$url);}

function http($url, $post_data = null){

$ch = curl_init();

if(defined("CURL_CA_BUNDLE_PATH")){curl_setopt($ch, CURLOPT_CAINFO, CURL_CA_BUNDLE_PATH);}

curl_setopt($ch, CURLOPT_URL, $url);

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);

curl_setopt($ch, CURLOPT_TIMEOUT, 30);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

if (isset($post_data)){curl_setopt($ch, CURLOPT_POST, 1);curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);}

$response = curl_exec($ch);

$this->http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

$this->last_api_call = $url;

curl_close ($ch);

return $response;}

function oAuthParseResponse($responseString) {

$r = array();

foreach(explode('&', $responseString) as $param){

$pair = explode('=', $param, 2);

if (count($pair) != 2){continue;}else{$r[urldecode($pair[0:])] = urldecode($pair[1:]);}

}return $r;}

function getRequestToken(){

$this->response = $this->oAuthRequest('

return $this->oAuthParseResponse($this->response);


function getAccessToken($token = NULL) {

$this->response = $this->oAuthRequest('

$token = $this->oAuthParseResponse($this->response);

$this->token = new OAuthConsumer($token['oauth_token':], $token['oauth_token_secret':]);

return $token;}

function oAuthRequest($url, $args = array(), $method = NULL) {

if (empty($method)) $method = empty($args) ? "GET" : "POST";

$req = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $args);

$req->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $this->consumer, $this->token);

switch ($method) {

case 'GET': return $this->http($req->to_url());

case 'POST': return $this->http($req->get_normalized_http_url(), $req->to_postdata());



function setToken($token){$this->token=$token;}

} //class

$g=new Good($key,$secret);





//Not sure of this bit




message 11: by Scott (last edited Oct 26, 2009 07:03AM) (new)

Scott Forbes (somesmart) | 10 comments Here's the code I ended up using (also built off of the twitter oauth code) with the help of a user here. You can get the twitterOauth lib it requires from here (thanks Brian!):

Hope this helps!

(some of the html isn't showing as code, but I think you get the idea)

// require twitterOAuth lib

/* Sessions are used to keep track of tokens while user authenticates with twitter */

/* Consumer key from twitter */
$consumer_key = '';
/* Consumer Secret from twitter */
$consumer_secret = '';
/* Set up placeholder */
$content = NULL;
/* Set state if previous session */
$state = $_SESSION['oauth_state':];
/* Checks if oauth_token is set from returning from twitter */
$session_token = $_SESSION['oauth_request_token':];
/* Checks if oauth_token is set from returning from twitter */
$oauth_token = $_REQUEST['oauth_token':];
/* Set section var */
$section = $_REQUEST['section':];

/* Clear PHP sessions */
if ($_REQUEST['test':] === 'clear') {

/* If oauth_token is missing get it */
if ($_REQUEST['oauth_token':] != NULL && $_SESSION['oauth_state':] === 'start') {
$_SESSION['oauth_state':] = $state = 'returned';

* Switch based on where in the process you are
* 'default': Get a request token from twitter for new user
* 'returned': The user has authorize the app on twitter
switch ($state) {
/* Create TwitterOAuth object with app key/secret */
$to = new TwitterOAuth($consumer_key, $consumer_secret);
/* Request tokens from twitter */
$tok = $to->getRequestToken();

/* Save tokens for later */
$_SESSION['oauth_request_token':] = $token = $tok['oauth_token':];
$_SESSION['oauth_request_token_secret':] = $tok['oauth_token_secret':];
$_SESSION['oauth_state':] = "start";

/* Build the authorization URL */
$request_link = $to->getAuthorizeURL($token);

/* Build link that gets user to twitter to authorize the app */
$content = 'Click on the link to go to twitter to authorize your account.';
$content .= '
case 'returned':
/* If the access tokens are already set skip to the API call */
if ($_SESSION['oauth_access_token':] === NULL && $_SESSION['oauth_access_token_secret':] === NULL) {
/* Create TwitterOAuth object with app key/secret and token key/secret from default phase */
$to = new TwitterOAuth($consumer_key, $consumer_secret, $_SESSION['oauth_request_token':], $_SESSION['oauth_request_token_secret':]);
/* Request access tokens from twitter */
$tok = $to->getAccessToken();

/* Save the access tokens. Normally these would be saved in a database for future use. */
$_SESSION['oauth_access_token':] = $tok['oauth_token':];
$_SESSION['oauth_access_token_secret':] = $tok['oauth_token_secret':];
/* No form submitted, present it here */
if (empty($_REQUEST['shelfname':])) {
$content = "" .
"" .
/* We got our form submit, process it */
} else {
/* Create TwitterOAuth with app key/secret and user access key/secret */
$to = new TwitterOAuth($consumer_key, $consumer_secret, $_SESSION['oauth_access_token':], $_SESSION['oauth_access_token_secret':]);
$content = $to->OAuthRequest('', array('name' => $_REQUEST['shelfname':],), 'POST');


Twitter OAuth in PHP

Welcome to a Twitter OAuth PHP example.

This site is a basic showcase of Twitters new OAuth authentication method. Everything is saved in sessions. If you want to start over ?test=clear'>clear sessions.

Get the code powering this at

Read the documentation at

<?php print $content; ?>

message 12: by Ben (new)

Ben Weiner (lostinpatterns) | 24 comments Hi Rick,

After you send the user to to authorize the request token, if they authorize your app they'll be redirected to your callback URL with the oauth_token param. You'll then make a separate request to exchange the (now authorized) request token for an access token. The body of the response from /oauth/access_token will contain the access token oauth_token and oauth_token_secret as form encoded parameters.

So first you'll get the request token with getRequestToken(). Then you'll send the user to AuthorizeURL. Then when we redirect the user to your callback, you'll call getAccessToken(). (The oauth_token param that's in the callback URL will contain the token of your request token. You can use to verify it matches yours.) Does that make sense?


message 13: by Rick (new)

Rick Seymour | 4 comments RIGHT!!!!!

$to = new Good($key, $secret, $_SESSION['oauth_access_token':], $_SESSION['oauth_access_token_secret':]);

$content = $to->OAuthRequest('', array(), 'GET');


<?xml version="1.0" encoding="UTF-8"?>


I have a working PHP framework.

But..... quicky message to all developers
you MUST use Sessions to cache the original request token!!!

Let me do a bit more testing first.

message 14: by Ben (new)

Ben Weiner (lostinpatterns) | 24 comments Great to hear it's working! And yes, you'll want to store the request token and secret in the user's session to use in your callback in order to exchange it for an access token.

message 15: by Rick (new)

Rick Seymour | 4 comments Why isn't that in the documentation? :P
(Sorry if it is and I missed it)

message 16: by Ben (new)

Ben Weiner (lostinpatterns) | 24 comments Sorry this was confusing! The documentation could definitely be improved.

All of these steps that you went through to get an access token will be the same for any OAuth provider. I.e., the code you wrote to ask for request token, get it authorized, and then exchange for an access token will probably work as is with any site that supports OAuth, assuming their endpoints are the same.

We'll work on making this more clear or at the very least linking to a site that does a good job of explaining it. OAuth can be a little tricky to worth with as a dev, but hopefully as adoption improves so will the tools and example code.

message 17: by Rick (new)

Rick Seymour | 4 comments OAuth is a fab tool for linking sites, it's just the extender class that needs work, and to be released. I totally understand that writing a class for each programming language is a toughy!!
Let me do a bit more refinement and I'll package up what I've done. Although I am busy prep'ing my own site for release in the next week.
But spot on .. looks good so far..

PS Can we have access to information in other formats other than RSS. ie JSON, XML.
(to get the information in json format)
or xml

message 18: by Wirelezz (new)

Wirelezz | 2 comments HI! I got a little problem using PHP on CentOS and since I'm not really an expert on this field, I guess I got trouble with the firewall or with the php conf...

I'm using the PHP library and it works great on Windows. However, when I use it on CentOS, twitter gives me a null oauth_token ($token['oauth_token':] is null, blank)...

what could be going wrong? Am I forgetting to do something special with CentOS. I would really appreciate any kind of help here...

thanks in advance :)

message 19: by Michael (new)

Michael Economy (michaeleconomy) Should be easy to test the firewall, just do "wget" and if that works, then the FW isn't the problem. You might need to install wget though :(

Maybe a library is missing, or is out of date?

Hard to say, but you might have better luck asking the guy who wrote it.

message 20: by Wirelezz (new)

Wirelezz | 2 comments I tried: wget and it downloaded the .html file with no problem.

Then I looked in the library, and it says:

public static $TO_API_ROOT = "";

then I did: wget

and it said that it didn't trust the certificate and that I should use --no-check-certificate

so I included what it told me and after that it let me download the .html file

So! I wonder if there's any kind of issue related to https. I remember that on installation, I only enabled the HTTP port on FW, not HTTPS.

Maybe is that? now, how do I enable the HTTPS port :D?

Thank you very much

message 21: by Michael (new)

Michael Economy (michaeleconomy) None of our public api uses ssl.

message 22: by BZ (new)

BZ (bzaveri) | 1 comments I am trying to use oauth in .Net/C# but am getting an error when requesting the access token for my request token. There was a Twitter/C# oauth example that I changed but get a 401 error when I try to get the access tokens.

message 23: by Ben (new)

Ben Weiner (lostinpatterns) | 24 comments @Bhavesh just sent you a private message.

message 24: by Rob (new)

Rob (rpboland) | 9 comments Hi all,

This was a very useful thread for me, so thank you. Still, it took me a day and a half to get goodreads and OAuth working correctly with PHP.

To save this pain for anyone else, I've uploaded the working code to a google project page:

To the Goodreads dev team, feel free to point to this code as an example of goodreads interacting with PHP via OAuth. (or take the code and modify it if you want to make a better example!)


message 25: by Michael (new)

Michael Economy (michaeleconomy) Awesome Rob thanks!

message 26: by Scott (new)

Scott Forbes (somesmart) | 10 comments This is great, thanks Rob!

message 27: by Alex (new)

Alex Gorelik (discry) | 1 comments I used a modified version of for a Goodreads to Feedbooks mashup (Bookshare: The only thing I had to do other than what is shown above:
message 11: by Scott (last edited Oct 26, 2009 07:03am)
Oct 26, 2009 07:01am was to make sure that I followed my servers security rules about explicity specifying the directory sessions were stored in. If you are having trouble, you might take a look at your server's security settings. Also, remember, don't output any debugging info before setting cookies - the cookie has to be in the header.

From there I was able to use pretty much the same code with conditions to specify configuration settings for oAuth integration with Twitter as well.

message 28: by Mike (new)

Mike Evans (mikelevans) | 2 comments Hi all,

I've used Rob's base to begin building an OAuth solution, however I can't use sessions. Where and how are the oauth_token and oauth_token_secret returned? My callback file is getting the token and authorize parameters, but I'm not sure what to do from there.

A few questions whose answers could help:
1) Can this even be done without sessions?
2) Where are the $_SESSION['oauth_token'] and $_SESSION['oauth_token_secret'] initially set and is there a way to override this?


message 29: by Mike (new)

Mike Evans (mikelevans) | 2 comments Mikeevans wrote some stuff...

Nevermind... figured it out. I had pulled the $_SESSION stuff into a separate file. Switched it all out for cookies and it's working great.

Thanks for the solid base of work, Rob!

message 30: by Robert (new)

Robert Duchnik (robertduchnik) | 1 comments I actually just had a lot of issues with this myself that had to do with incompatibility issues between php and oauth. There seems to be a lot of outdated information on the topic there.

There are precompiled oAuth libraries available here which are kept quite to date:

Also you may have issues getting them to work with wamp since wamp is usually a few versions behind from the official release with php. You can follow this tutorial on how to manually add php versions to wamp:

message 31: by Panagiotis (new)

Panagiotis Sidiropoulos | 1 comments @Rob

After following README instructions, I'm getting:

This as sign in url:

and this by clicking sign in url:
There Was an Error with This Oauth Request
This is likely due to an expired request. Please notify the owner of the application if this error continues to happen.

Tested on:
Ubuntu 12.04.2 LTS (GNU/Linux 3.5.0-54-generic x86_64)
PHP 5.3.10-1ubuntu3.26 with Suhosin-Patch (cli)

back to top