WooCommerce - woocommerce_rest_cannot_view - Status 401 - wordpress

I have generated a consumer key and consumer secret. The website has SSL installed. I have also installed plugins required for JSON and REST services. This is how the url looks like:
https://<url>/wp-json/wc/v1/products
When I am trying to get(GET) the product details using Basic Auth by using POSTMAN, a Chrome plugin, I get a JSON response like:
{
"code": "woocommerce_rest_cannot_view",
"message": "Sorry, you cannot list resources.",
"data": {
"status": 401
}
}
I have both the READ and WRITE permissions corresponding to the Consumer key.

The 401 error you are getting is because you are using basic auth even though your website is not secure (does not have https).
The solution in postman is to use OAuth 1.0. Just add the consumer key and consumer secret and send the request.

I met same problem.
Here is how I solve it:
require "woocommerce_api"
woocommerce = WooCommerce::API.new(
"https://example.com",
"consumer_key",
"consumer_secret",
{
wp_json: true,
version: "wc/v1",
query_string_auth: true
}
)
The key is query_string_auth: true
you need to force basic authentication as query string true under HTTPS

This is how i stopped worrying and moved on.
In short, the woocommerce rest controllers pretty much all have a SOMEWPRESTCLASS::get_item_permissions_check() method which in turn calls wc_rest_check_post_permissions() to decide if it returns that error;
So you hook into that and validate whichever way you want:
add_filter( 'woocommerce_rest_check_permissions', 'my_woocommerce_rest_check_permissions', 90, 4 );
function my_woocommerce_rest_check_permissions( $permission, $context, $object_id, $post_type ){
return true;
}

Trying to help others:
I was struggling with the 401 response while trying to CURL, and also with VBA trying to request as content-type "application/json"
However, I was able to pull a valid response by just entering this in my browser address bar:
https://mywebsite.com/wp-json/wc/v2/products?consumer_key=ck_blahblah&consumer_secret=cs_blahblah
Following this line of thought, I went back to my VBA app and changed the content type to "application/text" and was able to pull a valid response text with response code 200.
Hope this helps someone.

Try this, I had the same issue with the automattic/woocommerce library and I just got it working by appending the customer_key and customer_secret to the query.
$woocommerce->get("customers/$userId?consumer_key={$this->key}&consumer_secret={$this->secret}");
Quick Edit
The above method works but I found a better solution for the automattic/woocommerce library.
Set query_string_auth to true
Had to dig into the code to find this setting.
Found nothing on it in the docs
return new Client($this->url, $this->key, $this->secret, [
"query_string_auth" => true
]);

I just ran into this. Apparently something was funny with how curl was handling the url, so I had to encapsulate it in double quotes.
This doesn't work:
curl https://www.my-site.com/wp-json/wc/v3/orders?consumer_key=ck_40097dbc2844ce7712e1820bcadf0149c2bedegh&consumer_secret=cs_ab57e19263af0b9ab4c596c310f1e7904bb20123
This does work:
curl "https://www.my-site.com/wp-json/wc/v3/orders?consumer_key=ck_40097dbc2844ce7712e1820bcadf0149c2bedegh&consumer_secret=cs_ab57e19263af0b9ab4c596c310f1e7904bb20123"

You can try Oauth 1.0 with postman:

Problem solved by adding this line below to the end of .htaccess file
All you need to add this line to .htaccess , this work with me
SetEnv HTTPS on
And make sure use OAuth 1.0 for Authorization

Try making the request using query parameter, like this:
https://www.exemple.com/wp-json/wc/v3/orders?consumer_key=ck_01234567890&consumer_secret=cs_01234567890
here: https://www.exemple.com you'll need to fill your url domain.
here: consumer_key and consumer_secret is your ck and cs that was previous genereted on WooCommerce > Settings > Advanced > REST API

Here is a modified answer to Quickredfox's anwer:
add_filter('woocommerce_rest_check_permissions', 'my_woocommerce_rest_check_permissions', 90, 4);
function my_woocommerce_rest_check_permissions($permission, $context, $object_id, $post_type) {
if($_GET['consumer_key'] == 'asdfghj' && $_GET['consumer_secret'] == 'qwerty') {
return true;
}
return $permission;
}
The downside to this is that the flexibility of adding and revoking access for users using a gui is lost. However, if nothing else works and you just can't figure out why, this will work and does not expose the API to the whole world.
Oh, and this requires passing the key and secret as parameters a la:
https://foo.bar.com/wp-json/wc/v3/products/123&consumer_key=asdfghj&consumer_secret=qwerty
This will work without https, but if you use it without https, remember that any credentials you send along with your request will be sent in plain text.

I just ran into this, I was getting the exact same error message as OP. I was using https and OAuth 1. The problem ended up being the domain. I was trying to access example.com when the correct domain for the site was www.example.com.
This URL returns 401 woocommerce_rest_cannot_view error:
https://example.com/wp-json/wc/v3/products
This URL works and returns results:
https://www.example.com/wp-json/wc/v3/products

