Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WP REST API V1 #35

Merged
merged 65 commits into from
Jun 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
ca66021
Created new index for WP REST API
claudiosanches Apr 28, 2016
51cf49c
Docs for coupons
claudiosanches Apr 28, 2016
3a4abf9
Docs for coupons, customers, index, orders notes, attributes, categor…
claudiosanches May 24, 2016
238b02f
Product terms batch docs
claudiosanches May 24, 2016
5d8e877
Fixed webhook urls
claudiosanches May 24, 2016
9936b5d
Product attributes batch docs
claudiosanches May 24, 2016
362d264
Updated examples of batch create taxes
claudiosanches May 24, 2016
3ad3a78
Added note about deleting product attributes
claudiosanches May 24, 2016
0d019a8
Webhook batch endpoint docs
claudiosanches May 24, 2016
6f92717
Initial introduction
claudiosanches May 24, 2016
6d46994
Refunds docs
claudiosanches May 30, 2016
7d8f974
Moved webhooks instructions from introdution to webhooks docs
claudiosanches May 30, 2016
f909c7f
Update order docs
claudiosanches May 30, 2016
6fbf88f
Disable search
mikejolley May 31, 2016
7da299d
New styles and logo
mikejolley May 31, 2016
caa04a2
Intro
mikejolley May 31, 2016
d170e68
Intro shuffle
mikejolley May 31, 2016
74fc75a
index
mikejolley May 31, 2016
5702e79
Merge pull request #34 from woothemes/wp-api-v1-proof
claudiosanches May 31, 2016
03e704d
Moar styling
mikejolley May 31, 2016
71f4d7b
Fixed delete orders paramaters
claudiosanches Jun 1, 2016
3f98ef4
Fixed batch taxes examples
claudiosanches Jun 1, 2016
fee6198
Products docs
claudiosanches Jun 1, 2016
b13a1fd
Merge pull request #33 from woothemes/wp-api-v1-styles
claudiosanches Jun 1, 2016
2243660
Improved styles
claudiosanches Jun 1, 2016
5977608
We love Slate
claudiosanches Jun 1, 2016
7b73f98
Improved notices styles
claudiosanches Jun 1, 2016
5dfa08c
Added hover in language selector
claudiosanches Jun 1, 2016
5c3e8e1
Fixed links in notices
claudiosanches Jun 1, 2016
51b326e
Updated introduction and authentication
claudiosanches Jun 1, 2016
54ebcf4
Introduction text
mikejolley Jun 1, 2016
ef3c166
auth
mikejolley Jun 1, 2016
532eeff
coupons
mikejolley Jun 1, 2016
dbd71d9
customers
mikejolley Jun 1, 2016
a149b0d
orders
mikejolley Jun 1, 2016
0a9ea77
Auth endpoint
mikejolley Jun 1, 2016
e4561cf
Order notes
mikejolley Jun 1, 2016
bfc286a
refunds
mikejolley Jun 1, 2016
ac37c20
products
mikejolley Jun 1, 2016
b9905b8
attributes
mikejolley Jun 1, 2016
8ad948a
attribute terms
mikejolley Jun 1, 2016
de9b0da
categories
mikejolley Jun 1, 2016
ed5e588
shipping classes
mikejolley Jun 1, 2016
c76038c
tags
mikejolley Jun 1, 2016
07cc86d
reports
mikejolley Jun 1, 2016
27703cf
Remove title case
mikejolley Jun 1, 2016
01f7ab9
tax rates
mikejolley Jun 1, 2016
ae6185d
tax class
mikejolley Jun 1, 2016
f8cb216
webhooks
mikejolley Jun 1, 2016
4a457e1
Improve oauth instruction
mikejolley Jun 1, 2016
a314f9d
Split legacy API table apart from new api table
mikejolley Jun 1, 2016
0b1694d
Split auth endpoint again
mikejolley Jun 1, 2016
df64a7c
batch descriptions
mikejolley Jun 1, 2016
9dc2c59
Update oAuth tips
claudiosanches Jun 1, 2016
a4e945a
Fixed notices text shadow
claudiosanches Jun 1, 2016
c86de84
Created new REST API keys under authentication section and merged wit…
claudiosanches Jun 1, 2016
fb69384
Updated descriptions in some endpoints
claudiosanches Jun 1, 2016
ebeb52e
Do not runs independently, works based in the WP core REST API
claudiosanches Jun 1, 2016
9e7ad02
More code examples
claudiosanches Jun 1, 2016
914d954
Fixed logo link
claudiosanches Jun 1, 2016
13b26bd
Fixed styles indetation and styles for #warning-top
claudiosanches Jun 1, 2016
4c3a9ee
Updated the deprecated messages in the legacy REST API docs
claudiosanches Jun 1, 2016
97a6abd
Fixed the product categories examples
claudiosanches Jun 2, 2016
8c31272
Updated docs for new attribute format
claudiosanches Jun 2, 2016
51646e0
Updated the categories examples for the new image data format
claudiosanches Jun 2, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified source/images/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added source/images/woocommerce-api-key-generated.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added source/images/woocommerce-api-keys-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added source/images/woocommerce-creating-api-keys.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
336 changes: 336 additions & 0 deletions source/includes/wp-api-v1/_authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,336 @@
# Authentication #

WooCommerce includes two ways to authenticate with the WP REST API. In addition, it is possible to use any [WP REST API authentication](http://v2.wp-api.org/guide/authentication/) plugin or method too.

## REST API keys ##

To be unable to authenticate to any endpoint of our REST API you must generate a REST API keys, currently you can generate new REST API keys by the WordPress admin interface or by an endpoint to auto generate.

### Generating API keys in the WordPress admin interface ###

To create or manage keys for a specific WordPress user, go to WooCommerce > Settings > API > Keys/Apps.

![WooCommerce REST API keys settings](images/woocommerce-api-keys-settings.png)

Click in the "Add Key" button and in the next screen select the User you would like to generate a key for in the User field and add a Description. Choose the level of access for this REST API key, which can be Read access, Write access or Read/Write access. Then select the Generate API Key button and WooCommerce will generate REST API keys for that user.

![Creating a new REST API key](images/woocommerce-creating-api-keys.png)

Now that keys have been generated, you should see two new keys, a QRCode, and a Revoke API Key button. These two keys are your Consumer Key and Consumer Secret.

![Generated REST API key](images/woocommerce-api-key-generated.png)

### Auto generating API keys using our Application Authentication Endpoint ###

This endpoint can be used by any APP to *allow users to generate API keys* for your APP. This makes integration with WooCommerce API easier because the user only needs to grant access to your APP via a URL. After being redirected back to your APP, the API keys will be sent back in a separate POST request.

The following image illustrates how this works:

![Authentication Endpoint flow](images/woocommerce-auth-endpoint-flow.png)

<aside class="warning">
This endpoint works exclusively for users to generate API keys and facilitate integration between the WooCommerce REST API and an application. In no way is this endpoint intended to be used as login method for customers.
</aside>

#### URL parameters ####

| Parameter | Type | Description |
|----------------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `app_name` | string | Your APP name <i class="label label-info">mandatory</i> |
| `scope` | string | Level of access. Available: `read`, `write` and `read_write` <i class="label label-info">mandatory</i> |
| `user_id` | string | User ID in your APP. For your internal reference, used when the user is redirected back to your APP. NOT THE USER ID IN WOOCOMMERCE <i class="label label-info">mandatory</i> |
| `return_url` | string | URL the user will be redirected to after authentication <i class="label label-info">mandatory</i> |
| `callback_url` | string | URL that will receive the generated API key. Note: this URL should be over **HTTPS** <i class="label label-info">mandatory</i> |

#### Creating an authentication endpoint URL ####

You must use the `/wc-auth/v1/authorize` endpoint and pass the above parameters as a query string.

> Example of how to build an authentication URL:

```shell
# Bash example
STORE_URL='http://example.com'
ENDPOINT='/wc-auth/v1/authorize'
PARAMS="app_name=My App Name&scope=read_write&user_id=123&return_url=http://app.com/return-page&callback_url=https://app.com/callback-endpoint"
QUERY_STRING="$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$PARAMS")"
QUERY_STRING=$(echo $QUERY_STRING | sed -e "s/%20/\+/g" -e "s/%3D/\=/g" -e "s/%26/\&/g")

echo "$STORE_URL$ENDPOINT?$QUERY_STRING"
```

```javascript
var querystring = require('querystring');

var store_url = 'http://example.com';
var endpoint = '/wc-auth/v1/authorize';
var params = {
app_name: 'My App Name',
scope: 'read_write',
user_id: 123,
return_url: 'http://app.com/return-page',
callback_url: 'https://app.com/callback-endpoint'
};
var query_string = querystring.stringify(params).replace(/%20/g, '+');

console.log(store_url + endpoint + '?' + query_string);
```

```php
<?php
$store_url = 'http://example.com';
$endpoint = '/wc-auth/v1/authorize';
$params = [
'app_name' => 'My App Name',
'scope' => 'write',
'user_id' => 123,
'return_url' => 'http://app.com',
'callback_url' => 'https://app.com'
];
$query_string = http_build_query( $params );

echo $store_url . $endpoint . '?' . $query_string;
?>
```

```python
from urllib.parse import urlencode

store_url = 'http://example.com'
endpoint = '/wc-auth/v1/authorize'
params = {
"app_name": "My App Name",
"scope": "read_write",
"user_id": 123,
"return_url": "http://app.com/return-page",
"callback_url": "https://app.com/callback-endpoint"
}
query_string = urlencode(params)

print("%s%s?%s" % (store_url, endpoint, query_string))
```

```ruby
require "uri"

store_url = 'http://example.com'
endpoint = '/wc-auth/v1/authorize'
params = {
app_name: "My App Name",
scope: "read_write",
user_id: 123,
return_url: "http://app.com/return-page",
callback_url: "https://app.com/callback-endpoint"
}
query_string = URI.encode_www_form(params)

puts "#{store_url}#{endpoint}?#{query_string}"
```

> Example of JSON posted with the API Keys

```
{
"key_id": 1,
"user_id": 123,
"consumer_key": "ck_xxxxxxxxxxxxxxxx",
"consumer_secret": "cs_xxxxxxxxxxxxxxxx",
"key_permissions": "read_write"
}
```

Example of the screen that the user will see:

![Authentication Endpoint example](images/woocommerce-auth-endpoint-example.png)

#### Notes ####

- While redirecting the user using `return_url`, you are also sent `success` and `user_id` parameters as query strings.
- `success` sends `0` if the user denied, or `1` if authenticated successfully.
- Use `user_id` to identify the user when redirected back to the (`return_url`) and also remember to save the API Keys when your `callback_url` is posted to after auth.
- The auth endpoint will send the API Keys in JSON format to the `callback_url`, so it's important to remember that some languages such as PHP will not display it inside the `$_POST` global variable, in PHP you can access it using `$HTTP_RAW_POST_DATA` (for old PHP versions) or `file_get_contents('php://input');`.

## Authentication over HTTPS ##

You may use [HTTP Basic Auth](http://en.wikipedia.org/wiki/Basic_access_authentication) by providing the REST API Consumer Key as the username and the REST API Consumer Secret as the password.

> HTTP Basic Auth example

```shell
curl https://www.example.com/wp-json/wc/v1/orders \
-u consumer_key:consumer_secret
```

```javascript
var WooCommerceAPI = require('woocommerce-api');

var WooCommerce = new WooCommerceAPI({
url: 'https://example.com',
consumerKey: 'consumer_key',
consumerSecret: 'consumer_secret',
wp_api: true,
version: 'wc/v1'
});
```

```php
<?php
require __DIR__ . '/vendor/autoload.php';

use Automattic\WooCommerce\Client;

$woocommerce = new Client(
'https://example.com',
'consumer_key',
'consumer_secret',
[
'wp_api' => true,
'version' => 'wc/v1'
]
);
?>
```

```python
from woocommerce import API

wcapi = API(
url="https://example.com",
consumer_key="consumer_key",
consumer_secret="consumer_secret",
wp_api=True,
version="wc/v1"
)
```

```ruby
require "woocommerce_api"

woocommerce = WooCommerce::API.new(
"https://example.com",
"consumer_key",
"consumer_secret",
{
wp_json: true,
version: "v3"
}
)
```

Occasionally some servers may not parse the Authorization header correctly (if you see a "Consumer key is missing" error when authenticating over SSL, you have a server issue). In this case, you may provide the consumer key/secret as query string parameters instead.

> Example for servers that not properly parse the Authorization header:

```shell
curl https://www.example.com/wp-json/wc/v1/orders?consumer_key=123&consumer_secret=abc
```

```javascript
var WooCommerceAPI = require('woocommerce-api');

var WooCommerce = new WooCommerceAPI({
url: 'https://example.com',
consumerKey: 'consumer_key',
consumerSecret: 'consumer_secret',
wp_api: true,
version: 'wc/v1',
queryStringAuth: true // When true and using under HTTPS force Basic Authentication as query string
});
```

```php
<?php
require __DIR__ . '/vendor/autoload.php';

use Automattic\WooCommerce\Client;

$woocommerce = new Client(
'https://example.com',
'consumer_key',
'consumer_secret',
[
'wp_api' => true,
'version' => 'wc/v1',
'query_string_auth' => true // When true and using under HTTPS force Basic Authentication as query string
]
);
?>
```

## Authentication over HTTP ##

You must use [OAuth 1.0a "one-legged" authentication](http://tools.ietf.org/html/rfc5849) to ensure REST API credentials cannot be intercepted by an attacker. Typically you will use any standard OAuth 1.0a library in the language of your choice to handle the authentication, or generate the necessary parameters by following the following instructions.

### Creating a signature ###

#### Collect the request method and URL ####

First you need to determine the HTTP method you will be using for the request, and the URL of the request.

The **HTTP method** will be `GET` in our case.

The **Request URL** will be the endpoint you are posting to, e.g. `http://www.example.com/wp-json/wc/v1/orders`.

#### Collect parameters ####

Collect and normalize your query string parameters. This includes all `oauth_*` parameters except for the `oauth_signature` itself.

These values need to be encoded into a single string which will be used later on. The process to build the string is very specific:

1. [Percent encode](https://dev.twitter.com/oauth/overview/percent-encoding-parameters) every key and value that will be signed.
2. Sort the list of parameters alphabetically by encoded key.
3. For each key/value pair:
- Append the encoded key to the output string.
- Append the `=` character to the output string.
- Append the encoded value to the output string.
- If there are more key/value pairs remaining, append a `&` character to the output string.

When percent encoding in PHP for example, you would use `rawurlencode()`.

When sorting parameters in PHP for example, you would use `uksort( $params, 'strcmp' )`.

> Parameters example:

```
oauth_consumer_key=abc123&oauth_signature_method=HMAC-SHA1
```

#### Create the signature base string ####

The above values collected so far must be joined to make a single string, from which the signature will be generated. This is called the signature base string in the OAuth specification.

To encode the HTTP method, request URL, and parameter string into a single string:

1. Set the output string equal to the uppercase **HTTP Method**.
2. Append the `&` character to the output string.
3. [Percent encode](https://dev.twitter.com/oauth/overview/percent-encoding-parameters) the URL and append it to the output string.
4. Append the `&` character to the output string.
5. [Percent encode](https://dev.twitter.com/oauth/overview/percent-encoding-parameters) the parameter string and append it to the output string.

> Example signature base string:

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

#### Generate the signature ####

Generate the signature using the *signature base string* and your consumer secret key with the HMAC-SHA1 hashing algorithm.

In PHP you can use the [hash_hmac](http://php.net/manual/en/function.hash-hmac.php) function.

HMAC-SHA1 or HMAC-SHA256 are the only accepted hash algorithms.

If you are having trouble generating a correct signature, you'll want to review the string you are signing for encoding errors. The [authentication source](https://github.com/woothemes/woocommerce/blob/master/includes/api/class-wc-rest-authentication.php#L141) can also be helpful in understanding how to properly generate the signature.

### OAuth tips ###

* The OAuth parameters must be added as query string parameters and *not* included in the Authorization header. This is because there is no reliable cross-platform way to get the raw request headers in WordPress.
* The required parameters are: `oauth_consumer_key`, `oauth_timestamp`, `oauth_nonce`, `oauth_signature`, and `oauth_signature_method`. `oauth_version` is not required and should be omitted.
* The OAuth nonce can be any randomly generated 32 character (recommended) string that is unique to the consumer key. Read more suggestions on [generating nonces on the Twitter REST API forums](https://dev.twitter.com/discussions/12445).
* The OAuth timestamp should be the unix timestamp at the time of the request. The REST API will deny any requests that include a timestamp outside of a 15 minute window to prevent replay attacks.
* You must use the store URL provided by the index when forming the base string used for the signature, as this is what the server will use. (e.g. if the store URL includes a `www` sub-domain, you should use it for requests)
* You may test your generated signature using LinkedIn's [OAuth test console](http://developer.linkedinlabs.com/oauth-test/) -- leave the member token/secret blank.
* Twitter has great instructions on [generating signatures](https://dev.twitter.com/docs/auth/creating-signature) with OAuth 1.0a, but remember tokens are not used with this implementation.
* Note that the request body is *not* signed as per the OAuth spec, see [Google's OAuth 1.0 extension](https://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html) for details on why.
* If including parameters in your request, it saves a lot of trouble if you can order your query string items alphabetically.
Loading