8

I have a custom post type, card, that I'm exposing through the WP REST API. Is there a way to require authentication, with cookie or Basic Auth header? I see an argument under the POST method block for password, but I'm not sure how to use it.

enter image description here

9
+50

When we register a rest route with register_rest_route(), then we can use the permission_callback parameter with the kind of permission we want.

Check for example how WP_REST_Posts_Controller::register_routes() and WP_REST_Users_Controller::register_routes() implement the permission callback.

The password argument you're referring to is the content's password, that you can set for each post and that's not the same.

But since you want to target existing routes, like:

/wp/v2/cards
/wp/v2/cards/(?P<id>[\d]+)
/wp/v2/cards/...possibly some other patterns...

you could try e.g. the rest_dispatch_request filter to setup your additional permission check for those kind of routes.

Here's a demo plugin:

add_filter( 'rest_dispatch_request', function( $dispatch_result, $request, $route, $hndlr )
{
    $target_base = '/wp/v2/cards';    // Edit to your needs

    $pattern1 = untrailingslashit( $target_base ); // e.g. /wp/v2/cards
    $pattern2 = trailingslashit( $target_base );   // e.g. /wp/v2/cards/

    // Target only /wp/v2/cards and /wp/v2/cards/*
    if( $pattern1 !== $route && $pattern2 !== substr( $route, 0, strlen( $pattern2 ) ) )
        return $dispatch_result;

    // Additional permission check
    if( is_user_logged_in() )  // or e.g. current_user_can( 'manage_options' )
        return $dispatch_result;

    // Target GET method
    if( WP_REST_Server::READABLE !== $request->get_method() ) 
        return $dispatch_result;

    return new \WP_Error( 
        'rest_forbidden', 
        esc_html__( 'Sorry, you are not allowed to do that.', 'wpse' ), 
        [ 'status' => 403 ] 
    );

}, 10, 4 );

where we target the /wp/v2/cards and /wp/v2/cards/* GET routes, with additional user permission checks.

When debugging it with the WordPress cookie authentication, we can e.g. test it directly with:

https://example.tld/wp-json/wp/v2/cards?_wpnonce=9467a0bf9c

where the nonce part has been generated from wp_create_nonce( 'wp_rest' );

Hope this helps!

  • I tried to make it general for a given target base, but maybe there's an easier way around this? I added a capability example as an inline comment @MarkKaplun – birgire May 10 '17 at 12:34
  • Maybe it's even simpler to remove the endpoint for a given custom post type, with the register_post_type_args filter and e,g, set $args['show_in_rest'] = is_user_logged_in(); for a given post type or based on $args['rest_base']. Not sure if that's wanted or recommended ;-) – birgire May 10 '17 at 17:24
3

The "password" field you are seeing is actually not for the REST API, but for the Post entry itself. Individual posts in WordPress can be password protected such that you need the password in order to see their content.

This form of individual post-password is not a strong password mechanism, it is a shared password. The password is the same for all users, and it is stored in the database unencrypted and unhashed. It is was never intended as a secure mechanism by any means, it is a simple mechanism to hide content in a simple way.

If you want to use this mechanism with the REST API, then it is possible. For example, if the individual post's ID is 123, then a post can be retrieved like so:

http://example.com/wp-json/wp/v2/posts/123

If that post is password protected, then this URL will retrieve it:

http://example.com/wp-json/wp/v2/posts/123?password=example-pass

Reference: https://developer.wordpress.org/rest-api/reference/posts/#retrieve-a-post

If you need stronger, user-based authentication, then WordPress offers a way to make posts "private" instead. This setting makes posts only visible to user accounts that have the "read_private_posts" capability, which is limited to the Administrator and Editor roles by default. (Note: Private only makes the post contents private, their Titles can still be exposed.)

When you make a custom post type, this same capability is mapped to the plural of your type (using plural_base). So for a post type of cards, there would be a similar "read_private_cards" permission available for you to assign to user roles if desired.

Now, Authentication on a user-level is not actually built into the REST API. The standard WordPress cookie based auth works fine, however the API offers no way to get that cookie. It will accept it if it is present, but you have to do the normal login flow to get such a cookie. If you want some other authentication approach, then you need a plugin for it.

Four such plugins exist. These are OAuth 1.0, Application Passwords, JSON Web Tokens, and a Basic Authentication plugin. Note that the Basic Authentication is easiest, however it is also insecure and thus only recommended for testing and development purposes. It should not be used on a live production server.

You can find more information about these plugins here:

https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/#authentication-plugins

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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