For local development (localhost) you can also use Basic Auth (e.g. for Postman) instead of Consumer Key & Consumer Secret. It works seamlessly.

Add this code to function.php to fix the problem:
add_filter( 'woocommerce_rest_check_permissions', 'my_woocommerce_rest_check_permissions', 90, 4 );
function my_woocommerce_rest_check_permissions( $permission, $context, $object_id, $post_type ){
return true;
}

in node js code would be
const WooCommerceRestApi = require("#woocommerce/woocommerce-rest-api").default;
const api = new WooCommerceRestApi({
url: "http://example.com",
consumerKey: "ck_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
consumerSecret: "cs_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
queryStringAuth: true,
version: "wc/v3"
});

It's sometimes an error with wordpress htaccess configuration (only if you are accessing website by https).
For some reason woocommerce want you to authorize with basic authentication when your are connecting through https which some hosting blocks so you need to unlock it.
you need to change
RewriteRule ^index\.php$ - [L]
To
RewriteRule ^index\.php$ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]

Related

Symfony HttpFoundation\Request with no user agent specified leads to 403 Forbidden

I am using symfony to create an API to update some dataset. One of the possible update is coming from a third party through an HTTP request which does not include user agent specifications. As a result, the call is returning a 403 Forbidden error.
I kept the code to its simpliest form (see below):
/**
* #Route("/Debug", name="Debug")
*/
public function Debug(Request $request)
{
return new Response(
'hurray !!' ,
Response::HTTP_OK
);;
}
I am sure that the issue is coming from the user agent, I have been able to reproduce it with postman by taking this header item out.
Any idea how to fix this issue ?
Thanks !
Adrien

multisite Wordpress API CORS issue with headers set in theme (v5)

I have a React app which calls a Wordpress v5 API.
const api = `${WAPI}`;
const headers = {
'Content-Type': 'application/json'
} ;
fetch(api, {
headers: headers
})
.then(function(data){
console.log(data);
})
.then(this.handleposts)
.catch(err => console.log(err));
}
Which returns this error in my development tools' console:
Access to fetch at 'http://XXX.XXX.XXX.XX/firstcivdivcareers/wp-json/wp/v2/posts/' from origin 'http://localhost:9000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
I used to call a single Wordpress site API but now it doesn't' work. I assumed Wordpress API would work with cross-origin domain calls to be used as a third-party service.
I added changes to the theme's functions.php. When I go to my site in the browser and check the header's in dev tool console. I can see I sent my response with the proper headers. However, doesn't work the same when I call through my JS's fetch call.
Changes added to functions.php:
/**
* Only allow GET requests
*/
function add_cors_http_header(){
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET");
header("Access-Control-Allow-Headers: origin");
}
Locate the file in your wordpress code which is serving the API.
You just have to add at the start of that file:
<? header("Access-Control-Allow-Origin: *"); ?>
Edit:
Instead of editing the core files, the better option is to use the filter as explained in this thread. You can put the following code in your functions.php
add_filter('init', 'add_cors_header');
function add_cors_header() {
header(...);
}
I had this issue as well with my Vue.js code. This is what I added to my GET request and I have had no further issues: https://cors-anywhere.herokuapp.com and it immediately precedes the URL:
let url = 'https://cors-anywhere.herokuapp.com/https://jobs.github.com/positions.json?&markdown=true&page=1';
I hope that helps!
You can use this MS Edge plugin t quickly disable Cors.
CORS Unblock - Microsoft Edge Addons
It will work just fine :)

Gravity Forms API always 401

