1

WordPress end points default rules,

GET               ----> PUBLIC
POST, PUT, DELETE ----> AUTH

How can I force authentication the WordPress REST API GET method requests?

2 Answers 2

2

You can't really apply authentication based directly on whether the request is GET or otherwise, but can forcefully apply authentication requirements globally in that manner, if you like.

I've been quite verbose with the code to illustrate what's happening:

add_filter( 'rest_authentication_errors', function ( $error ) {

    /**
     * If it's a WP_Error, leave it as is. Authentication failed anyway
     *
     * If it's true, then authentication has already succeeded. Leave it as-is.
     */
    if ( strtolower( $_SERVER[ 'REQUEST_METHOD' ] ) === 'get' && !is_wp_error( $error ) && $error !== true ) {

        if ( !is_user_logged_in() ) {
            $error = new \WP_Error( 'User not logged-in' );
        }
        
    }

    return $error;
}, 11 );

Assumptions:

  • PHP is at least version 5.3
  • We're only testing GET requests
  • If an authentication error has been met before this filter is executed, then we leave the error as-is.
  • If there is no error, and in-fact it's set to true, then this means authentication has already succeeded and there's not need to block anything.
  • We're only testing whether or not the user making the request is logged-in i.e. is authenticated with WordPress.
0

Good Question and not that easy to do propperly (took me 1 week to figure that out).

Then I found 2 good summaries in WordPress docs:
Home / REST API Handbook / Extending the REST API / Routes and Endpoints
Home / REST API Handbook / Extending the REST API / Adding Custom Endpoints

There I found out how to use namespaces, routes and permission_callback correctly.

Critical part was to add the Permission Callback into the function.php of your theme.

/**
  * This is our callback function to return (GET) our data.
  *
  * @param WP_REST_Request $request This function accepts a rest request to process data.
  */
function get_your_data($request) {
    global $wpdb;
    $yourdata = $wpdb->get_results("SELECT * FROM your_custom_table");

    return rest_ensure_response( $yourdata );
};

/**
 * This is our callback function to insert (POST) new data record.
 *
 * @param WP_REST_Request $request This function accepts a rest request to process data.
 */
function insert_your_data($request) {
    global $wpdb;
    $contentType = isset($_SERVER["CONTENT_TYPE"]) ? trim($_SERVER["CONTENT_TYPE"]) : '';

    if ($contentType === "application/json") {
        $content = trim(file_get_contents("php://input"));
        $decoded = json_decode($content, true);
        $newrecord = $wpdb->insert( 'your_custom_table', array( 'column_1' => $decoded['column_1'], 'column_2' => $decoded['column_2']));
    };
    if($newrecord){
        return rest_ensure_response($newrecord);
    }else{
        //something gone wrong
        return rest_ensure_response('failed');
    };

    header("Content-Type: application/json; charset=UTF-8");
};
/**
 * This is our callback function to update (PUT) a data record.
 *
 * @param WP_REST_Request $request This function accepts a rest request to process data.
 */
function update_your_data($request) {
    global $wpdb;
    $contentType = isset($_SERVER["CONTENT_TYPE"]) ? trim($_SERVER["CONTENT_TYPE"]) : '';

    if ($contentType === "application/json") {
        $content = trim(file_get_contents("php://input"));
        $decoded = json_decode($content, true);
        $updatedrecord = $wpdb->update( 'your_custom_table', array( 'column_1' => $decoded['column_1'], 'column_2' => $decoded['column_2']), array('id' => $decoded['id']), array( '%s' ));
    };

    if($updatedrecord){
        return rest_ensure_response($updatedrecord);
    }else{
        //something gone wrong
        return rest_ensure_response('failed');
    };

    header("Content-Type: application/json; charset=UTF-8");
};

//  Permission Callback 
// 'ypp' is the Prefix I chose (ypp = Your Private Page)

function ypp_get_private_data_permissions_check() {
    // Restrict endpoint to browsers that have the wp-postpass_ cookie.

    if ( !isset($_COOKIE['wp-postpass_'. COOKIEHASH] )) {
       return new WP_Error( 'rest_forbidden', esc_html__( 'OMG you can not create or edit private data.', 'my-text-domain' ), array( 'status' => 401 ) );
    };
    // This is a black-listing approach. You could alternatively do this via white-listing, by returning false here and changing the permissions check.
    return true;
};

// And then add the permission_callback to your POST and PUT routes:

add_action('rest_api_init', function() {
    /**
    * Register here your custom routes for your CRUD functions
    */
    register_rest_route( 'your_private_page/v1', '/data', array(
       array(
          'methods'  => WP_REST_Server::READABLE,
          'callback' => 'get_your_data',
          // Always allow.
          'permission_callback' => '__return_true' // <-- you can protect GET as well if your like
       ),
       array(
          'methods'  => WP_REST_Server::CREATABLE,
          'callback' => 'insert_your_data',
          // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
          'permission_callback' => 'ypp_get_private_data_permissions_check', // <-- that was the missing part
       ),
       array(
          'methods'  => WP_REST_Server::EDITABLE,
          'callback' => 'update_your_data',
          // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
          'permission_callback' => 'ypp_get_private_data_permissions_check', // <-- that was the missing part
       ),
    ));
});

If you like, I posted a Question (similar issue to yours, but for custom routes) and then my findings in the answer.

Full story with complete code at:
How to force Authentication on REST API for Password protected page using custom table and fetch() without Plugin

Hope this helps a little.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.