Search code examples
phpoauthphp-curletsy

PHP URL query parameters in Etsy OAuth 1.0 not working


After getting all the credentials I'm now requesting a resource from Etsy API. It's working fine without query parameters to the url but when I add them I get signature invalid.

Here's what I got working without the query parameters in the url:

// enconding, sorting and creating the base URI
function buildBaseString($baseURI, $method, $params){
            $r = array();
            ksort($params);
            foreach($params as $key=>$value){
                $r[] = "$key=" . rawurlencode($value);
            }

            return $method."&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $r));
        }

        // create encoded header
        function buildAuthorizationHeader($oauth){
            $r = 'Authorization: OAuth ';
            $values = array();
            foreach($oauth as $key=>$value)
                $values[] = "$key=\"" . rawurlencode($value) . "\"";

            $r .= implode(', ', $values);
            return $r;
        }
        $consumer_key              = 'the_key';
        $consumer_secret           = 'the_secret';
        $shop_id                   = '00000000000';
        $oauth_access_token        = 'access_token';
        $oauth_access_token_secret = 'token_secret';

$receipts_by_status_url    = 'https://openapi.etsy.com/v2/shops/'.$shop_id.'/receipts/opens';

$oauth = array(
            'oauth_callback'         => 'oob',
            'oauth_consumer_key'     => $consumer_key,
            'oauth_nonce'            => time(),
            'oauth_signature_method' => 'HMAC-SHA1',
            'oauth_timestamp'        => time(),
            'oauth_token'            => $oauth_access_token,
            'oauth_version'          => '1.0',
            );


        $base_info = buildBaseString($receipts_by_status_url, 'GET', $oauth);
        $composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret);
        $oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
        $oauth['oauth_signature'] = $oauth_signature;

        $header = array(buildAuthorizationHeader($oauth), 'Expect:', 'Content-Type: application/x-www-form-urlencoded');


        /*
         * Set curl options
         */
        //ob_start();
        //$curl_log = fopen('php://output', 'w');

        $ch = curl_init($receipts_by_status_url);

        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 25);
        curl_setopt($ch, CURLOPT_VERBOSE, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

        // Execute curl
        $result_token = curl_exec($ch);

when I add the parameters to the url: $receipts_by_status_url = 'https://openapi.etsy.com/v2/shops/'.$shop_id.'/receipts/opens/?includes=Listings';

I get signature invalid.

$base info:

'GET&https%3A%2F%2Fopenapi.etsy.com%2Fv2%2Fshops%2F12962774%2Freceipts%2Fopen%3Fincludes%3DListings&oauth_callback%3Doob%26oauth_consumer_key%thekey%26oauth_nonce%3D1607965396%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1607965396%26oauth_token%oauthtoken%26oauth_version%3D1.0'

$oauth signature:

0Dr9wz24LU6NPkO7eKvP//HCOWk=

$header:

  0 => string 'Authorization: OAuth oauth_callback="oob", oauth_consumer_key="consumerkey", oauth_nonce="1607965396", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1607965396", oauth_token="oauthtoken", oauth_version="1.0", oauth_signature="0Dr9wz24LU6NPkO7eKvP%2F%2FHCOWk%3D"' (length=301)
  1 => string 'Expect:' (length=7)
  2 => string 'Content-Type: application/x-www-form-urlencoded

What am I doing wrong?


Solution

  • I got it working.

    I Manually created the base string without the function in the question, this was the root of the problem, because when I added parameters to the endpoint it didn't work.

    The server takes the parameters in the authrization header and creates an OAuth signature and compares it to yours, if the don't match you'll get invalid signature like in my case.

    The base string should be 3 chunks of data concatenated together and rawurlencoded:

    Http method '&' url endpoint '&' params

    Things to make sure:

    1. Use a url endpoint without query parameters
    2. Make sure the whole base string has only two ampersands.
    3. Sort params alphabetically.
    4. Use Postman and succeed in sending the request there, after that you can compare the signature generated in the header there to yours, when you can match it then it should work.
    5. Make sure you're using the long url (with query params) in cURL, the clean one is only to create the base string.
    6. I didn't notice but Etsy is actually sending the base string they created from the params in the response when the signature is invalid, all I had to do is compare mine to theirs and fix it.

    Hope I helped anyone