{"id":163734,"date":"2022-10-20T00:49:55","date_gmt":"2022-10-20T00:49:55","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/rest-api-guard\/"},"modified":"2026-10-13T01:23:41","modified_gmt":"2026-10-13T01:23:41","slug":"rest-api-guard","status":"publish","type":"plugin","link":"https:\/\/af.wordpress.org\/plugins\/rest-api-guard\/","author":5853094,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.5.0","stable_tag":"1.5.0","tested":"7.1.3","requires":"6.5","requires_php":"8.3","requires_plugins":null,"header_name":"REST API Guard","header_author":"Sean Fisher","header_description":"Restrict and control access to the REST API","assets_banners_color":"","last_updated":"2026-10-13 01:23:41","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/alleyinteractive\/wp-rest-api-guard","header_author_uri":"https:\/\/alley.com\/","rating":5,"author_block_rating":0,"active_installs":100,"downloads":4549,"num_ratings":2,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"sean212","date":"2022-10-20 00:56:42","revision":2801545},"1.0.1":{"tag":"1.0.1","author":"sean212","date":"2022-10-26 15:34:21","revision":2805089},"1.0.2":{"tag":"1.0.2","author":"sean212","date":"2022-11-03 19:26:19","revision":2811404},"1.0.3":{"tag":"1.0.3","author":"sean212","date":"2023-08-28 20:31:01","revision":2959576},"1.1.2":{"tag":"1.1.2","author":"sean212","date":"2024-01-15 15:49:00","revision":3021965},"1.2.0":{"tag":"1.2.0","author":"sean212","date":"2024-02-23 14:39:13","revision":3040295},"1.2.1":{"tag":"1.2.1","author":"sean212","date":"2024-02-28 19:25:17","revision":3042771},"1.3.0":{"tag":"1.3.0","author":"sean212","date":"2024-02-28 19:26:48","revision":3042772},"1.3.1":{"tag":"1.3.1","author":"sean212","date":"2024-03-20 15:15:21","revision":3055438},"1.3.2":{"tag":"1.3.2","author":"sean212","date":"2024-03-20 15:21:17","revision":3055440},"1.4.1":{"tag":"1.4.1","author":"sean212","date":"2025-09-09 20:00:57","revision":3358865},"1.4.2":{"tag":"1.4.2","author":"sean212","date":"2026-09-19 00:56:34","revision":3702886},"1.5.0":{"tag":"1.5.0","author":"sean212","date":"2026-10-13 01:23:41","revision":3742715}},"upgrade_notice":[],"ratings":{"1":0,"2":0,"3":0,"4":0,"5":2},"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3742732,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3742732,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0","1.0.1","1.0.2","1.0.3","1.1.2","1.2.0","1.2.1","1.3.0","1.3.1","1.3.2","1.4.1","1.4.2","1.5.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3742715,"resolution":"1","location":"assets","locale":"","width":1280,"height":1570},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3742715,"resolution":"2","location":"assets","locale":"","width":1280,"height":900}},"screenshots":{"1":"The settings page.","2":"The Tokens tab for generating, listing, and revoking JSON Web Tokens."}},"plugin_section":[],"plugin_tags":[710,38851,396,23853,600],"plugin_category":[38,54],"plugin_contributors":[78228],"plugin_business_model":[],"class_list":["post-163734","plugin","type-plugin","status-publish","hentry","plugin_tags-authentication","plugin_tags-jwt","plugin_tags-privacy","plugin_tags-rest-api","plugin_tags-security","plugin_category-authentication","plugin_category-security-and-spam-protection","plugin_contributors-sean212","plugin_committers-sean212"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/rest-api-guard\/assets\/icon-128x128.png?rev=3742732","icon_2x":"https:\/\/ps.w.org\/rest-api-guard\/assets\/icon-256x256.png?rev=3742732","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/rest-api-guard\/assets\/screenshot-1.png?rev=3742715","caption":"The settings page."},{"src":"https:\/\/ps.w.org\/rest-api-guard\/assets\/screenshot-2.png?rev=3742715","caption":"The Tokens tab for generating, listing, and revoking JSON Web Tokens."}],"raw_content":"<!--section=description-->\n<p>The WordPress REST API is public by default and shares a good deal of information about your site with anyone who asks. REST API Guard makes it easy to decide who can see what.<\/p>\n\n<p>Out of the box, the plugin:<\/p>\n\n<ul>\n<li>Blocks anonymous access to the users endpoint (<code>\/wp\/v2\/users<\/code>) so usernames aren't exposed.<\/li>\n<li>Blocks anonymous access to the REST API index (<code>\/<\/code>) and namespace endpoints (<code>\/wp\/v2<\/code>) so visitors can't list your plugins and post types.<\/li>\n<\/ul>\n\n<p>It can also:<\/p>\n\n<ul>\n<li>Block all anonymous access to the REST API.<\/li>\n<li>Allow anonymous access only to specific routes (allowlist), or block specific routes (denylist).<\/li>\n<li>Require anonymous requests to include a JSON Web Token (JWT).<\/li>\n<li>Let users authenticate with a JWT tied to their account.<\/li>\n<li>Generate, list, and revoke tokens from the settings page or WP-CLI.<\/li>\n<\/ul>\n\n<p>Every option is available on the settings page (Settings \u2192 REST API Guard) and as a filter for configuring the plugin in code. A setting controlled by a filter is shown as read-only on the settings page.<\/p>\n\n<h4>Restrict access to user information<\/h4>\n\n<p>Anonymous access to <code>\/wp\/v2\/users<\/code> is blocked by default. To allow it:<\/p>\n\n<pre><code>add_filter( 'rest_api_guard_allow_user_access', '__return_true' );\n<\/code><\/pre>\n\n<h4>Restrict access to the index and namespace endpoints<\/h4>\n\n<p>Anonymous access to the index (<code>\/<\/code>) and namespace (<code>\/wp\/v2<\/code>) endpoints is blocked by default. To allow it:<\/p>\n\n<pre><code>add_filter( 'rest_api_guard_allow_index_access', '__return_true' );\nadd_filter( 'rest_api_guard_allow_namespace_access', '__return_true' );\n<\/code><\/pre>\n\n<h4>Block all anonymous access<\/h4>\n\n<pre><code>add_filter( 'rest_api_guard_prevent_anonymous_access', '__return_true' );\n<\/code><\/pre>\n\n<h4>Allow anonymous access to specific routes (allowlist)<\/h4>\n\n<p>When an allowlist is set, anonymous requests to any route not on the list are denied. The allowlist takes priority over the denylist. Use <code>*<\/code> as a wildcard.<\/p>\n\n<pre><code>add_filter(\n    'rest_api_guard_anonymous_requests_allowlist',\n    fn () =&gt; [\n        '\/wp\/v2\/posts*',\n        '\/custom-namespace\/v1\/public\/*',\n    ]\n);\n<\/code><\/pre>\n\n<h4>Deny anonymous access to specific routes (denylist)<\/h4>\n\n<p>Anonymous requests to routes on the denylist are denied. All other routes are allowed. Use <code>*<\/code> as a wildcard.<\/p>\n\n<pre><code>add_filter(\n    'rest_api_guard_anonymous_requests_denylist',\n    fn () =&gt; [\n        '\/wp\/v2\/comments*',\n        '\/custom-namespace\/v1\/private\/*',\n    ]\n);\n<\/code><\/pre>\n\n<h4>Require a JSON Web Token (JWT) for anonymous requests<\/h4>\n\n<p>Anonymous requests can be required to send a token in an <code>Authorization: Bearer &lt;token&gt;<\/code> header:<\/p>\n\n<pre><code>add_filter( 'rest_api_guard_authentication_jwt', '__return_true' );\n<\/code><\/pre>\n\n<p>Tokens are expected to have an audience of <code>wordpress-rest-api<\/code> and an issuer of the site URL. Both can be changed:<\/p>\n\n<pre><code>add_filter( 'rest_api_guard_jwt_audience', fn () =&gt; 'custom-audience' );\nadd_filter( 'rest_api_guard_jwt_issuer', fn () =&gt; 'https:\/\/example.com' );\n<\/code><\/pre>\n\n<p>Tokens are signed with a secret generated automatically and stored in the <code>rest_api_guard_jwt_secret<\/code> option. It can also be set in code:<\/p>\n\n<pre><code>add_filter( 'rest_api_guard_jwt_secret', fn () =&gt; 'my-custom-secret' );\n<\/code><\/pre>\n\n<h4>Authenticate users with a JWT<\/h4>\n\n<p>Tokens can also be tied to a user. A request with a user token is treated as that user, with the same permissions they have:<\/p>\n\n<pre><code>add_filter( 'rest_api_guard_user_authentication_jwt', '__return_true' );\n<\/code><\/pre>\n\n<h4>Generate, list, and revoke tokens<\/h4>\n\n<p>Once JWT authentication is enabled, tokens can be generated from the Tokens tab of the settings page. Give each one a name so you can tell them apart later, and optionally tie it to a user or set an expiration. The token is shown once after it's generated, so copy it somewhere safe.<\/p>\n\n<p>The same tab lists every token the plugin has issued, and any of them can be revoked. A revoked token stops working right away.<\/p>\n\n<p>Tokens can also be managed with WP-CLI:<\/p>\n\n<pre><code>wp rest-api-guard generate-jwt [--name=&lt;name&gt;] [--user=&lt;user-id&gt;] [--expiration=&lt;seconds&gt;]\nwp rest-api-guard list-jwts\nwp rest-api-guard revoke-jwt &lt;id&gt;\n<\/code><\/pre>\n\n<p>Or generated in code:<\/p>\n\n<pre><code>$token = \\Alley\\WP\\REST_API_Guard\\generate_jwt(\n    expiration: HOUR_IN_SECONDS, \/\/ Optional. Seconds until the token expires.\n    user: 1,                     \/\/ Optional. A user ID or WP_User.\n    name: 'Mobile App',          \/\/ Optional. A name to identify the token by.\n);\n<\/code><\/pre>\n\n<p>Tokens issued before version 1.5.0 aren't tracked, so they can't be listed or revoked one at a time. They're still accepted by default. To reject them:<\/p>\n\n<pre><code>add_filter( 'rest_api_guard_allow_untracked_jwt', '__return_false' );\n<\/code><\/pre>\n\n<p>Changing the <code>rest_api_guard_jwt_secret<\/code> option invalidates every token issued so far, tracked or not.<\/p>\n\n<h4>Caching<\/h4>\n\n<p>Responses to REST API requests that include an <code>Authorization<\/code> header are sent with no-cache headers so a page cache or CDN doesn't store them.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install the plugin from the Plugins \u2192 Add New screen, or upload it to the <code>\/wp-content\/plugins\/<\/code> directory.<\/li>\n<li>Activate the plugin from the Plugins screen.<\/li>\n<li>Configure it from Settings \u2192 REST API Guard.<\/li>\n<\/ol>\n\n<p>The plugin can also be installed with Composer:<\/p>\n\n<pre><code>composer require alleyinteractive\/wp-rest-api-guard\n<\/code><\/pre>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20affect%20logged-in%20users%3F\"><h3>Does this affect logged-in users?<\/h3><\/dt>\n<dd><p>No. The restrictions only apply to anonymous requests. Logged-in users have the same REST API access WordPress normally gives them.<\/p><\/dd>\n<dt id=\"why%20does%20the%20block%20editor%20still%20work%3F\"><h3>Why does the block editor still work?<\/h3><\/dt>\n<dd><p>The block editor makes REST API requests as the logged-in user, so it isn't affected by the anonymous access rules.<\/p><\/dd>\n<dt id=\"can%20i%20hide%20the%20settings%20page%3F\"><h3>Can I hide the settings page?<\/h3><\/dt>\n<dd><p>Yes. Configure the plugin in code and disable the settings page:<\/p>\n\n<pre><code>add_filter( 'rest_api_guard_disable_admin_settings', '__return_true' );\n<\/code><\/pre><\/dd>\n<dt id=\"are%20options%20requests%20checked%3F\"><h3>Are OPTIONS requests checked?<\/h3><\/dt>\n<dd><p>Not by default, since browsers send them as CORS preflight requests without credentials. To check them too:<\/p>\n\n<pre><code>add_filter( 'rest_api_guard_check_options_requests', '__return_true' );\n<\/code><\/pre><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.5.0<\/h4>\n\n<ul>\n<li>Track issued JWTs and allow them to be revoked from the settings page or WP-CLI.<\/li>\n<li>Add a Tokens tab to the settings page to generate, list, and revoke JWTs when JWT authentication is enabled.<\/li>\n<li>Add the <code>rest_api_guard_allow_untracked_jwt<\/code> filter to reject JWTs issued before tracking.<\/li>\n<li>Send no-cache headers on REST API requests that include an <code>Authorization<\/code> header.<\/li>\n<\/ul>\n\n<h4>1.4.2<\/h4>\n\n<ul>\n<li>Prevent mixed-case REST API routes from bypassing anonymous access restrictions.<\/li>\n<li>Add support for WordPress 7.1.<\/li>\n<li>Require PHP 8.3+.<\/li>\n<li>Update <code>firebase\/php-jwt<\/code> to version 7.<\/li>\n<\/ul>\n\n<h4>1.4.1<\/h4>\n\n<ul>\n<li>No changes, release to trigger deployment to WordPress.org.<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>Add support for WordPress 6.8.<\/li>\n<li>Require PHP 8.1+.<\/li>\n<\/ul>\n\n<h4>1.3.1<\/h4>\n\n<ul>\n<li>Ignore JWT authentication for the REST API if the user is already authenticated.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>Allow claims to be added to a generated JWT via filter.<\/li>\n<li>Don't check <code>OPTIONS<\/code> requests by default.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Add support for authenticated users interacting with the REST API.<\/li>\n<li>Allow settings to be completely disabled via code.<\/li>\n<li>Increase the default length of the JWT secret to 32 characters.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Require PHP 8.0.<\/li>\n<li>Add support for anonymous authentication with a JSON Web Token (JWT).<\/li>\n<\/ul>\n\n<p>The full changelog is available on <a href=\"https:\/\/github.com\/alleyinteractive\/wp-rest-api-guard\/blob\/develop\/CHANGELOG.md\">GitHub<\/a>.<\/p>","raw_excerpt":"Restrict and control anonymous access to the WordPress REST API, with optional JSON Web Token (JWT) authentication.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/af.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/163734","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/af.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/af.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/af.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=163734"}],"author":[{"embeddable":true,"href":"https:\/\/af.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/sean212"}],"wp:attachment":[{"href":"https:\/\/af.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=163734"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/af.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=163734"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/af.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=163734"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/af.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=163734"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/af.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=163734"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/af.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=163734"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}