Verify nonce in REST API?

I would like to understand the best practices regarding nonce validation in REST APIs.

I see a lot of people talking about wp_rest nonce for REST requests. But upon looking on WordPress core code, I saw that wp_rest is just a nonce to validate a logged in user status, if it’s not present, it just runs the request as guest.

That said, should I submit two nonces upon sending a POST request to a REST API? One for authentication wp_rest and another for the action foo_action?

If so, how should I send wp_rest and foo_action nonce in JavaScript, and, in PHP, what’s the correct place to validate those nonces? (I mean validate_callback for a arg? permission_callback?)

2 s
2

You should pass the special wp_rest nonce as part of the request. Without it, the global $current_user object will not be available in your REST class. You can pass this from several ways, from $_GET to $_POST to headers.

The action nonce is optional. If you add it, you can’t use the REST endpoint from an external server, only from requests dispatched from within WordPress itself. The user can authenticate itself using Basic Auth, OAuth2, or JWT from an external server even without the wp_rest nonce, but if you add an action nonce as well, it won’t work.

So the action nonce is optional. Add it if you want the endpoint to work locally only.

Example:

/**
* First step, registering, localizing and enqueueing the JavaScript
*/
wp_register_script( 'main-js', get_template_directory_uri() . '/js/main.js', [ 'jquery' ] );
wp_localize_script( 'main-js', 'data', [
    'rest' => [
        'endpoints' => [
            'my_endpoint'       => esc_url_raw( rest_url( 'my_plugin/v1/my_endpoint' ) ),
        ],
        'timeout'   => (int) apply_filters( "my_plugin_rest_timeout", 60 ),
        'nonce'     => wp_create_nonce( 'wp_rest' ),
        //'action_nonce'     => wp_create_nonce( 'action_nonce' ), 
    ],
] );
wp_enqueue_script( 'main-js' );

/**
* Second step, the request on the JavaScript file
*/
jQuery(document).on('click', '#some_element', function () {
    let ajax_data = {
        'some_value': jQuery( ".some_value" ).val(),
        //'action_nonce': data.rest.action_nonce
    };

    jQuery.ajax({
        url: data.rest.endpoints.my_endpoint,
        method: "GET",
        dataType: "json",
        timeout: data.rest.timeout,
        data: ajax_data,
        beforeSend: function (xhr) {
            xhr.setRequestHeader('X-WP-Nonce', data.rest.nonce);
        }
    }).done(function (results) {
        console.log(results);
        alert("Success!");
    }).fail(function (xhr) {
        console.log(results);
        alert("Error!");
    });
});

/**
* Third step, the REST endpoint itself
*/
class My_Endpoint {
        public function registerRoutes() {
        register_rest_route( 'my_plugin', 'v1/my_endpoint', [
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => [ $this, 'get_something' ],
            'args'                => [
                'some_value'     => [
                    'required' => true,
                ],
            ],
            'permission_callback' => function ( WP_REST_Request $request ) {
                return true;
            },
        ] );
    }

    /**
    *   @return WP_REST_Response
    */
    private function get_something( WP_REST_Request $request ) {
        //if ( ! wp_verify_nonce( $request['nonce'], 'action_nonce' ) ) {
        //  return false;
        //}

        $some_value        = $request['some_value'];

        if ( strlen( $some_value ) < 5 ) {
            return new WP_REST_Response( 'Sorry, Some Value must be at least 5 characters long.', 400 );
        }

        // Since we are passing the "X-WP-Nonce" header, this will work:
        $user = wp_get_current_user();

        if ( $user instanceof WP_User ) {
            return new WP_REST_Response( 'Sorry, could not get the name.', 400 );
        } else {
            return new WP_REST_Response( 'Your username name is: ' . $user->display_name, 200 );
        }
    }
}

Leave a Comment