Cookie-Nonce authentication for REST API cURL Requests

The WordPress REST API is quite a feature, but it can be a struggle to deal with authentication. One option is Basic Auth. But can we leverage the built-in cookie authentication?

If you look at rest_cookie_check_errors(), you’ll see where it’s checking for an authentication cookie and valid nonce. Using WP-CLI, we can carefully piece together a cURL command that passes those values appropriately. Remember, cookies and nonces have a limited lifetime, so be sure to generate new commands as time goes by.

Example

Run wp-cli command

$ wp curl-rest --user=admin 

Output:

curl -H 'X-WP-NONCE: ooO0o00o00' --cookie \
  'wordpress_logged_in_wwWwwwWwwwWWwwwwwWwwwWWwwWWWwwwww=admin|xxxxxxxxxx|YYyyYyyyyYyYyYYYYYyyyYYyyyyYyyYYyyyyyyYYyyY|zZzzzzzZzZzzzzzZZzzzZzzzZzzZZzzzzzzZZzZzzzZZZzzZzZzzzZZzzzzzZzzz' \
  'http://local.wordpress.local/wp-json/wp/v2/settings'

Run curl command

$ curl -H 'X-WP-NONCE: ooO0o00o00' --cookie \
  'wordpress_logged_in_wwWwwwWwwwWWwwwwwWwwwWWwwWWWwwwww=admin|xxxxxxxxxx|YYyyYyyyyYyYyYYYYYyyyYYyyyyYyyYYyyyyyyYYyyY|zZzzzzzZzZzzzzzZZzzzZzzzZzzZZzzzzzzZZzZzzzZZZzzZzZzzzZZzzzzzZzzz' \
  'http://local.wordpress.local/wp-json/wp/v2/settings'

Output:
(prettified, I recommend the jq command line tool)

{
  "title": "wordpress.local",
  "description": "Just another WordPress site",
  "url": "http://local.wordpress.local",
  "email": "[email protected]",
  "timezone": "",
  "date_format": "F j, Y",
  "time_format": "g:i a",
  "start_of_week": 1,
  "language": "",
  "use_smilies": true,
  "default_category": 1,
  "default_post_format": "0",
  "posts_per_page": 10,
  "default_ping_status": "open",
  "default_comment_status": "open"
}

view raw

readme.md

hosted with ❤ by GitHub


<?php
if ( !defined( 'WP_CLI' ) ) return;
/**
*/
class trepmal_cURL_REST extends WP_CLI_Command {
/**
* Generate cURL command for REST API
*
* ## EXAMPLES
*
* # Generare command for fetching all administrators
* $ wp curl-rest –user=1 wp/v2/users?role=administrator
*
* @synopsis [<route>] –user=<user>
*
*/
function __invoke( $args, $assoc_args ) {
$args = wp_parse_args( [
0 => 'wp/v2/settings'
], $args );
list( $route ) = $args;
$route = trim( $route, '/');
if ( substr( $route, 0, 5 ) !== 'wp/v2' ) {
$route = "wp/v2/$route";
}
if ( ! $user_id = get_current_user_id() ) {
WP_CLI::error( 'Please pass –user' );
}
$expiration = time() + DAY_IN_SECONDS;
$manager = WP_Session_Tokens::get_instance( $user_id );
$token = $manager->create( $expiration );
$logged_in_cookie = wp_generate_auth_cookie( $user_id, $expiration, 'logged_in', $token );
$_COOKIE[ LOGGED_IN_COOKIE ] = $logged_in_cookie; // for nonce creation
$url = rest_url( $route );
$nonce = wp_create_nonce( 'wp_rest' );
$cookie = LOGGED_IN_COOKIE . "={$logged_in_cookie}";
$nonce_header = "X-WP-NONCE: $nonce";
$curl = "curl -H '$nonce_header' –cookie '$cookie' '$url'";
$split_curl = _split_str_by_whitespace( $curl, 100 );
$curl = implode( "\\\n ", $split_curl );
WP_CLI::line( $curl );
}
}
WP_CLI::add_command( 'curl-rest', 'trepmal_cURL_REST' );

Leave a Reply

Your email address will not be published. Required fields are marked *

%d bloggers like this: