One of the main purposes of an API is to allow the integration of different services/systems.
Let’s consider that the WordPress REST API can have both public and protected endpoints, where public endpoints do not require any form of authentication, and protected endpoints do.
- Example of a public endpoint:
GET https://main.loc/wp-json/wp/v2/posts
- Example of a protected endpoint:
POST https://main.loc/wp-json/wp/v2/posts
Internally, WordPress protects the POST endpoint like this:
WordPress 5.4: wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php:550
if ( ! current_user_can( $post_type->cap->create_posts ) ) {
return new WP_Error(
'rest_cannot_create',
__( 'Sorry, you are not allowed to create posts as this user.' ),
array( 'status' => rest_authorization_required_code() )
);
}
Which ultimately means it’s a cookie-based authentication method, through the chain current_user_can()
-> _wp_get_current_user
-> determine_current_user
filter -> wp_validate_auth_cookie
and wp_validate_logged_in_cookie
hooked actions.
Those actions check if the request contains a valid authentication cookie, which is verified through the function, but it makes it difficult to generate them from an external system, because of two reasons:
- The cookie name itself requires the knowledge of the value of
COOKIEHASH
, which for most websites will be a simple md5 of the site URL, but some can override this cookie hash to be something else by defining the constant to another value. - The cookie value, however, is the real challenge. It expects a value in this format:
wordpress_logged_in_COOKIE_HASH=username|expiration|token|hmac
However, AFAIK there is no way to get a token
outside the context of WordPress itself, so I can’t possibly send an cookie-based authenticated request from a third party, only from within WordPress itself.
I understand there are initiatives like https://github.com/WP-API/jwt-auth to provide a JWT based authentication method. However, I as a plugin developer would like to avoid depending on another third-party plugin to provide authentication to my protected endpoints.
The only place I’ve ever seen something like what I would like to achieve is in WooCommerce. It hooks itself to the determine_current_user
to add it’s own authentication logic, on top of the default cookie-based one: https://github.com/woocommerce/woocommerce/blob/master/includes/class-wc-rest-authentication.php#L69-L90
Which adds Basic-Auth authentication for websites with HTTPS, and OAuth for HTTP.
For Basic Auth, it requires you to go to your dashboard WooCommerce -> Settings -> REST API -> Create a new key, and assign that key to an user. That will give you an Consumer key
and Consumer secret
that you can use to send authenticated requests:
Authenticated request:
Same request, without authentication:
My understanding, after all, is that WordPress 5.4 REST API therefore does not provide a way to send authenticated requests from external servers to protected endpoints out-of-the-box, and you can either go with a JWT third-party route, or build a robust solution to provide Basic Auth or OAuth authentication methods, like WooCommerce have done. Is that right?