After hours of pondering over this problem i finally realized why some of us get the following error:
Invalid auth/bad request (got a 403, expected HTTP/1.1 20X or a redirect)
{"messages":{"error":[{"code":403,"message":"Access denied"}]}}
Even after successfully authorizing admin/customer.
The problem unfortunately is not with Magento but could very likely be your server configuration.
I started looking into the Magento Api2 code and realized that they were making use of Zend_Controller_Request_Http method "getHeader" to check for the oAuth authorization.
The following is the code for "getHeader()"
public function getHeader($header)
{
if (empty($header)) {
#require_once 'Zend/Controller/Request/Exception.php';
throw new Zend_Controller_Request_Exception('An HTTP header name is required');
}
// Try to get it from the $_SERVER array first
$temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
if (isset($_SERVER[$temp])) {
return $_SERVER[$temp];
}
// This seems to be the only way to get the Authorization header on
// Apache
if (function_exists('apache_request_headers')) {
$headers = apache_request_headers();
if (isset($headers[$header])) {
return $headers[$header];
}
$header = strtolower($header);
foreach ($headers as $key => $value) {
if (strtolower($key) == $header) {
return $value;
}
}
}
return false;
}
Passed to this function by Magento class "Mage_Api2_Model_Auth_Adapter_Oauth" is:
public function isApplicableToRequest(Mage_Api2_Model_Request $request)
{
$headerValue = $request->getHeader('Authorization');
return $headerValue && 'oauth' === strtolower(substr($headerValue, 0, 5));
}
Since "$request->getHeader('Authorization') is being called, that means the $header var in the getHeader function is "Authorization"
// Try to get it from the $_SERVER array first
$temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
if (isset($_SERVER[$temp])) {
return $_SERVER[$temp];
}
The Zend class then converts "Authorization" to "HTTP_AUTHORIZATION" and looks for it in the $_SERVER array, this is where the problem lies because in that array the Authorization values are located in "$_SERVER['Authorization']" not "$_SERVER['HTTP_AUTHORIZATION"]", they do this because other variables such as CONTENT_TYPE is stored as HTTP_CONTENT_TYPE, except Authorization.
However, it seems as though Zend is aware of this and hence they've written the following code:
// This seems to be the only way to get the Authorization header on
// Apache
if (function_exists('apache_request_headers')) {
$headers = apache_request_headers();
if (isset($headers[$header])) {
return $headers[$header];
}
$header = strtolower($header);
foreach ($headers as $key => $value) {
if (strtolower($key) == $header) {
return $value;
}
}
}
The problem here is that many servers out there do not enable "apache_request_headers", if you are facing this problem it is likely that your hosting company has "apache_request_headers" disabled.
There are 2 solutions here:
- Contact your host and ask them to enable "apache_request_headers".
- Modify the getHeader($header) function in Zend_Controller_Request_Http class
Replace:
$temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
With:
$temp = ($header == 'Authorization') ? $header : 'HTTP_' . strtoupper(str_replace('-', '_', $header));