401 Error "oauth_problem=nonce_used" Adding Products To Magento w/ Rest API
Asked Answered
B

5

10

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"}]}}

Battlement answered 2/4, 2013 at 18:54 Comment(2)
It appears the actual call in Magento that adds the product is running twice for every 1 call that is made. I have edited the _validateNonce function in ../Mage/Oauth/Model/Server.php to skip the validation process and now I get an error indicating the SKU in the product I'm inserting must be unique (and it is inserting the product). So it appears to insert the product and then attempt inserting it again causing the errors... this should be fun to track down... anyone want to beat me to it ;-)Battlement
Did you ever find a solution to this? Running into the same issue, and hacking core code is definitely not a possibility.Aqaba
R
8

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
Rudbeckia answered 28/5, 2014 at 20:38 Comment(2)
this definitely works, but we need another solution that does not modify Magento core files @RudbeckiaOutsole
Thanks to that comment. You can also do this by using $this->getResponse(); ... setHttpResponseCode is not necessary.Janot
E
1

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...

Exergue answered 8/10, 2013 at 22:39 Comment(0)
D
1

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

Dicker answered 22/4, 2016 at 0:4 Comment(0)
T
0

I had the exact same problem and to solve it I looked at the mod_rewrite apache module and turned on logging for this module which is done by adding this to your apache httpd.conf file (this is for apache 2.4x , 2.2x needs to be done differently

<IfModule mod_rewrite.c>
   LogLevel mod_rewrite.c:trace8
</IfModule>

The errors are then logged out to the apache standard error_log When I looked at the rewrite here I could see that my post request was being rewritten twice, the first time it add the products to magento and the second time it failed to add the product again as the nonce was used, obviously.

I could see that the rewrite rule that was causing this in the .htaccess was the one

## workaround for HTTP authorization
## in CGI environment

  RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 

I check my configuration and I was indeed running fast cgi php and I checked this by checking the value of Server API from a php info script. I had spent so long trying to solve this that I knowing the root cause I simply changed PHP from CGI php to an apache module and hey preto my post request now is only rewritten once and returns that all elusive 200 response code.

Thalassic answered 11/8, 2016 at 9:9 Comment(0)
B
-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.

Battlement answered 17/4, 2013 at 17:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.