Write a secure REST API endpoint with proper permission callbacks
A register_rest_route scenario that reasons through the gap between is_user_logged_in and real capability checks, plus param validation and rate-limit judgment calls.
Works with Claude / GPT2,100 uses★ 4.6
The prompt
code-secure-rest-api-endpoint
I need a REST endpoint `POST /wp-json/myplugin/v1/orders/{id}/refund` that a React
admin dashboard calls to trigger a partial refund. It needs to accept a JSON body
`{ "amount": 25.00, "reason": "damaged item" }`.
CONTEXT: [this endpoint currently exists with `'permission_callback' => function() {
return is_user_logged_in(); }` and a support rep flagged that a logged-in subscriber
from the storefront was somehow able to hit it in testing]
Fix this like a senior dev doing a security pass on an API surface, in order:
1. Explain precisely why `is_user_logged_in()` is the wrong check here: it verifies
identity, not authorization, so any logged-in customer account passes it. Replace it
with a proper `current_user_can()` check against a specific capability (not just
`manage_options`, since a shop manager role should also be allowed, so map it to a
custom capability like `process_refunds`).
2. Validate the route args with `args` schema in `register_rest_route()`: `id` must be
a valid, existing order ID owned by a real order (not just numeric), `amount` must
be a positive number not exceeding the order's remaining refundable total, and
`reason` should be sanitized text with a max length.
3. Show the full `register_rest_route()` call plus the callback, using
`WC_REST_Response` or `WP_REST_Response` with correct HTTP status codes (403 for
permission failure, 404 for missing order, 422 for invalid amount, not a blanket 200
with an error string in the body).
4. Flag the edge case: nonce vs application password auth. If the dashboard uses
cookie auth, the endpoint also needs `X-WP-Nonce` verification via
`wp_verify_nonce()`, since `permission_callback` alone doesn't protect against CSRF
for cookie-authenticated requests, only against unauthorized users.
5. Recommend a lightweight rate limit or at least logging on this route, since refund
endpoints are a common target for abuse if a capability check ever regresses again.
Replace the route, capability, and validation rules with your actual endpoint's needs.
The is_user_logged_in() mistake in step 1 is one of the most common REST API vulnerabilities in WordPress plugins, since it looks correct in a quick test with an admin account and only fails once a lower-privilege user tries it. Always test permission callbacks with the lowest-privilege role that should be denied, not just the highest one that should be allowed.