Pre-Authorized Rest API – How to Access

apioauthrest

I'm trying to call Magento REST API with pre authorized access token, I thought it would be easy but for some reason i cant get it to work, i mean i have the four components required, the consumerKey, consumerSecret, oauth_token and oauth_token_secret, however i always get a nonce_used error (right from the REST docs: This error is used if the nonce-timestamp combination has already been used.)

My normal authentication code is as follows:

class AppFactory_Basic_TestController extends Mage_Core_Controller_Front_Action {


public function indexAction() {
    //Basic parameters that need to be provided for oAuth authentication
    //on Magento
    $params = array(
        'siteUrl' => 'http://www.appfactory.loc/magento/oauth',
        'requestTokenUrl' => 'http://www.appfactory.loc/magento/oauth/initiate',
        'accessTokenUrl' => 'http://www.appfactory.loc/magento/oauth/token',
        'authorizeUrl' => 'http://www.appfactory.loc/magento/admin/oauth_authorize',//This URL is used only if we authenticate as Admin user type
        'consumerKey' => '0165d0443e9a15a019f26b2e2ca8c0bc',//Consumer key registered in server administration
        'consumerSecret' => 'a1e9e199de111a566ed9698da7bf69b2',//Consumer secret registered in server administration
        'callbackUrl' => 'http://www.appfactory.loc/magento/basic/test/callback',//Url of callback action below
    );
    // Initiate oAuth consumer with above parameters
    $consumer = new Zend_Oauth_Consumer($params);
    // Get request token
    $requestToken = $consumer->getRequestToken();
    // Get session
    $session = Mage::getSingleton('core/session');
    // Save serialized request token object in session for later use
    $session->setRequestToken(serialize($requestToken));
    // Redirect to authorize URL
    //Zend_Debug::dump( serialize($requestToken) );
    //Zend_Debug::dump( $requestToken );
    $consumer->redirect();
    return;
}

public function callbackAction() {
    //oAuth parameters
    $params = array(
        'siteUrl' => 'http://www.appfactory.loc/magento/oauth',
        'requestTokenUrl' => 'http://www.appfactory.loc/magento/oauth/initiate',
        'accessTokenUrl' => 'http://www.appfactory.loc/magento/oauth/token',
        'consumerKey' => '0165d0443e9a15a019f26b2e2ca8c0bc',
        'consumerSecret' => 'a1e9e199de111a566ed9698da7bf69b2'
    );


    // Get session
    $session = Mage::getSingleton('core/session');
    // Read and unserialize request token from session
    $requestToken = unserialize($session->getRequestToken());
    // Initiate oAuth consumer
    $consumer = new Zend_Oauth_Consumer($params);
    // Using oAuth parameters and request Token we got, get access token
    Mage::log('Get Array:' . print_r($_GET, true) );
    $acessToken = $consumer->getAccessToken($_GET, $requestToken);
    // Get HTTP client from access token object
    $restClient = $acessToken->getHttpClient($params);
    // Set REST resource URL
    $restClient->setUri('http://www.appfactory.loc/magento/api/rest/products');
    // In Magento it is neccesary to set json or xml headers in order to work
    $restClient->setHeaders('Accept', 'application/json');
    // Get method
    $restClient->setMethod(Zend_Http_Client::GET);
    //Make REST request
    $response = $restClient->request();
    // Here we can see that response body contains json list of products
    Zend_Debug::dump($response);
    return;
}

Everything so far is running smoothly, im getting the Magento Authorize/Deny page and im redirected to the call back function with the actual API output and the product list. Now I try to do another call with the aouth_token i got:

public function doshitAction(){

    $params = array(
        'siteUrl' => 'http://www.appfactory.loc/magento/oauth',
        'requestTokenUrl' => 'http://www.appfactory.loc/magento/oauth/initiate',
        'accessTokenUrl' => 'http://www.appfactory.loc/magento/oauth/token',
        'consumerKey' => '0165d0443e9a15a019f26b2e2ca8c0bc',
        'consumerSecret' => 'a1e9e199de111a566ed9698da7bf69b2'
    );

    // Get session
    $session = Mage::getSingleton('core/session');
    // Read and unserialize request token from session
    $requestToken = unserialize($session->getRequestToken());
    Zend_Debug::dump($requestToken);
    // Initiate oAuth consumer
    $consumer = new Zend_Oauth_Consumer($params);
    // Using oAuth parameters and request Token we got, get access token
    $acessToken = $consumer->getAccessToken( array( 'oauth_token' => 'abd3945f27c4601591cb3434665ad6e8' ,
                                                    'oauth_verifier' => '85516e31405f59ac6f50eabac001edc5'
                                                    ) , $requestToken);

    // do a request
    $restClient = $acessToken->getHttpClient($params);
    $restClient->setUri('http://www.appfactory.loc/magento/api/rest/products');
    $restClient->setHeaders('Accept', 'application/json');
    $restClient->setMethod(Zend_Http_Client::GET);
    $response = $restClient->request();
    // Here we can see that response body contains json list of products
    Zend_Debug::dump($response);
    return;



}

And this is where im stuck, its exactly the same code in the callback function, but i replaced $_GET array with the varaiables that were actually in the array. What i am doing wrong. The $requestToken btw dump is

object(Zend_Oauth_Token_Request)#131 (3) {
  ["_params":protected] => array(3) {
    ["oauth_token"] => string(32) "abd3945f27c4601591cb3434665ad6e8"
    ["oauth_token_secret"] => string(32) "1c06bdd7614dce7357095fb43dd526a7"
    ["oauth_callback_confirmed"] => string(4) "true"
  }
  ["_response":protected] => NULL
  ["_httpUtility":protected] => object(Zend_Oauth_Http_Utility)#44 (0) {
  }
}

