WordPress REST API: How to Secure Custom Endpoints

Lock custom REST routes with capability checks, correct auth, and strict input validation.

Secure a custom endpoint by registering it with permission checks, authentication, and input validation. A custom endpoint is a URL you add to the WordPress REST API to send or receive your own data. Register each route with `register_rest_route()` on the `rest_api_init` hook and include a `permission_callback` that runs before the main callback. According to WordPress Developer Resources, an omitted callback triggers a `_doing_it_wrong` notice since WordPress 5.5, as explained in the custom endpoints guide.

Table of Contents

Require permission on every route

Treat `permission_callback` as the lock on the door. It decides whether the current request may proceed. Never leave a data-changing endpoint open with `__return_true`.

That setting allows anyone to call it. Return an error for unauthorized users instead. For public data, still set an explicit callback. You can allow open reads there while keeping writes restricted.

Check capability, not just login

Ask whether the user may do this action, not only whether they are logged in. Use `current_user_can()` with the capability that matches the task.

For example, check `edit_posts` for general content changes. Check `edit_post` with an ID for one specific post. According to WordPress Developer Resources, capability checks are the secure pattern for data-changing endpoints, as described in the custom endpoints guide.

  • Public list or read: allow with limits, or check `read` where appropriate.
  • Create or update content: require `edit_posts` or a matching capability.
  • Delete or manage settings: require a higher capability tied to that action.

How do same-site browser requests stay safe?

Logged-in browser clients use cookie authentication plus a `wp_rest` nonce. The nonce is sent as the `X-WP-Nonce` header or `_wpnonce` parameter to block cross-site request forgery. Without a valid nonce, WordPress treats the request as unauthenticated. The user becomes 0, so capability checks fail.

According to WordPress Developer Resources, this pairing is required for same-site cookie requests, as detailed in the REST API authentication handbook. You do not manually verify that nonce in the endpoint. WordPress validates it automatically in `rest_cookie_check_errors()` before your code runs. Focus your code on permissions and input handling.

How should external apps connect?

Cookie-plus-nonce authentication works only in the same logged-in WordPress context. Headless sites, mobile apps, and outside scripts need another method. Use Application Passwords for those clients.

They are per-application revocable credentials used with HTTP Basic authentication. According to WordPress Developer Resources, they have been built into core since WordPress 5.6 and are managed under the user profile or REST API, as explained in the Application Passwords reference. Those credentials carry the user's full capabilities. Create a dedicated user with least privilege, require HTTPS, and restrict methods and namespaces to what the app needs.

Validate and clean every input

Declare expected inputs in the route `args` schema. Include `required`, `default`, `validate_callback`, and `sanitize_callback` where they fit. Validation rejects bad values before your callback runs.

Sanitization cleans accepted values, such as trimming text or casting numbers. This keeps malformed or hostile input away from database queries and output. Keep read and write rules separate. Accept narrow values on writes, reject unknown fields, and return a clear error when validation fails.


You Might Also Like