The argument has been technically optional and omitting it means no authorisation at all, which is how an endpoint intended for the admin ends up readable by anyone who finds the URL.
register_rest_route( 'turkerdev/v1', '/reports/(?P<id>d+)', array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'turkerdev_get_report',
'permission_callback' => function ( WP_REST_Request $request ) {
return current_user_can( 'read_report', (int) $request['id'] );
},
'args' => array(
'id' => array(
'required' => true,
'validate_callback' => 'is_numeric',
'sanitize_callback' => 'absint',
),
),
) );
Checking a capability against the specific object rather than a blanket manage_options is what makes an endpoint usable by a non-administrator without opening everything. The args block is the half most often skipped: validation runs before the callback, so the callback can assume well-formed input. Returning a WP_Error rather than false from the permission callback lets you say why, which matters when debugging a client you did not write.