so it has the oauth_token and oauth_token_secret, not sure why the getAccessToken functions need a oauth_verifier value.

Below is the stack trace:

Could not retrieve a valid Token response from Token URL:
oauth_problem=nonce_used

Trace:
#0 C:\Development\stage\grantorino-appfactory-ab\magento\lib\Zend\Oauth\Http.php(190): Zend_Oauth_Http->_assessRequestAttempt(Object(Zend_Http_Response))
#1 C:\Development\stage\grantorino-appfactory-ab\magento\lib\Zend\Oauth\Http.php(191): Zend_Oauth_Http->startRequestCycle(Array)
#2 C:\Development\stage\grantorino-appfactory-ab\magento\lib\Zend\Oauth\Http.php(191): Zend_Oauth_Http->startRequestCycle(Array)
#3 C:\Development\stage\grantorino-appfactory-ab\magento\lib\Zend\Oauth\Http\AccessToken.php(52): Zend_Oauth_Http->startRequestCycle(Array)
#4 C:\Development\stage\grantorino-appfactory-ab\magento\lib\Zend\Oauth\Consumer.php(225): Zend_Oauth_Http_AccessToken->execute()
#5 C:\Development\stage\grantorino-appfactory-ab\magento\app\code\local\AppFactory\Basic\controllers\TestController.php(96): Zend_Oauth_Consumer->getAccessToken(Array, Object(Zend_Oauth_Token_Request))

I also tracked the Zend_Oauth_Http_AccessToken and found out that I actually im getting a new nonce on every request:

    /**
     * Initiate a HTTP request to retrieve an Access Token.
     *
     * @return Zend_Oauth_Token_Access
     */
    public function execute()
    {
        $params   = $this->assembleParams();
         Zend_Debug::dump($params);
        $response = $this->startRequestCycle($params);
        $return   = new Zend_Oauth_Token_Access($response);
        return $return;
    }

/**
 * Assemble all parameters for an OAuth Access Token request.
 *
 * @return array
 */
public function assembleParams()
{
    $params = array(
        'oauth_consumer_key'     => $this->_consumer->getConsumerKey(),
        'oauth_nonce'            => $this->_httpUtility->generateNonce(),
        'oauth_signature_method' => $this->_consumer->getSignatureMethod(),
        'oauth_timestamp'        => $this->_httpUtility->generateTimestamp(),
        'oauth_token'            => $this->_consumer->getLastRequestToken()->getToken(),
        'oauth_version'          => $this->_consumer->getVersion(),
    );

    if (!empty($this->_parameters)) {
        $params = array_merge($params, $this->_parameters);
    }

    $params['oauth_signature'] = $this->_httpUtility->sign(
        $params,
        $this->_consumer->getSignatureMethod(),
        $this->_consumer->getConsumerSecret(),
        $this->_consumer->getLastRequestToken()->getTokenSecret(),
        $this->_preferredRequestMethod,
        $this->_consumer->getAccessTokenUrl()
    );

    return $params;
}

so the error message showing might be misleading.

Best Answer

I was simply using the wrong oauth_token_secret, i should have used the one returned from the access_token not the request_token.

On another note the oauth_verifier is not needed when accessing the api endpoints.

Thats how the function ended up:

public function doshitAction(){

$params = array(
    'siteUrl' => 'http://www.appfactory.loc/magento/oauth',
    'requestTokenUrl' => 'http://www.appfactory.loc/magento/oauth/initiate',
    'accessTokenUrl' => 'http://www.appfactory.loc/magento/oauth/token',
    'consumerKey' => '531a7d194914fbd207766bcb022cdc94',
    'consumerSecret' => 'f51868e362b9211d4fde5ebf412080b0',
    'requestScheme' => Zend_Oauth::REQUEST_SCHEME_HEADER
);

// Initiate oAuth consumer
$consumer = new Zend_Oauth_Consumer($params);
// Using oAuth parameters and request Token we got, get access token
$acessToken = new Zend_Oauth_Token_Access;
$acessToken->setParams(array(
    'oauth_token' => 'e3d089e2b420cd3b940c3cf67587a95d',
    'oauth_token_secret' => 'ab2f46861defe6ee5740f7a748301367'
));


// do a request
$restClient = $acessToken->getHttpClient($params);
$restClient->setUri('http://www.appfactory.loc/magento/api/rest/products');
$restClient->setHeaders('Accept', 'application/json');
$restClient->setMethod(Zend_Http_Client::GET);
$response = $restClient->request();
// Here we can see that response body contains json list of products

return $response->getBody();


}