I am trying to use the gravity forms rest api, https://www.gravityhelp.com/documentation/article/web-api/ but I receive a 401 error no matter what I try. I've tried using all the methods listed in the documentation and in Steven Henty's article, https://www.stevenhenty.com/gravity-forms-api/ but it doesn't seem to work.
If I am logged into a wordpress site as administrator should I not be able to use a link like:
http://mydomain/gravityformsapi/forms/
Thank you for any suggestions.
For mine case it was that I haven't clicked the update button "Web API" Tab.
Make sure you click update button , although it does show the API Key's but still you have to click update button to enable API.
I was getting the same thing due to some weirdness about the route endpoint. When calculating the signature you don't use a trailing slash on the route: forms/1.
But you do use a trailing slash in the URL (otherwise I got a 301 Moved Permanently):
http://demo.gravityforms.com/gravityformsapi/the_route/?api_key...
It looks odd to have /?api_key... but that is what works for me.
Here's the ruby example I was using with the demo credentials:
GravityFormsAPI.generate_URL(site: 'demo.gravityforms.com', route: 'forms/1', public_api_key: '5b225f8382', private_api_key: 'fc6d1bc71d2ebfc')
Hope this helps.
Sometimes i received intermittent 401 error after a lot of research i find this article
Azure DocumentDB Intermittent 401 error when querying REST API via Obj-c
If the signature contains + sign i received 401 error
Maybe that help other person
Sorry for my english writing
Based on the solution here I'm posting this answer.Imagine you have created the URL and it didn't work and you got 401. Then after a little time you realized the error that Opps! The parameters I was passing needed a bracket and you run the code again and you again got 401.
Why is that?
This is because the parameters which are apiKey, Signature and Expire time are the same and you only changed the other parameters with your GET request. However these three parameters are used to authenticate the user so that means the old signature which was generated to deny the permission will deny it again no matter what.
So to fix that I just changed the expire time from 1577922200 to 1577933200. I could've changed it to anything but the thing is I just need to give something new so that a new signature can be generated. So when I changed it started working.
OTHER POSSIBLE REASONWhile making the signature using SHA1 you use NSString *string_to_sign = [NSString stringWithFormat:#"%#:%#:%#:%#",api_key,http_method,route,expires];
as per the documentation. But in order to make CCHmac you have to pass it two things:
Key
Data
and based on the link it is created as
const char *cKey = [api_private_key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [string_to_sign cStringUsingEncoding:NSASCIIStringEncoding];
So what I was mistaking is that I was using API Key in cKey instead of API Private Key. So I change it as per tutorial said and it worked. Otherwise I was getting 401 not matter what I try.

Drupal 7 feeds, permission-error with oauth for instagram ("public_content")

earlier in 2015 i started creating a website with drupal 7 that imports instagram-content (images, likes, comments etc.) via Drupal Feeds. Everything worked finde, but the projects stopped then.
Now it seems we start that again but suddenly the import is not working anymore. I always get the following error:
{"meta": {"error_type": "OAuthPermissionsException", "code": 400,
"error_message": "This request requires scope=public_content, but this
access token is not authorized with this scope. The user must
re-authorize your application with scope=public_content to be granted
this permissions."}}
I didnt had to send the "public_content" earlier, so i was just sending "basic"-scope access. And as i said, everything worked well.
Now i inserted also the scope for "public_content" along with "basic" within the oauth-Module for feeds. But still getting the error-message above.
Any hints on that?
Thanks in advance and regards,
Fab
This is due to a Instagram Platfrom Update
You'll have to add public_content scope as Joshi has pointed out - and also you'll need to renew your auth token in the settings page.
Then you'll be good to go.
Here is the solution:
Use following code in instagram_social_feed.module
Function: instagram_social_feed_settings()
if (variable_get('instagram_social_feed_client_id', '') != '' && variable_get('instagram_social_feed_redirect_uri', '') != '') {
$form['authenticate'] = array(
'#markup' => l(t('Click here to authenticate via Instagram and create an access token'),
'https://api.instagram.com/oauth/authorize/?client_id=' . variable_get('instagram_social_feed_client_id') . '&redirect_uri=' . variable_get('instagram_social_feed_redirect_uri') . '&response_type=code&scope=public_content'
)
);
}
This will solve the issus

ArangoDB authentication via HTTP

I've seen examples of how to authenticate with a database using arangosh, but I couldn't find anything in the documentation about how to authenticate via the http API. Is this possible? Is it something like this:
http://username:passwd#arangouri.com:8529/_api/document
From the command line, you can do something like this to pass HTTP basic authentication to the server:
curl --basic --user "username:passwd" -X GET http://arangouri.com:8529/_api/document/...
The above example is for curl. If you use any other HTTP client, you have to find the options for setting the username / password for HTTP basic authentication and send them to the server.
Ok, after playing around with authentication in Arango DB on Windows here is what I have found:
I could not get this command to work (which is supposed to enable authentication)
--server.disable-authentication false
UPDATE: I realized I couldn't get this command working because it's not a command at all :-o After looking more closely at the documentation it's a command line option. It should be used when you start arangosh. See documentation here.
I assume I need to adapt it somehow to work in a windows command prompt, but I'm not sure what needs to change. As a work around I opened the file "arangod.conf" (I found it here C:\Program Files (x86)\ArangoDB 1.4.7\etc\arangodb) and changed the following line:
disable-authentication = yes
to
disable-authentication = no
This enabled authentication when I restarted Arango. Yay!
Now to authenticate via http... very simple. It's just basic HTTP auth. So in my case I was using NodeJS and the request library to authenticate. Both examples below work fine.
Credentials appended with .auth:
request({
url:'http://localhost:8529/_api/document/example/20214484',
json: true
}, function (err, data){
console.log(err);
if (data.body.error) console.log("ERROR: " + data.body.errorMessage);
console.log(data.body);
}).auth("username", "password");
OR with credentials in url:
request({
url:'http://username:password#localhost:8529/_api/document/example/20214484',
json: true
}, function (err, data){
console.log(err);
if (data.body.error) console.log("ERROR: " + data.body.errorMessage);
console.log(data.body);
});
It's done through Authorization header where you set authentication mechanism (e.g. Basic) followed by base64 encoded string in format [username]:[password]. More information can be found for example here.

Resources