Respuesta corta: en la REST API de WordPress, autenticación y autorización son etapas diferentes. Cuando una solicitud usa la autenticación por cookies del propio WordPress, el nonce de la acción wp_rest ayuda al core a validar la intención de la solicitud y a asociarla con la sesión autenticada. No concede permiso para leer, crear, actualizar o eliminar recursos. La decisión de acceso debe estar en permission_callback, normalmente con current_user_can() y una capability adecuada al recurso.
Esta separación evita un error común: considerar que una solicitud con un X-WP-Nonce válido ya está autorizada. Un usuario puede estar autenticado y, aun así, no tener la capability requerida. La documentación de WordPress recomienda comprobar lo que el usuario puede hacer, en vez de limitarse a verificar si ha iniciado sesión.
Autenticación y autorización responden a preguntas diferentes
| Capa | Pregunta | Mecanismo típico |
|---|---|---|
| Autenticación | ¿Quién realiza la solicitud? | Cookies de WordPress con nonce wp_rest, Application Passwords u otro método de autenticación |
| Autorización | ¿Este usuario puede ejecutar esta acción? | permission_callback con current_user_can() u otra regla de acceso |
| Ejecución | ¿Qué ocurre después de aprobar el acceso? | callback de la ruta, con validación, saneamiento y lógica de negocio |
El flujo seguro es sencillo: WordPress primero resuelve la autenticación disponible; después, antes del callback principal, ejecuta permission_callback. Solo si se concede el permiso debe continuar la lógica de la ruta.
Qué hace realmente el nonce del REST
En la autenticación por cookies, utilizada principalmente cuando JavaScript se ejecuta dentro de un sitio WordPress con el usuario ya conectado, el cliente envía un nonce creado para la acción wp_rest. El valor puede enviarse en el encabezado X-WP-Nonce o en el parámetro _wpnonce. La documentación recomienda el encabezado porque funciona de forma consistente con distintos métodos HTTP.
Si la solicitud depende de cookies pero no presenta un nonce REST válido, el core no debe tratar esa sesión como autenticada para la llamada. El REST API Handbook explica que, sin el nonce, el usuario actual se establece como ID 0, por lo que la llamada se comporta como no autenticada. Cuando el nonce es inválido, el mecanismo de autenticación por cookies puede detener la solicitud con un error.
En endpoints personalizados, no es necesario volver a verificar manualmente el nonce wp_rest dentro del callback. El core realiza esa comprobación durante la autenticación por cookies mediante rest_cookie_check_errors(). Lo importante es que esto no sustituye la autorización. La documentación general de nonces de WordPress dice explícitamente que los nonces no deben usarse como control de acceso y recomienda proteger las operaciones con current_user_can().
Hay además un matiz importante: los nonces de WordPress no son tokens de un solo uso en el sentido criptográfico estricto. Tienen una ventana de validez y pueden reutilizarse durante ella. Por eso no deben tratarse como un secreto equivalente a una contraseña ni como prueba suficiente de permiso.
Cómo registrar una ruta privada con permission_callback
Considere una ruta que modifica una configuración del plugin. Como la operación es administrativa, el ejemplo siguiente exige la capability manage_options. En un plugin real, elija la capability más específica que corresponda a la acción.
<?php add_action( 'rest_api_init', function () { register_rest_route( 'acme/v1', '/settings', array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => 'acme_update_settings', 'permission_callback' => 'acme_update_settings_permissions_check', 'args' => array( 'value' => array( 'required' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', ), ), ) ); } ); function acme_update_settings_permissions_check( WP_REST_Request $request ) { if ( ! current_user_can( 'manage_options' ) ) { return new WP_Error( 'acme_rest_forbidden', __( 'You are not allowed to change this setting.', 'acme' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } function acme_update_settings( WP_REST_Request $request ) { $value = $request->get_param( 'value' ); update_option( 'acme_example_value', $value ); return rest_ensure_response( array( 'success' => true, 'value' => $value, ) ); }permission_callback puede devolver true, false o un WP_Error. Devolver WP_Error es útil cuando se quiere un código y un mensaje específicos. Si devuelve false o null, el servidor REST crea una respuesta de acceso denegado. El helper rest_authorization_required_code() devuelve 401 para un visitante no autenticado y 403 para un usuario autenticado que no puede realizar la acción.
Desde WordPress 5.5, registrar una ruta sin permission_callback genera un aviso de uso incorrecto. En rutas realmente públicas, __return_true puede ser apropiado. En una ruta privada, usar __return_true solo para eliminar el aviso elimina precisamente la barrera de autorización.
Tres escenarios que muestran por qué el nonce no basta
| Escenario | Autenticación | Autorización | Resultado esperado |
|---|---|---|---|
| Visitante anónimo | No hay sesión autenticada | current_user_can() falla | Acceso denegado, normalmente 401 |
| Usuario conectado con nonce válido, pero sin la capability | La sesión puede reconocerse | current_user_can() falla | Acceso denegado, normalmente 403 |
| Usuario conectado con nonce válido y la capability necesaria | La sesión se reconoce | current_user_can() pasa | Se ejecuta el callback de la ruta |
El segundo escenario es la prueba mental más importante. Un nonce válido puede acompañar la solicitud de un suscriptor, autor u otro usuario sin el permiso necesario. Si la ruta solo verifica el nonce o solo llama a is_user_logged_in(), puede exponer una operación que debería seguir restringida.
Cuándo usar nonce y cuándo usar otro método de autenticación
El nonce wp_rest encaja en el flujo de autenticación por cookies, sobre todo en pantallas de administración, bloques, plugins o front-ends renderizados por el propio WordPress, donde el navegador ya tiene las cookies de sesión. En ese caso, JavaScript envía el nonce junto con la llamada REST.
Para integraciones externas, servicios en otro servidor, scripts de automatización o clientes que no comparten la sesión de cookies del navegador, la documentación de WordPress presenta Application Passwords como método nativo de autenticación REST sobre HTTPS. Incluso con Application Passwords, la autorización de la ruta sigue siendo responsabilidad de permission_callback.
En otras palabras, el método de autenticación puede cambiar, pero la regla de autorización permanece. El endpoint debe decidir si la identidad autenticada puede realizar la operación solicitada.
Prefiera capabilities a nombres de roles
current_user_can() debe recibir una capability que represente la acción. Comprobar directamente si el usuario es administrator, editor u otro rol crea acoplamiento innecesario y puede fallar en sitios que personalizan roles y capabilities.
Cuando la autorización depende de un objeto concreto, prefiera una meta capability con el ID correspondiente. Para editar una entrada específica, por ejemplo:
function acme_update_post_permissions_check( WP_REST_Request $request ) { $post_id = (int) $request['id']; return current_user_can( 'edit_post', $post_id ); }WordPress mapea meta capabilities como edit_post a las capacidades primitivas necesarias según el usuario, el objeto y el contexto. Esto es más preciso que una comprobación genérica como edit_posts cuando la decisión depende de un elemento concreto.
Errores comunes al proteger una ruta REST
- Usar nonce como autorización: ayuda a proteger el flujo de la solicitud, pero no indica si el usuario puede realizar la acción.
- Comprobar solo si el usuario ha iniciado sesión: autenticación sin capability puede conceder acceso excesivo a cuentas con pocos privilegios.
- Poner toda la autorización dentro del callback principal: la comprobación debe ocurrir en permission_callback, antes de la lógica de negocio.
- Usar __return_true en un endpoint privado: esto autoriza públicamente la ruta aunque el callback intente compensarlo después.
- Comprobar un rol en vez de una capability: las capabilities son la abstracción prevista por WordPress para autorización.
- Volver a comprobar manualmente el nonce REST sin necesidad: en el flujo estándar de cookies, el core ya verifica wp_rest. Duplique la comprobación solo si existe otro requisito de seguridad independiente y bien definido.
- Confiar en parámetros del cliente para decidir privilegios: IDs y argumentos pueden orientar la comprobación, pero el servidor debe tomar la decisión con datos y capabilities confiables.
Prueba de regresión: anónimo, usuario sin capability y usuario autorizado
Además de probar el caso exitoso, mantenga pruebas que demuestren que la ruta sigue denegando acceso cuando cambian la autenticación o la capability. Una prueba unitaria o de integración puede despachar una WP_REST_Request directamente al servidor REST para validar la regla de autorización.
<?php public function test_settings_route_permissions() { $server = rest_get_server(); wp_set_current_user( 0 ); $request = new WP_REST_Request( 'POST', '/acme/v1/settings' ); $request->set_param( 'value', 'one' ); $response = $server->dispatch( $request ); $this->assertSame( 401, $response->get_status() ); $subscriber_id = self::factory()->user->create( array( 'role' => 'subscriber' ) ); wp_set_current_user( $subscriber_id ); $request = new WP_REST_Request( 'POST', '/acme/v1/settings' ); $request->set_param( 'value', 'two' ); $response = $server->dispatch( $request ); $this->assertSame( 403, $response->get_status() ); $admin_id = self::factory()->user->create( array( 'role' => 'administrator' ) ); wp_set_current_user( $admin_id ); $request = new WP_REST_Request( 'POST', '/acme/v1/settings' ); $request->set_param( 'value', 'three' ); $response = $server->dispatch( $request ); $this->assertSame( 200, $response->get_status() ); }Esta prueba cubre la autorización del endpoint. Si el plugin depende de JavaScript autenticado por cookies, añada también una prueba de integración HTTP para el flujo de nonce: sesión iniciada sin X-WP-Nonce, nonce inválido, nonce válido con usuario sin capability y nonce válido con usuario autorizado. Así se separan las regresiones de autenticación de las regresiones de autorización.
Checklist para una ruta REST privada
- Registre la ruta en rest_api_init.
- Defina explícitamente permission_callback.
- Elija una capability vinculada a la acción real, usando una meta capability y el ID del objeto cuando sea necesario.
- Use nonce wp_rest solo cuando la llamada dependa de autenticación por cookies.
- Para clientes externos, use un método de autenticación adecuado, como Application Passwords sobre HTTPS.
- Valide y sanee los argumentos de la solicitud por separado de la autorización.
- Mantenga el callback principal centrado en la lógica de la operación después de aprobar el permiso.
- Pruebe al menos los escenarios anónimo, autenticado sin capability y autenticado con capability.





