Opens in a new tab
  1. Home
  2. Guides
  3. System
System guide

How to restrict the WordPress REST API

Learn how to restrict the WordPress REST API without disabling it completely, including authentication, route permissions, capability checks, user enumeration protection and safe testing.

  • Updated September 8, 2026
  • 21 min read
  • WordPress guide

The WordPress REST API is now a fundamental part of WordPress.

It powers communication between WordPress and JavaScript applications, exposes structured content to external systems, and supports major parts of the modern administration interface.

That also means the REST API creates a public HTTP interface into your WordPress installation.

By default, many REST endpoints are intentionally accessible without authentication because WordPress needs to expose public content such as posts, pages, taxonomies and other resources.

Other endpoints require authentication and specific capabilities.

The important security question is therefore usually not:

How do I disable the WordPress REST API?

It is:

Which REST API requests should anonymous visitors be allowed to make?

That distinction changes the entire approach.

A secure REST configuration normally keeps the API available while restricting unnecessary access to sensitive resources.

For example:

Public posts
→ accessible

Public pages
→ accessible

Public taxonomies
→ accessible where required

User information
→ restricted where appropriate

Administrative operations
→ authenticated

Private plugin data
→ authenticated

Block Editor
→ functional

This guide explains how to restrict the WordPress REST API safely, how REST authentication works, how to use rest_authentication_errors, when to restrict individual routes instead of the entire API, what can break when restrictions are too aggressive, and how to test your configuration properly.

What does restricting the WordPress REST API mean?

Restricting the REST API means controlling who can access particular REST resources.

It does not necessarily mean removing:

/wp-json/

or preventing WordPress from using REST internally.

A restriction might instead mean:

anonymous visitor
→ can read public posts

anonymous visitor
→ cannot enumerate users

authenticated editor
→ can access required user information

administrator
→ can perform permitted administrative operations

This is fundamentally an authorization problem.

Hiding, restricting and disabling REST are different things

These concepts are frequently mixed together.

Hiding the REST API

Hiding normally means removing automatic discovery information such as:

  • REST API links from the document head;
  • REST API HTTP Link headers;
  • REST information advertised through RSD.

The endpoint can still exist.

Restricting the REST API

Restricting means allowing or denying requests according to rules such as:

  • authentication status;
  • user capabilities;
  • REST route;
  • resource type;
  • request method.

Disabling the REST API

Disabling implies preventing REST requests from functioning broadly.

That is considerably more invasive and is rarely the best choice for a modern WordPress installation.

For a detailed comparison, see Hiding vs. Restricting the WordPress REST API.

Why the REST API should not normally be disabled completely

The REST API is not merely an optional interface for external developers.

Modern WordPress itself uses it.

The official WordPress REST API Handbook describes REST as the foundation of the Block Editor and an important interface for applications interacting with WordPress.

WordPress features and workflows that may depend on REST include:

  • the Block Editor;
  • the Site Editor;
  • Global Styles;
  • templates;
  • template parts;
  • media operations;
  • taxonomy interfaces;
  • author selection;
  • plugin administration screens;
  • JavaScript applications;
  • headless WordPress frontends;
  • mobile applications;
  • external integrations.

For a more complete dependency map, see What Depends on the WordPress REST API.

Understand the REST request lifecycle first

A simplified WordPress REST request looks like this:

HTTP request
↓
WordPress REST API
↓
authentication
↓
route matching
↓
permission checks
↓
endpoint callback
↓
response

Different security controls operate at different points in that process.

Authentication and authorization are not the same thing

This distinction is essential when restricting REST.

Authentication

Authentication answers:

Who is making this request?

Authorization

Authorization answers:

Is this user allowed to perform this operation?

An authenticated user should not automatically have access to every REST resource.

For example:

Subscriber
→ authenticated
→ cannot manage plugins

Editor
→ authenticated
→ can edit content
→ cannot necessarily administer the site

Administrator
→ authenticated
→ broader capabilities

WordPress capabilities remain an important part of REST authorization.

How WordPress authenticates REST requests

WordPress supports different authentication mechanisms depending on how the API is being used.

The official REST API Authentication documentation explains the primary mechanisms.

For requests originating inside WordPress, cookie authentication is commonly used.

External applications can use mechanisms such as Application Passwords.

Cookie authentication inside WordPress

When a logged-in user interacts with WordPress administration screens, their existing WordPress authentication cookies identify the user.

REST requests made from WordPress JavaScript interfaces commonly include a REST nonce.

The nonce uses the action:

wp_rest

and can be sent using:

X-WP-Nonce

This protects requests against certain cross-site request forgery scenarios.

However, the nonce does not grant permissions by itself.

The current user must still possess the required capabilities.

Application Passwords for external REST clients

WordPress includes Application Passwords for authenticating external applications.

The official Application Passwords documentation explains how they provide revocable credentials for programmatic access.

They are useful for:

  • external applications;
  • automation;
  • API integrations;
  • remote publishing systems.

An Application Password authenticates as a specific WordPress user.

That user is still subject to WordPress capabilities.

Public REST endpoints are intentional

A REST request does not automatically need authentication simply because it reaches:

/wp-json/

For example:

GET /wp-json/wp/v2/posts

normally exposes public posts.

This mirrors information already available through the frontend.

The important question is whether a particular resource actually needs to be public.

Why blanket REST restrictions are risky

Suppose you apply this policy:

not logged in
→ reject every REST request

That may reduce public REST exposure.

But it can also break:

  • public applications consuming WordPress content;
  • headless frontends;
  • frontend plugin features;
  • public search interfaces;
  • forms;
  • custom JavaScript applications;
  • third-party integrations.

Restricting the API should therefore begin with understanding what actually depends on it.

The rest_authentication_errors filter

WordPress provides the:

rest_authentication_errors

filter for REST authentication behavior.

The official rest_authentication_errors documentation describes how it can be used to return authentication errors before a REST request continues.

This makes it one of the primary mechanisms for applying broad authentication requirements.

Require authentication for the entire REST API

A simple implementation could look like this:

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

        if ( ! empty( $result ) ) {
            return $result;
        }

        if ( ! is_user_logged_in() ) {
            return new WP_Error(
                'rest_not_logged_in',
                'REST API access requires authentication.',
                array( 'status' => 401 )
            );
        }

        return $result;
    }
);

This effectively creates:

anonymous REST request
→ denied

authenticated REST request
→ continues

But this should not be copied blindly.

Why the existing result must be preserved

The filter may already contain:

  • null;
  • true;
  • a WP_Error generated by another authentication mechanism.

The official documentation specifically warns developers not to overwrite authentication errors produced by another handler.

That is why the example first checks:

if ( ! empty( $result ) ) {
    return $result;
}

Authentication filters are part of a chain. One plugin should not casually erase the result of another.

Why requiring authentication everywhere may be excessive

Imagine a site using WordPress as a headless CMS.

The frontend might request:

/wp-json/wp/v2/posts

for public content.

If every REST request suddenly requires WordPress authentication:

frontend
↓
GET /wp-json/wp/v2/posts
↓
401 Unauthorized
↓
website breaks

The restriction is technically effective but architecturally wrong.

A better strategy: restrict specific REST resources

For many sites, a more appropriate model is:

public content
→ public

sensitive resources
→ restricted

administrative operations
→ authenticated

private plugin data
→ authenticated

This follows the principle of least privilege.

REST API user enumeration is a good example

A common reason administrators want to restrict REST is the users endpoint:

/wp-json/wp/v2/users

Depending on the account and published content, public REST responses can expose information such as:

  • user IDs;
  • display names;
  • user slugs;
  • author URLs;
  • public profile information.

For the complete behavior, see WordPress REST API User Enumeration, Explained.

If user enumeration is the problem, restricting:

/wp/v2/users

is more targeted than disabling:

/wp-json/

entirely.

Route-level permissions are the preferred design for custom endpoints

When registering a custom REST route, WordPress expects developers to define a:

permission_callback

The official Routes and Endpoints documentation explains how permission callbacks determine whether a requester can access an endpoint.

For example:

register_rest_route(
    'my-plugin/v1',
    '/settings',
    array(
        'methods'  => 'GET',
        'callback' => 'my_plugin_get_settings',
        'permission_callback' => function () {
            return current_user_can( 'manage_options' );
        },
    )
);

Now the security rule exists directly on the endpoint.

Why permission_callback matters

Consider a custom route:

/wp-json/my-plugin/v1/private-data

If the callback exposes sensitive information but the route is intentionally public:

'permission_callback' => '__return_true'

the endpoint is accessible anonymously.

That may be correct for public data.

It is dangerous for private data.

REST security should therefore be designed at the resource level whenever possible.

Use WordPress capabilities instead of role names

A permission callback should normally ask:

Can this user perform the required action?

rather than:

Does this user have a particular role name?

For example:

current_user_can( 'manage_options' )

is usually preferable to manually checking:

administrator

because WordPress authorization is capability-based.

GET requests are not automatically safe

Developers sometimes assume:

GET
→ harmless

POST
→ dangerous

That is too simplistic.

A GET endpoint can expose:

  • personal information;
  • private configuration;
  • customer records;
  • internal IDs;
  • system metadata;
  • security-sensitive information.

Read access still needs authorization when the underlying data is private.

POST requests are not automatically administrative

Likewise, some public APIs legitimately accept POST requests.

HTTP method alone should not determine authorization.

The permission requirement should follow the operation being performed.

Restricting access based on authentication alone

A rule such as:

is_user_logged_in()

answers only:

Does this request represent an authenticated WordPress user?

It does not answer:

Should this particular user access this resource?

For sensitive operations, use capability checks.

For example:

current_user_can( 'edit_posts' )

or:

current_user_can( 'manage_options' )

depending on the operation.

Authentication plus authorization

A robust REST security model looks like:

Request
↓
authenticate user
↓
identify requested route
↓
evaluate permission callback
↓
check capabilities
↓
allow or deny operation

Each layer solves a different problem.

Do not use rest_enabled to disable REST

Older tutorials may recommend the:

rest_enabled

filter.

That advice is outdated.

The official rest_enabled documentation marks the filter as deprecated and explains that the REST API can no longer be completely disabled using that mechanism.

WordPress recommends using:

rest_authentication_errors

when authentication restrictions are required.

Do not confuse REST discovery with REST access

WordPress can advertise its REST API through several mechanisms.

For example, the document head can contain:

<link rel="https://api.w.org/" href="https://example.com/wp-json/" />

WordPress can also advertise REST through HTTP Link headers and RSD.

The official REST API Discovery documentation describes these mechanisms.

Removing them changes discovery.

It does not restrict requests.

The REST API URL remains predictable

Even without discovery metadata, a client can request:

https://example.com/wp-json/

directly.

WordPress also supports REST routing through forms such as:

?rest_route=/

depending on permalink configuration.

Therefore:

remove REST discovery links
≠
restrict REST API

This distinction is covered in detail in How WordPress Advertises Its REST API.

Restricting the REST API by IP address

Some private applications may benefit from network-level restrictions.

For example:

REST integration
→ known application server
→ fixed IP address
→ allowlisted

A firewall or reverse proxy could then limit requests from other networks.

This can be useful for highly controlled integrations.

But IP-based access is not universally appropriate.

It can fail when:

  • clients use dynamic IP addresses;
  • mobile users access the API;
  • CDNs or proxies change request origins;
  • multiple external services need access;
  • WordPress frontend functionality uses REST publicly.

Restricting REST at the web server level

REST access can also be controlled before WordPress executes.

Possible layers include:

  • Nginx;
  • Apache;
  • reverse proxies;
  • CDNs;
  • web application firewalls.

This can reduce requests reaching PHP.

However, the infrastructure layer does not naturally understand WordPress capabilities.

A web server can easily understand:

URL
IP address
HTTP method
headers

WordPress understands:

current user
capabilities
resource ownership
plugin permissions
content status

Application-level authorization is therefore usually more precise.

Use rate limiting for abuse, not authorization

Rate limiting can help with:

  • automated scraping;
  • enumeration;
  • high-volume API abuse;
  • denial-of-service pressure;
  • credential-related API attacks.

For example:

1000 REST requests / minute
→ suspicious
→ throttle

But rate limiting does not answer whether the requester is allowed to access the data.

A single successful request can still expose sensitive information.

Use rate limiting alongside authorization, not instead of it.

Restricting REST does not replace login security

Blocking public user endpoints can reduce reconnaissance.

It does not protect a weak password.

Likewise:

REST restricted
+
password = password123

is not a secure WordPress installation.

For authentication hardening, see A WordPress Login Hardening Checklist and WordPress Brute-Force Attacks, Explained.

Restricting REST does not disable XML-RPC

The REST API and XML-RPC are separate interfaces.

You can have:

REST API restricted
+
XML-RPC available

or:

REST API available
+
XML-RPC disabled

Restricting one does not automatically restrict the other.

See XML-RPC in WordPress, Explained for the architectural difference.

REST restrictions can affect the Block Editor

The Block Editor is one of the most important things to test after changing REST access.

The editor can use REST for:

  • loading posts;
  • saving posts;
  • taxonomies;
  • media;
  • users;
  • settings;
  • previews;
  • editor entities.

If REST authorization is incorrect, symptoms can include:

  • failed saves;
  • publishing errors;
  • missing sidebar controls;
  • author selector failures;
  • taxonomy panels not loading;
  • media problems;
  • generic editor errors.

REST restrictions can affect the Site Editor

Block themes depend heavily on API-driven interfaces.

Test:

  • templates;
  • template parts;
  • navigation;
  • styles;
  • patterns;
  • site settings.

A REST restriction that appears harmless on the frontend can still damage administrative editing workflows.

REST restrictions can break plugins

Modern WordPress plugins frequently register custom REST namespaces.

For example:

/wp-json/plugin-name/v1/

A plugin administration interface may be almost entirely JavaScript-driven and communicate with PHP through REST.

A global restriction can therefore produce strange failures such as:

plugin page loads
↓
JavaScript starts
↓
REST request rejected
↓
interface appears empty or broken

REST restrictions can break frontend features

REST is not limited to wp-admin.

Frontend functionality may use REST for:

  • search;
  • filters;
  • forms;
  • dynamic content;
  • infinite scrolling;
  • user interfaces;
  • interactive blocks;
  • custom applications.

Always test the public site after introducing restrictions.

REST restrictions and headless WordPress

For a headless WordPress installation, REST may be one of the primary content delivery interfaces.

A frontend application might rely on:

GET /wp-json/wp/v2/posts
GET /wp-json/wp/v2/pages
GET /wp-json/wp/v2/categories
GET /wp-json/wp/v2/media

Requiring WordPress authentication for all of those routes could make a public frontend impossible to render without introducing additional authentication architecture.

Headless installations therefore require particularly careful route-level policy.

Public content does not automatically need protection

If a WordPress post is publicly available at:

https://example.com/article/

exposing the same public post through:

/wp-json/wp/v2/posts/123

does not inherently reveal private content.

The fact that REST exposes structured JSON should not automatically be classified as a vulnerability.

The real question is:

Does the REST response expose information that should not be public?

Private content should have appropriate permission checks

REST endpoints dealing with:

  • draft posts;
  • private posts;
  • site configuration;
  • customer information;
  • user account details;
  • orders;
  • private plugin data;

must enforce suitable authentication and authorization.

For custom endpoints, that responsibility largely belongs to the code registering the route.

Do not trust client-side restrictions

Suppose JavaScript hides an administrative button unless the user is an administrator.

That does not secure the REST endpoint behind the button.

An attacker can bypass the interface and request the endpoint directly.

Security must exist server-side:

REST request
↓
server permission check
↓
current_user_can()
↓
allow / deny

Do not rely on a secret endpoint URL

A route such as:

/wp-json/company/v1/secret-settings-92841

is not secure merely because its URL is obscure.

Routes can be discovered through:

  • REST index responses;
  • JavaScript source;
  • browser Network requests;
  • plugin code;
  • logs;
  • documentation;
  • automated enumeration.

Private routes need real permission checks.

Do not use nonces as authorization

A WordPress REST nonce helps verify the request context for cookie-authenticated REST requests.

It does not mean:

nonce valid
→ administrator

A valid nonce can belong to a user with limited capabilities.

After authentication, authorization must still evaluate what the user can do.

REST API restrictions and CORS

Cross-Origin Resource Sharing controls which browser origins can read certain cross-origin responses.

CORS is not a replacement for REST authentication or authorization.

An attacker does not need to use a browser from a prohibited origin to make an HTTP request.

Therefore:

CORS restriction
≠
API access control

Use CORS for browser-origin policy, not as the primary protection for sensitive REST data.

REST API restrictions and robots.txt

Adding:

Disallow: /wp-json/

to robots.txt does not restrict the REST API.

Robots directives are instructions for cooperative crawlers.

They are not access-control rules.

A client can still request:

/wp-json/

directly.

REST API restrictions and security through obscurity

Removing REST discovery metadata can reduce passive exposure.

Changing visible clues can make casual reconnaissance less convenient.

But a secure configuration should assume an attacker already knows:

WordPress is installed
/wp-json/ exists
/wp/v2/ exists

Authorization should still protect sensitive resources under that assumption.

Restricting custom plugin endpoints correctly

Suppose a plugin exposes internal settings.

A weak implementation might be:

register_rest_route(
    'company/v1',
    '/settings',
    array(
        'methods'  => 'GET',
        'callback' => 'company_get_settings',
        'permission_callback' => '__return_true',
    )
);

That explicitly makes the route public.

A more appropriate implementation could be:

register_rest_route(
    'company/v1',
    '/settings',
    array(
        'methods'  => 'GET',
        'callback' => 'company_get_settings',
        'permission_callback' => function () {
            return current_user_can( 'manage_options' );
        },
    )
);

Now WordPress checks authorization before executing the endpoint callback.

Object-level authorization matters too

Sometimes a capability alone is not enough.

Suppose a route modifies a specific post:

/company/v1/posts/123

The correct permission check might involve:

current_user_can( 'edit_post', 123 )

rather than merely:

current_user_can( 'edit_posts' )

This allows WordPress’s meta capability system to evaluate ownership, post type and other relevant permissions.

Use the narrowest appropriate permission

A common mistake is protecting every custom REST endpoint with:

manage_options

That certainly restricts access, but it may be unnecessarily broad.

If the operation only requires editing a post, an editing capability may be more appropriate.

The security principle is:

grant exactly the permission required
not more
not less

Returning proper REST errors

When access is denied, return an appropriate WP_Error.

For example:

return new WP_Error(
    'rest_forbidden',
    'You are not allowed to access this resource.',
    array( 'status' => 403 )
);

A useful distinction is:

401 Unauthorized
→ authentication is required or missing

403 Forbidden
→ identity is known but permission is insufficient

Exact behavior can vary with the authentication flow, but keeping this conceptual distinction makes APIs easier to understand and debug.

Restricting the REST API without hiding it

A perfectly reasonable configuration is:

/wp-json/
→ visible

REST namespaces
→ visible

public resources
→ accessible

sensitive resources
→ authentication required

Visibility is not inherently a vulnerability.

Correct permissions matter more than pretending the interface does not exist.

Hiding REST discovery without restricting requests

The inverse configuration is also possible:

REST discovery links
→ removed

/wp-json/
→ still publicly accessible

This may be useful as cleanup or reconnaissance reduction.

But it is not access control.

TheOneWP’s Disable REST API Links feature can remove REST discovery output when that metadata is unnecessary.

Use that independently from actual REST authorization policy.

RSD can also advertise the REST API

WordPress REST discovery is not limited to the document head.

The RSD document can advertise:

WP-API

alongside other discovery information.

The official rest_output_rsd() documentation describes how WordPress adds REST API information to RSD output.

For the broader discovery architecture, see RSD and WordPress Discovery Endpoints, Explained.

Before restricting REST, inventory your routes

Start by requesting:

https://example.com/wp-json/

The REST index provides information about registered namespaces and routes.

Typical namespaces might include:

wp/v2
oembed/1.0
plugin-name/v1
company/v1

Do not assume only WordPress core is using REST.

Identify public REST consumers

Before changing access, determine whether REST is consumed by:

  • the frontend;
  • mobile applications;
  • headless applications;
  • external automation;
  • CRM integrations;
  • publishing systems;
  • analytics tools;
  • custom applications.

A REST restriction made without this inventory can create failures far away from wp-admin.

Identify authenticated REST consumers

Also document integrations using:

  • WordPress cookies;
  • Application Passwords;
  • custom authentication;
  • OAuth-style plugins;
  • other API authentication layers.

Make sure your restriction preserves those authentication mechanisms.

Test REST access as multiple user roles

Do not test only as administrator.

Test as:

  • anonymous visitor;
  • subscriber;
  • author;
  • editor;
  • administrator;
  • custom roles used by the site.

The expected result may be different for each role.

Build an access matrix

For a serious WordPress installation, create a simple REST access matrix.

Resource Anonymous Authenticated user Privileged user
Public posts Allow Allow Allow
Public pages Allow Allow Allow
Public categories Allow Allow Allow
User directory Review / restrict As required Allow where authorized
Draft content Deny Capability dependent Capability dependent
Private settings Deny Deny unless authorized Allow where authorized
Plugin private data Deny Capability dependent Capability dependent

This is far more useful than a generic:

REST on / REST off

decision.

How to audit REST restrictions step by step

1. Inspect the REST root

Request:

/wp-json/

Record the namespaces and important routes.

2. Test anonymous public content

Check routes such as:

/wp-json/wp/v2/posts
/wp-json/wp/v2/pages
/wp-json/wp/v2/categories

Decide whether public access is expected.

3. Test the users endpoint

Request:

/wp-json/wp/v2/users

Review what anonymous visitors can retrieve.

Use WordPress REST API User Enumeration, Explained to evaluate the result correctly.

4. Identify custom namespaces

Look for:

plugin-name/v1
theme-name/v1
company/v1

and inspect their routes.

5. Test sensitive GET endpoints anonymously

Remember that read-only requests can still leak private information.

6. Test write operations

Verify that anonymous and low-privilege users cannot:

  • create protected content;
  • edit protected content;
  • delete resources;
  • change settings;
  • modify users;
  • perform administrative actions.

7. Test authenticated low-privilege users

A Subscriber should not gain access merely because they are authenticated.

8. Test capabilities

Verify that route permissions correspond to the actual operation.

9. Test the Block Editor

Create and edit content.

Verify:

  • loading;
  • saving;
  • publishing;
  • media;
  • taxonomies;
  • author selection;
  • previews.

10. Test the Site Editor

If using a block theme, test templates, styles and navigation.

11. Test plugin interfaces

Open major plugin administration pages and check for failed requests.

12. Test frontend interactions

Test:

  • search;
  • filters;
  • forms;
  • dynamic content;
  • infinite scrolling;
  • interactive components.

13. Inspect browser Network requests

Open developer tools and filter requests for:

wp-json

Look for:

401
403
404
500

responses introduced by your restriction.

14. Test external integrations

Check every application that consumes WordPress data remotely.

15. Test Application Passwords

If integrations use them, verify that authenticated requests still work.

16. Review server and security logs

Look for repeated denied requests and unexpected REST consumers.

Common REST restriction mistakes

Disabling the entire API because /wp-json/ is public

Public REST availability is normal WordPress behavior.

Assuming every public REST endpoint is a vulnerability

Public content is often intentionally public through REST.

Using rest_enabled

The old mechanism is deprecated.

Removing REST discovery and calling the API disabled

Discovery and access are separate.

Blocking /wp-json/ but forgetting ?rest_route=/

REST routing is not defined solely by one visible URL prefix.

Requiring authentication everywhere without testing

This can break legitimate public consumers.

Checking only is_user_logged_in()

Authentication alone does not prove authorization.

Checking role names instead of capabilities

WordPress authorization is capability-driven.

Using __return_true for private custom endpoints

This explicitly makes the endpoint publicly accessible.

Using a nonce as the only permission check

A nonce is not authorization.

Using CORS as API security

CORS controls browser cross-origin behavior, not general HTTP access.

Using robots.txt as API security

Robots directives are not access controls.

Relying on obscure REST URLs

Private endpoints require real permission checks.

Blocking REST at the firewall without understanding WordPress

Infrastructure rules cannot naturally evaluate WordPress capabilities.

Ignoring custom plugin namespaces

Core wp/v2 is only part of the REST surface.

Testing only as administrator

Administrators legitimately have broader REST access.

Ignoring frontend REST requests

REST can be used outside wp-admin.

Ignoring Block Editor dependencies

Broad restrictions can break core editing workflows.

Ignoring Application Passwords

External authenticated clients may rely on them.

Using rate limiting instead of authorization

Throttling and permissions solve different problems.

A safer WordPress REST API strategy

For most sites, a sensible model is:

1. Keep the REST API enabled.

2. Inventory registered routes.

3. Identify genuinely public resources.

4. Identify sensitive resources.

5. Restrict sensitive routes.

6. Require authentication where appropriate.

7. Apply capability checks.

8. Preserve required editor functionality.

9. Preserve required plugin functionality.

10. Rate limit abusive traffic separately.

11. Remove unnecessary discovery metadata only if desired.

12. Test everything.

WordPress REST API restriction checklist

  • Understand the difference between hiding, restricting and disabling REST.
  • Do not disable REST merely because /wp-json/ is publicly reachable.
  • Understand what depends on the REST API.
  • Inventory the REST API root.
  • Record all registered namespaces.
  • Identify WordPress core routes.
  • Identify plugin routes.
  • Identify theme and custom routes.
  • Identify public REST consumers.
  • Identify authenticated REST consumers.
  • Review headless frontend dependencies.
  • Review mobile application dependencies.
  • Review external integrations.
  • Review Application Password usage.
  • Understand cookie authentication.
  • Understand the wp_rest nonce.
  • Do not treat a nonce as authorization.
  • Understand WordPress capabilities.
  • Use capabilities instead of hard-coded role names.
  • Use object-specific capabilities where appropriate.
  • Use permission_callback on custom routes.
  • Never expose private endpoints using __return_true.
  • Review GET endpoints for sensitive information.
  • Review POST endpoints for unauthorized operations.
  • Review PUT/PATCH endpoints where registered.
  • Review DELETE endpoints.
  • Test public post endpoints.
  • Test public page endpoints.
  • Test taxonomy endpoints.
  • Test the users endpoint.
  • Audit REST user enumeration.
  • Restrict user information where unnecessary.
  • Do not disable all REST merely to prevent user enumeration.
  • Understand rest_authentication_errors.
  • Preserve authentication errors generated by other handlers.
  • Do not use the deprecated rest_enabled approach.
  • Return appropriate REST errors.
  • Distinguish authentication from authorization.
  • Do not rely on REST discovery removal for security.
  • Remember the ?rest_route=/ routing form.
  • Understand that RSD can advertise REST.
  • Do not use robots.txt as access control.
  • Do not use CORS as the primary REST security mechanism.
  • Do not rely on secret endpoint URLs.
  • Review server-level REST restrictions.
  • Review CDN rules.
  • Review WAF rules.
  • Use rate limiting separately from authorization.
  • Test anonymous REST requests.
  • Test Subscriber access.
  • Test Author access.
  • Test Editor access.
  • Test Administrator access.
  • Test custom roles.
  • Test the Block Editor.
  • Test post saving.
  • Test publishing.
  • Test author selection.
  • Test media operations.
  • Test taxonomies.
  • Test the Site Editor.
  • Test templates and template parts.
  • Test Global Styles.
  • Test major plugin interfaces.
  • Test frontend JavaScript functionality.
  • Test forms.
  • Test search and filtering.
  • Test headless applications.
  • Test external REST integrations.
  • Inspect browser Network requests for REST failures.
  • Review server logs after restrictions are deployed.
  • Reaudit REST routes after installing major plugins.
  • Reaudit REST permissions after custom development.
  • Keep WordPress and plugins updated.

Related guides

Final recommendation

Do not treat the WordPress REST API as a single switch that must be either completely public or completely disabled.

Modern WordPress is built around a much more granular security model.

The better approach is:

public resource
→ public REST access where useful

private resource
→ authentication required

privileged operation
→ capability check required

unnecessary exposure
→ restrict

abusive traffic
→ rate limit

discovery metadata
→ optionally remove

REST itself
→ keep functional

Start by identifying what your site actually exposes through REST and which applications depend on those routes.

Then restrict the smallest possible surface.

If user enumeration is the concern, address user-related routes and the other places WordPress exposes author information instead of disabling every REST endpoint.

If a custom plugin exposes sensitive data, fix its permission_callback rather than trying to hide the entire API.

If an external application needs access, authenticate it properly and authorize the WordPress user behind those credentials according to the capabilities required by the operation.

Most importantly, test restrictions as anonymous visitors and as multiple WordPress roles.

A REST policy that appears secure while logged out can still expose excessive information to low-privilege accounts. A policy that blocks everything can be equally problematic if it breaks the Block Editor, Site Editor, plugins or external applications.

The objective is therefore not:

make /wp-json/ disappear

It is:

make every REST resource accessible only to the users and applications that actually need it

That produces a considerably stronger WordPress security model without fighting against the architecture modern WordPress itself depends on.

Simplify your WordPress stack

A modular WordPress toolkit. 104 focused tools.

Ultimately, you can build cleaner workflows, maintain fewer plugins and enable only the features each website actually needs.