Question

From what I have tried and tested so far, the getters and setters do not work inside the function permission_callback.

The alternate way would be to throw a custom 401 from the callback itself.

Is it possible to use the permission_callback, check the parameter, and return false instead of writing a custom response in the callback for the same functionality to do a return 401?

Update 1:

permission_callback => function($request) { $request->get_params(); } does not return anything. I need to check the body parameters to allow or deny the request.

Whereas callback => function($request) { $request->get_params(); } returns the parameters correctly, as it should.

Update 2:

In the constructor, $this->init_api(); add_action('wp_enqueue_scripts', array($this, 'api_wholesale_params'));

In init_api,

$this->set_namespace();

$this->set_route();

$this->api_params = array(
    'methods'             => WP_REST_Server::EDITABLE,
    // 'permission_callback' => array($this, "verify_api_call"),
    'callback'            => array($this, "callback")
);

// Set up the API
add_action('rest_api_init', function() {
    register_rest_route($this->namespace, $this->route, $this->api_params);
});


/**
 * Set property: namespace
 * 
 * Source: https://developer.wordpress.org/reference/functions/get_rest_url/
 */
function set_namespace() {
    return $this->namespace = "wholesale/v1/";
}

/**
 * Set property: route
 */
function set_route() {
    return $this->route = "authorise/";
}

/**
 * Localising the API parameters for use in JS
 */
function api_wholesale_params() {
    wp_register_script('api_wholesale', null);
    wp_enqueue_script('api_wholesale');

    wp_localize_script('api_wholesale', 'apiWholesale', array(
        'namespace'         => $this->namespace,
        'route'             => $this->route,
        "url"               => get_rest_url(null, $this->namespace.$this->route),
        "app_id"            => $this->manifest_data['app_id'],
        "ver"               => $this->manifest_data['ver'],
    ));
}

/**
 * Verification of the API call origin
 */
function verify_api_call(WP_REST_Request $req) {
    // $req->get_params(); // returns nothing

    if (array_key_exists('body', $this->params) && array_key_exists('xsrf', $this->params['body'])) {
        // Validate the XSRF token, returns true or false
        $valid_xsrf = $this->verify_xsrf();

        // Returning false would trigger a 401
        return $valid_xsrf ? true : false;
    }
}

// API callback
function callback(WP_REST_Request $req) {
    // Unable to do this in permission_callback
    $this->params        = $req->get_params();

    // Want to do it part using permission_callback
    if ($this->verify_api_call()) {
        return rest_ensure_response($this->res);
    }
}

As you would see, I have commented permission_callback because $request->get_params() does not return anything in verify_api_call. I can, however, call the same $request-get_params() from callback.

Was it helpful?

Solution

I've created a reduced test case that demonstrates that what you want to do is achievable:

add_action( 
    'rest_api_init',
    function() {
        register_rest_route(
            'wpse/343039',
            'route',
            [
                'methods' => [ 'POST' ],
                'permission_callback' => function( WP_REST_Request $request ) {
                    if ( '1' == $request->get_param( 'param' ) ) {
                        return true;
                    } else {
                        return false;
                    }
                },
                'callback' => function( WP_REST_Request $request ) {
                    return rest_ensure_response( '1' );
                },
            ]
        );
    }
);

With this rest route, if I send a POST request to:

https://example.com/wp-json/wpse/343039/route

I will receive a 401 response unless I pass param with the value of 1 in the request body:

{
    "param": 1
}

It can also be passed as form data. If I do pass that parameter, then I see 1 in the response, as expected.

The proper way to return a 401 from a REST endpoint is to return false from the permission_callback function, and as I've demonstrated, you have full access to the request in the callback, so long as you accept it as an argument.

Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top