Monday, April 25, 2016

401 Error “oauth_problem=nonce_used” Adding Products To Magento w/ Rest API

Leave a Comment

Getting a 401 status with "oauth_problem=nonce_used" message return when attempting to add products to Magento using the rest api. Oddly, the products are still get imported but it's really throwing me off because I'm not getting the product id's back in which to update the stock info.

Magento install is brand new (crucialwebhost installer) 1.7.0.2 and the code I'm using is pretty much copied and pasted from magento site...

$callbackUrl = '****'; $temporaryCredentialsRequestUrl = "*****/oauth/initiate?oauth_callback=".urlencode($callbackUrl); $adminAuthorizationUrl = '*****/admin/oauth_authorize'; $accessTokenRequestUrl = '*****/oauth/token'; $apiUrl = '*****/api/rest';  $consumerKey = '*****'; $consumerSecret = '******';  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";     $productData = json_encode(array( 'type_id' => 'simple',     'attribute_set_id' => 4,     'sku' => $local_product['sku'],     'weight' => 1,     'status' => 1, 'visibility' => 4,     'name' => $local_product['name'],     'description' => $local_product['description'],     'short_description' => $local_product['description'],     'price' => $local_product['price'],     'tax_class_id' => 0,   ));   $headers = array('Content-Type' => 'application/json');   $oauthClient->fetch($resourceUrl, $productData, OAUTH_HTTP_METHOD_POST, $headers);   $respHeader = $oauthClient->getLastResponseHeaders();   }  } catch(OAuthException $e) {   print_r($e); } }  session_destroy(); 

Exact error: {"messages":{"error":[{"code":401,"message":"oauth_problem=nonce_used"}]}}

4 Answers

Answers 1

In Mage_Api2_Model_Resource, about line 227, locate

$this->getResponse()->setHeader('Location', $newItemLocation); 

and insert just after this:

 $this->getResponse()->setHttpResponseCode(202);  

Ref: Wikipedia "HTTP Location":

The HTTP Location header field is returned in responses from an HTTP server under two circumstances:

  1. To ask a web browser to load a different web page. In this circumstance, the Location header should be sent with an HTTP status code of 3xx.
  2. To provide information about the location of a newly created resource. In this circumstance, the Location header should be sent with an HTTP status code of 201 or 202

Answers 2

I had exactly the same problem and spend weeks tracking down the problem. It seems to be a strange combination of Apache with PHP and Rewriting. In the end I created a clean installation and the problem was gone. I also tried to create a second installation where the problem could be observed but failed - the error appeared only in my production system, not in any of test installations...

Answers 3

I looked at this and from what I see in the code, it looks like OAuth register all your calls and if it find out that the exact same nonce was actually used with the exact same timestamp as some previous call, it will just discard it with this very specific oauth_problem=nonce_used error.

Code from app/code/core/Mage/Oauth/Model/Server.php

/**  * Validate nonce request data  *  * @param string $nonce Nonce string  * @param string|int $timestamp UNIX Timestamp  */ protected function _validateNonce($nonce, $timestamp) {     $timestamp = (int) $timestamp;      if ($timestamp <= 0 || $timestamp > (time() + self::TIME_DEVIATION)) {         $this->_throwException('', self::ERR_TIMESTAMP_REFUSED);     }     /** @var $nonceObj Mage_Oauth_Model_Nonce */     $nonceObj = Mage::getModel('oauth/nonce');      $nonceObj->load($nonce, 'nonce');      if ($nonceObj->getTimestamp() == $timestamp) {         $this->_throwException('', self::ERR_NONCE_USED);     }     $nonceObj->setNonce($nonce)         ->setTimestamp($timestamp)         ->save(); } 

So I would say, when you do calls through Magento API in REST you should take extra care that each and every request you make have its own unique generated combinaison timestamp / nonce value.

Also see

oauth_nonce. A random value, uniquely generated by the application.
oauth_timestamp. A positive integer, expressed in the number of seconds since January 1, 1970 00:00:00 GMT.

And

nonce_used: The nonce-timestamp combination has already been used.

From this source : http://devdocs.magento.com/guides/v2.0/get-started/authentication/gs-authentication-oauth.html

Answers 4

Work Around:

Use SOAP API.

Reason for not using it before:

SOAP API didn't provide ability to at custom product attributes or product quantity increment fields.

Fix:

Add any field you want to the product using the SOAP api by first creating an array of objects for them like this (last 4 lines of code below repeated for each field added):

$additionalAttrs = array();  $per_item = new stdClass(); $per_item->key = 'price_per_item'; $per_item->value = $local_product['price']; $additionalAttrs['single_data'][] = $per_item; 

And then adding it to your product array with the key "additional_attributes" like:

'additional_attributes' => $additionalAttrs, 

I know this work around only helps people that were avoiding the SOAP API for the same reason I was but hopefully it helps some of you. That error we're seeing where it tries to add a product twice seems to be server configuration specific and very hard to track down.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment