Restrict access to WordPress REST API
Asked Answered
O

3

10

Is there a way that I can restrict access to url calls made to WP REST API? I am using WP REST API to create AJAX feeds that can be accessed through the URL. They are formatted like this: http://example.com/wp-json/posts?type=post&filter[posts_per_page]=10

The problem is that anyone can add /wp-json/posts?type=post&filter[posts_per_page]=10 to the end of my URL and retrieve a feed of this information. I want to turn this off when users are not logged into WordPress doing something like this:

if ( !is_user_logged_in()) {
    // Turn off REST API feed
}

Or, I would like to add some kind of authentication that needs to be added to mask the api.

I found something like this online but I have not had any luck getting it to work. I added it to a custom plugin. Unfortunately I am still able to access the feed when not logged in.

add_action( 'init', function() {
    global $wp_post_types;
    $wp_post_types['post']->show_in_rest = is_user_logged_in();
}, 20 );

I am worried that there is no way to make a connection between activating the API and making the HTTP request on the front end. Am I thinking about this wrong? Has anyone run into this problem?

Thanks!

Obelize answered 18/8, 2015 at 21:30 Comment(2)
Are you trying to access the API from the same server/site, or from an external site?Amesace
It will be from the same site and server.Obelize
R
9

The problem and blessing of Wordpress is that it allows too much flexibility, particularly when the platform provides a clean method: Require Authentication for all requests

You can require authentication for all REST API requests by adding an is_user_logged_in check to the rest_authentication_errors filter.

Note: The incoming callback parameter can be either null, a WP_Error, or a boolean. The type of the parameter indicates the state of authentication:

  • null: no authentication check has yet been performed, and the hook callback may apply custom authentication logic.
  • boolean: indicates a previous authentication method check was performed. Boolean true indicates the request was successfully
    authenticated, and boolean false indicates authentication failed.
  • WP_Error: Some kind of error was encountered.
add_filter( 'rest_authentication_errors', function( $result ) {
    // If a previous authentication check was applied,
    // pass that result along without modification.
    if ( true === $result || is_wp_error( $result ) ) {
        return $result;
    }

    // No authentication has been performed yet.
    // Return an error if user is not logged in.
    if ( ! is_user_logged_in() ) {
        return new WP_Error(
            'rest_not_logged_in',
            __( 'You are not currently logged in.' ),
            array( 'status' => 401 )
        );
    }

    // Our custom authentication check should have no effect
    // on logged-in requests
    return $result;
});

To be fair, this is hidden in the frequently asked questions.

Edit: To exclude jwt-auth

global $wp;

// No authentication has been performed yet.
// Return an error if user is not logged in and not trying to login.
if ( ! is_user_logged_in() && $wp->request !== 'wp-json/jwt-auth/v1/token' ) {
    return new WP_Error(
        'rest_not_logged_in',
        __( 'You are not currently logged in.' ),
        array( 'status' => 401 )
    );
}
Remark answered 22/3, 2020 at 9:56 Comment(3)
I tried this and it works fine. BUT: This stops my addon CONTACT FORM 7 from working! I use this as a contact form for users that are not logged in. The addon tries to access /wp-json/contact-form-7/v1/contact-forms/9589/feedback and this is blocked by your code. How cat I avoid this?Shanelleshaner
@Shanelleshaner I have some routes where I do want to allow unauthenticated users to go to, like the wp-json/jwt-auth/v1/token route above. So just replace that route with yoursRemark
Works like a charm for 6.5.4! And you can even add your custom logic and aren't limited to blocking everything.Bristling
M
5

This will remove all REST API endpoints for WordPress and Woocommerce for not logged in users:

function myplugin_removes_api_endpoints_for_not_logged_in() {

    if ( ! is_user_logged_in() ) {

        // Removes WordpPress endpoints:
        remove_action( 'rest_api_init', 'create_initial_rest_routes', 99 );

        // Removes Woocommerce endpoints
        if ( function_exists('WC') )
            remove_action( 'rest_api_init', array( WC()->api, 'register_rest_routes' ), 10 );
    }

} add_action('init', 'myplugin_removes_api_endpoints_for_not_logged_in');
Mob answered 21/6, 2019 at 12:20 Comment(2)
You can add it to your functions.php file, that would do it.Mob
how can I login using nextjs app then ??Budget
G
1

This will block the entire REST API for anyone not logged in:

function no_valid_user_no_rest($user) {
    if (!$user) {
        add_filter('rest_enabled', '__return_false');
        add_filter('rest_jsonp_enabled', '__return_false');
    }
    return $user;
}
add_filter('determine_current_user', 'no_valid_user_no_rest', 50);

Standard caveat that this just turns off REST, nothing else. Make sure it has enough priority to come after other determine_current_user filters. Did not test on multi site.

You can add other tests to the conditional as well, if you want to filter by URL or other factors.

Glitter answered 16/3, 2016 at 19:35 Comment(4)
Garbage. I still get users list from requesting: http://example.com/wp-json/wp/v2/users.Mob
@TuninTuna make sure you are not logged in before testingGlitter
Thanks for your response holmes, I managed to do this in a different way, maybe in a way that wasn't available at the time of this question. I'll post it below for reference.Mob
how can I login using nextjs app then ??Budget

© 2022 - 2024 — McMap. All rights reserved.