Octoxan
Octoxan

Reputation: 2299

oAuth 1.0 REST API with Magento 1.9, how to get oauth_signature like postman does?

I'm trying to access a Magento 1.9 REST API in php, which only supports authentication in oAuth 1.0.

Now, I have it working in Postman, but it's doing some sort of magic to do oAuth that it isn't disclosing. It even has a button for the code from the request, but the nonce, time and signature must change with every request.

I'm making a GET request to example.com/api/rest/products (production site, url changed for privacy) with the consumer key, consumer secret, access token and access secret. It returns a proper response with all the products. Here's the curl code it outputs...

<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://www.example.com/api/rest/products",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: OAuth oauth_consumer_key=\"some_key\",oauth_token=\"some_token\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1529691153\",oauth_nonce=\"0fVylxHPUqv\",oauth_version=\"1.0\",oauth_signature=\"LTJHEp2A5mczD3xrYxbWW2BHlQk%3D\"",
    "Cache-Control: no-cache",
    "Content-Type: application/json",
    "Postman-Token: d684d11c-498e-4760-8709-76777e8ea75d"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

This doesn't work, fails every time due to the nonce already being used. If I change the nonce it says the signature is invalid.

Here's the code Magento's ancient docs recommend, which fails with 403 Not Authorized.

$baseUrl = 'https://www.example.com';
$callbackUrl = 'http://otherexample.test/test';
$temporaryCredentialsRequestUrl = $baseUrl."/oauth/initiate?oauth_callback=" . urlencode($callbackUrl);
$adminAuthorizationUrl = $baseUrl.'/admin/oauth_authorize';
$accessTokenRequestUrl = $baseUrl.'/oauth/token';
$apiUrl = $baseUrl.'/api/rest';

$consumerKey = 'some_key';
$consumerSecret = 'some_secret';

session_start();

if(! isset($_SESSION['state'])) {
    $_SESSION['state'] = null;
}

if (!isset($_GET['oauth_token']) && isset($_SESSION['state']) && $_SESSION['state'] == 1) {
    $_SESSION['state'] = 0;
}

try {
    $authType = ($_SESSION['state'] == 2) ? OAUTH_AUTH_TYPE_AUTHORIZATION : OAUTH_AUTH_TYPE_URI;
    $oauthClient = new \OAuth($consumerKey, $consumerSecret, OAUTH_SIG_METHOD_HMACSHA1, $authType);
    $oauthClient->enableDebug();

    if (!isset($_GET['oauth_token']) && !$_SESSION['state']) {
        $requestToken = $oauthClient->getRequestToken($temporaryCredentialsRequestUrl);
        $_SESSION['secret'] = $requestToken['oauth_token_secret'];
        $_SESSION['state'] = 1;
        header('Location: ' . $adminAuthorizationUrl . '?oauth_token=' . $requestToken['oauth_token']);
        exit;
    } else if ($_SESSION['state'] == 1) {
        $oauthClient->setToken($_GET['oauth_token'], $_SESSION['secret']);
        $accessToken = $oauthClient->getAccessToken($accessTokenRequestUrl);
        $_SESSION['state'] = 2;
        $_SESSION['token'] = $accessToken['oauth_token'];
        $_SESSION['secret'] = $accessToken['oauth_token_secret'];
        header('Location: ' . $callbackUrl);
        exit;
    } else {
        $oauthClient->setToken($_SESSION['token'], $_SESSION['secret']);

        $resourceUrl = $apiUrl . "/products";

        $oauthClient->fetch($resourceUrl, array(), 'GET', array('Content-Type' => 'application/json'));
        $productsList = json_decode($oauthClient->getLastResponse());
        print_r($productsList);
    }

} catch (\OAuthException $e) {
    print_r($e->getMessage());
    echo "&lt;br/&gt;";
    print_r($e->lastResponse);
}

Basically, I think I need to somehow generate the nonce and signature like postman is. I'm giving postman my access token and secret, but thats of course not in the response because a secret never should be. So how is it doing it? Every time I run a request in postman it succeeds and the code sample has different data in it. Every time I run it in php it fails with not authorized.

I'd prefer to use something more object oriented like Guzzle than curl, but I'll take whatever I can get at this point to get this external site to be able to use Magento 1.x REST API.

Here is what is working in postman, with the keys removed.

Upvotes: 2

Views: 3076

Answers (1)

Shyju S.
Shyju S.

Reputation: 31

yes, you have to generate a random nonce for every request sent.

let nonceObj = Math.random()
  .toString(36)
  .replace(/[^a-z]/, "")
  .substr(2);

This is how i did in JS.

Upvotes: 1

Related Questions