Faizaan Gagan
Faizaan Gagan

Reputation: 752

Issue while accessing WooCommerce Rest API from OkHttp based app

I want to build an android client that can interact with the WooCommerce based site using the Rest Api provided by WooCommerce

This is my android code. I am using OkHttp library for networking.

public class MainActivity extends AppCompatActivity {
    OkHttpClient client;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String cred = Credentials.basic("ck_...","cs_...");

        OkHttpClient client = new OkHttpClient
                                    .Builder()
                                    .build();
        Request req = new Request
                            .Builder()
                .addHeader("Authorization",cred)

                .url("http://10.0.2.2:8080/woocom/wp-json/wc/v2/products")
                            .build();
        client.newCall(req).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d("api resp", "onFailure: ");
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.d("Api resp", "onResponse: "+response.body().string());
            }
        });
    }
}

This is the error log after running the app

com.example.android.woocommerceapiintegration D/Api resp: onResponse: {"code":"woocommerce_rest_cannot_view","message":"Sorry, you cannot list resources.","data":{"status":401}}

What am I doing wrong here. I tried out the NodeJS client provided by WooCommerce which works fine.

Also I cannot access the rest api via curl according to the command given in the docs

Can someone tell me what I am doing wrong ?

Update: The selected answer is what needs to be done in production environments, and is the technically right thing to do. If you want to avoid the hassle of OAuth while on a development server, I have answered it seperately.

Upvotes: 1

Views: 1037

Answers (2)

Faizaan Gagan
Faizaan Gagan

Reputation: 752

Thanks akseli for answering my question.I've also awarded you the bounty and thanks for adding to my knowledge. Despite everything, I've found a simple solution to this problem.

My concern was that while development, We generally don't have an https based server and hence have to go through that tedious OAuth based process which won't be used is production anyway as the server we will probably use will be https enabled.

So, to use basic authentication while on an http dev server, you need to go to [your wordpress directory]/wp-content/woocommerce/includes/api. Find out class-wc-rest-authentication.php. This class handles the api authentication. Find the authenticate function which looks like this

public function authenticate( $user_id ) {
    // Do not authenticate twice and check if is a request to our endpoint in the WP REST API.
    if ( ! empty( $user_id ) || ! $this->is_request_to_rest_api() ) {
        return $user_id;
    }

    if ( is_ssl() ) {
        return $this->perform_basic_authentication();
    }

    return $this->perform_oauth_authentication();
}

comment out the condition is_ssl and simply return $this->perform_basic_authentication(), so that in any case, basic authentication is performed.

Note:This is a hack just to avoid the hassle of OAuth authentication while in dev environment and is not at all recomended in production.

Upvotes: 1

akseli
akseli

Reputation: 2818

The 401 code indicates an authorization issue with your connection. Specifically your issue is caused by your usage of BasicAuth with an HTTP connection.

The WooCommerce REST API Documentation indicates that BasicAuth is only supported for HTTPS connections, and HTTP connections must use OAuth 1.0a "one-Legged" authentication to "ensure" your credentials aren't intercepted by an attacker. It's important to note that even with OAuth 1.0a, an HTTP connection will never be truly secure and it's highly recommended to switch your app over to a secure HTTPS connection.

Meanwhile, in order to get your code working, you'll have to implement the OAuth 1.0a authentication method for your Android app.

You can find a complete set of instructions and a complete project example of OAuth 1.0a implementation for Android here. The GitHub Page has an excellent guide with step-by-step instructions on using the library linked above. Just make sure that when using the code provided you make sure to account for the fact that you're using OKHttp. Luckily, the author has commented the code in the instructions very well and makes a note of changes to make when using something like OkHttp.

You could use Retrofit and simply write an Interceptor which takes care of the 'nitty-gritty' part as detailed in the documentation here.

You could also follow the step by step guide detailed in the WooCommerce Documentation here to generate your OAuth signature and finally encodedUrl and then pass it to your http client. This processs involves: (see the Documentation for detailed specs for each section)

  1. Collecting the request method and URL
  2. Collecting all oauth_* parameters and encoding them into a single string using percent encoding and correct ordering. For Example (taken from WooCommerce Docs): oauth_consumer_key=abc123&oauth_signature_method=HMAC-SHA1
  3. Create the base string for the signature by joining the values from 1 and 2. For example: (once again from Docs):

GET&http%3A%2F%2Fwww.example.com%2Fwp-json%2Fwc%2Fv2%2Forders&oauth_consumer_key%3Dabc123%26oauth_signature_method%3DHMAC-SHA1

  1. Finally generate the signature using HMAC-SHA1 (HMAC-SHA256 is also supported).

Personally I would recommend either the first or second approach. "No need to reinvent the wheel".

EDIT: You can look at this question which discusses how you can use self-signed certificates in a local dev environment with OkHttp.

Upvotes: 1

Related Questions