Goodreads Developers discussion

107 views
questions > PHP Not authorized response on signed requests with token

Comments Showing 1-4 of 4 (4 new)    post a comment »
dateUp arrow    newest »

message 1: by Israel (new)

Israel (iisisrael) | 4 comments We're able to capture an authorized token, and can get successful responses from /book/isbn_to_id and /review/show_by_user_and_book.xml, for example. But from /api/auth_user and /review.xml, we get "Invalid OAuth Request" and "not authorized" respectively.

Can anyone spot any error in our building of the Authorization header in the requests below? Or other possible cause for the not authorized responses? (Extends https://github.com/thephpleague/oauth..., which provides functionality for the HMAC-SHA1 signature generating.)
use League\OAuth1\Client\Server\Server;

/**
* OAuth1 client for Goodreads.
*/
class Goodreads extends Server
{
/**
* @var string
*/
protected $token;

/**
* Get the authorized user data.
*
* @return string
*/
public function apiAuthUser()
{
return $this->get('https://www.goodreads.com/api/auth_us...
}

/**
* Get a Goodreads book ID by ISBN.
*
* @param string $isbn The ISBN.
*
* @return string
*/
public function bookIsbnToId(string $isbn)
{
return $this->get('https://www.goodreads.com/book/isbn_t...', array(
'isbn' => $isbn,
'key' => $this->clientCredentials->getIdentifier()
));
}

/**
* Create a review for book by ID.
*
* @param string $bookId The Goodreads book ID.
* @param string $review The review text.
* @param integer $rating The star rating.
*
* @return string
*/
public function review(string $bookId, string $review, int $rating = null)
{
return $this->post('https://www.goodreads.com/review.xml', array(
'book_id' => $bookId,
'review[review]' => $review,
'review[rating]' => $rating ?? 0
));
}

/**
* Get a review ID by user ID and book ID.
*
* @param string $bookId The Goodreads book ID.
* @param string $userId The Goodreads user ID.
*
* @return string
*/
public function reviewShowByUserAndBook(string $bookId, string $userId)
{
return $this->get('https://www.goodreads.com/review/show...', array(
'key' => $this->clientCredentials->getIdentifier(),
'book_id' => $bookId,
'user_id' => $userId
));
}

/**
* Make a GET request.
*
* @param string $url The request URL.
* @param array $parameters The request parameters.
*
* @return string
*/
protected function get(string $url, array $parameters = array())
{
$headers = array(
'Authorization: OAuth ' . http_build_query(array(
'oauth_consumer_key' => $this->clientCredentials->getIdentifier(),
'oauth_nonce' => md5(microtime() . mt_rand()),
'oauth_signature' => $this->signature->sign($url, $parameters, 'GET'),
'oauth_signature_method' => $this->signature->method(),
'oauth_timestamp' => time(),
'oauth_token' => $this->token,
'oauth_version' => '1.0',
)),
'Content-Type: application/x-www-form-urlencoded'
);

$url = $parameters ? sprintf('%s?%s', $url, http_build_query($parameters)) : $url;

$curl = curl_init();
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);

$result = curl_exec($curl);
curl_close($curl);

return $result;
}

/**
* Make a POST request.
*
* @param string $url The request URL.
* @param array $parameters The request parameters.
*
* @return string
*/
protected function post(string $url, array $parameters = array())
{
$headers = array(
'Authorization: OAuth ' . http_build_query(array(
'oauth_consumer_key' => $this->clientCredentials->getIdentifier(),
'oauth_nonce' => md5(microtime() . mt_rand()),
'oauth_signature' => $this->signature->sign($url, $parameters, 'POST'),
'oauth_signature_method' => $this->signature->method(),
'oauth_timestamp' => time(),
'oauth_token' => $this->token,
'oauth_version' => '1.0',
))
);

$curl = curl_init();
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');

if ($parameters) {
$jsonData = json_encode($parameters);
curl_setopt($curl, CURLOPT_POSTFIELDS, $jsonData);
$headers[] = 'Content-Type: application/json';
$headers[] = 'Content-Length: ' . strlen($jsonData);
}
else {
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
}

curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);

$result = curl_exec($curl);
curl_close($curl);

return $result;
}
...
}



message 2: by Israel (new)

Israel (iisisrael) | 4 comments Here's the full updated version with (I think) bugs fixed: https://gist.github.com/iisisrael/49e...

Use cases (after successfully getting the user's authorized token):

use ExampleBundle\OAuth1\Client\Server\Goodreads;

// configure the Goodreads OAuth client
$server = new Goodreads(array(
'identifier' => '***goodreads_key***',
'secret' => '***goodreads_secret***'
));
$server->setToken('***stored_user_token***');

// look up this member's user ID on Goodreads
// FAILS, return value is "Invalid OAuth Request"
$userId = $server->apiAuthUser();

// look up the book on Goodreads
// SUCCEEDS, return value is "26771521"
$bookId = $server->bookIsbnToId('9781516865871');

// look up any existing review by this member for this book on Goodreads
// SUCCEEDS (when $userId is set manually to a known value), return value is a XML document
$reviewData = $server->reviewShowByUserAndBook($bookId, $userId);

// attempt to create a Goodreads review
// FAILS, return value is "not authorized"
$result = $server->review($bookId, $reviewText, $starRating);



message 3: by Marco (new)

Marco Pavan (revenue) | 6 comments Mod
Hi, sorry for the late response to this thread. The post review operation requires additional permissions to be granted, which is likely the cause for the response you are getting.
Your request does not seem malformed, which is in line with being able to make other API request successfully.
Looking into your API profile at the moment


message 4: by Israel (new)

Israel (iisisrael) | 4 comments We've open-sourced the authentication client extension we came up with, and I updated gist example linked above. Hopefully we can get some community input - client and example links also posted here.


back to top