I resolved the issue, it was core Magento bug.
Admin user with restricted "order create" access can "view", "cancel", etc via API
To fix I need to update the webapi.xml
in Sales
module.
<?xml version="1.0"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">
<route url="/V1/orders/:id" method="GET">
<service class="Magento\Sales\Api\OrderRepositoryInterface" method="get"/>
<resources>
<resource ref="Magento_Sales::actions_view" />
</resources>
</route>
<route url="/V1/orders" method="GET">
<service class="Magento\Sales\Api\OrderRepositoryInterface" method="getList"/>
<resources>
<resource ref="Magento_Sales::actions_view" />
</resources>
</route>
<route url="/V1/orders/:id/statuses" method="GET">
<service class="Magento\Sales\Api\OrderManagementInterface" method="getStatus"/>
<resources>
<resource ref="Magento_Sales::actions_view" />
</resources>
</route>
<route url="/V1/orders/:id/cancel" method="POST">
<service class="Magento\Sales\Api\OrderManagementInterface" method="cancel"/>
<resources>
<resource ref="Magento_Sales::cancel" />
</resources>
</route>
<route url="/V1/orders/:id/emails" method="POST">
<service class="Magento\Sales\Api\OrderManagementInterface" method="notify"/>
<resources>
<resource ref="Magento_Sales::emails" />
</resources>
</route>
<route url="/V1/orders/:id/hold" method="POST">
<service class="Magento\Sales\Api\OrderManagementInterface" method="hold"/>
<resources>
<resource ref="Magento_Sales::hold" />
</resources>
</route>
<route url="/V1/orders/:id/unhold" method="POST">
<service class="Magento\Sales\Api\OrderManagementInterface" method="unHold"/>
<resources>
<resource ref="Magento_Sales::unhold" />
</resources>
</route>
<route url="/V1/orders/:id/comments" method="POST">
<service class="Magento\Sales\Api\OrderManagementInterface" method="addComment"/>
<resources>
<resource ref="Magento_Sales::comment" />
</resources>
</route>
<route url="/V1/orders/:id/comments" method="GET">
<service class="Magento\Sales\Api\OrderManagementInterface" method="getCommentsList"/>
<resources>
<resource ref="Magento_Sales::actions_view" />
</resources>
</route>
<route url="/V1/orders/create" method="PUT">
<service class="Magento\Sales\Api\OrderRepositoryInterface" method="save"/>
<resources>
<resource ref="Magento_Sales::create" />
</resources>
</route>
<route url="/V1/orders/:parent_id" method="PUT">
<service class="Magento\Sales\Api\OrderAddressRepositoryInterface" method="save"/>
<resources>
<resource ref="Magento_Sales::create" />
</resources>
</route>
<route url="/V1/orders/items/:id" method="GET">
<service class="Magento\Sales\Api\OrderItemRepositoryInterface" method="get"/>
<resources>
<resource ref="Magento_Sales::actions_view" />
</resources>
</route>
<route url="/V1/orders/items" method="GET">
<service class="Magento\Sales\Api\OrderItemRepositoryInterface" method="getList"/>
<resources>
<resource ref="Magento_Sales::actions_view" />
</resources>
</route>
<route url="/V1/invoices/:id" method="GET">
<service class="Magento\Sales\Api\InvoiceRepositoryInterface" method="get"/>
<resources>
<resource ref="Magento_Sales::sales_invoice" />
</resources>
</route>
<route url="/V1/invoices" method="GET">
<service class="Magento\Sales\Api\InvoiceRepositoryInterface" method="getList"/>
<resources>
<resource ref="Magento_Sales::sales_invoice" />
</resources>
</route>
<route url="/V1/invoices/:id/comments" method="GET">
<service class="Magento\Sales\Api\InvoiceManagementInterface" method="getCommentsList"/>
<resources>
<resource ref="Magento_Sales::sales_invoice" />
</resources>
</route>
<route url="/V1/invoices/:id/emails" method="POST">
<service class="Magento\Sales\Api\InvoiceManagementInterface" method="notify"/>
<resources>
<resource ref="Magento_Sales::sales_invoice" />
</resources>
</route>
<route url="/V1/invoices/:id/void" method="POST">
<service class="Magento\Sales\Api\InvoiceManagementInterface" method="setVoid"/>
<resources>
<resource ref="Magento_Sales::sales_invoice" />
</resources>
</route>
<route url="/V1/invoices/:id/capture" method="POST">
<service class="Magento\Sales\Api\InvoiceManagementInterface" method="setCapture"/>
<resources>
<resource ref="Magento_Sales::sales_invoice" />
</resources>
</route>
<route url="/V1/invoices/comments" method="POST">
<service class="Magento\Sales\Api\InvoiceCommentRepositoryInterface" method="save"/>
<resources>
<resource ref="Magento_Sales::sales_invoice" />
</resources>
</route>
<route url="/V1/invoices/" method="POST">
<service class="Magento\Sales\Api\InvoiceRepositoryInterface" method="save"/>
<resources>
<resource ref="Magento_Sales::sales_invoice" />
</resources>
</route>
<route url="/V1/invoice/:invoiceId/refund" method="POST">
<service class="Magento\Sales\Api\RefundInvoiceInterface" method="execute"/>
<resources>
<resource ref="Magento_Sales::sales_invoice" />
</resources>
</route>
<route url="/V1/creditmemo/:id/comments" method="GET">
<service class="Magento\Sales\Api\CreditmemoManagementInterface" method="getCommentsList"/>
<resources>
<resource ref="Magento_Sales::sales_creditmemo" />
</resources>
</route>
<route url="/V1/creditmemos" method="GET">
<service class="Magento\Sales\Api\CreditmemoRepositoryInterface" method="getList"/>
<resources>
<resource ref="Magento_Sales::sales_creditmemo" />
</resources>
</route>
<route url="/V1/creditmemo/:id" method="GET">
<service class="Magento\Sales\Api\CreditmemoRepositoryInterface" method="get"/>
<resources>
<resource ref="Magento_Sales::sales_creditmemo" />
</resources>
</route>
<route url="/V1/creditmemo/:id" method="PUT">
<service class="Magento\Sales\Api\CreditmemoManagementInterface" method="cancel"/>
<resources>
<resource ref="Magento_Sales::sales_creditmemo" />
</resources>
</route>
<route url="/V1/creditmemo/:id/emails" method="POST">
<service class="Magento\Sales\Api\CreditmemoManagementInterface" method="notify"/>
<resources>
<resource ref="Magento_Sales::sales_creditmemo" />
</resources>
</route>
<route url="/V1/creditmemo/refund" method="POST">
<service class="Magento\Sales\Api\CreditmemoManagementInterface" method="refund"/>
<resources>
<resource ref="Magento_Sales::sales_creditmemo" />
</resources>
</route>
<route url="/V1/creditmemo/:id/comments" method="POST">
<service class="Magento\Sales\Api\CreditmemoCommentRepositoryInterface" method="save"/>
<resources>
<resource ref="Magento_Sales::sales_creditmemo" />
</resources>
</route>
<route url="/V1/creditmemo" method="POST">
<service class="Magento\Sales\Api\CreditmemoRepositoryInterface" method="save"/>
<resources>
<resource ref="Magento_Sales::sales_creditmemo" />
</resources>
</route>
<route url="/V1/order/:orderId/refund" method="POST">
<service class="Magento\Sales\Api\RefundOrderInterface" method="execute"/>
<resources>
<resource ref="Magento_Sales::creditmemo" />
</resources>
</route>
<route url="/V1/shipment/:id" method="GET">
<service class="Magento\Sales\Api\ShipmentRepositoryInterface" method="get"/>
<resources>
<resource ref="Magento_Sales::shipment" />
</resources>
</route>
<route url="/V1/shipments" method="GET">
<service class="Magento\Sales\Api\ShipmentRepositoryInterface" method="getList"/>
<resources>
<resource ref="Magento_Sales::shipment" />
</resources>
</route>
<route url="/V1/shipment/:id/comments" method="GET">
<service class="Magento\Sales\Api\ShipmentManagementInterface" method="getCommentsList"/>
<resources>
<resource ref="Magento_Sales::shipment" />
</resources>
</route>
<route url="/V1/shipment/:id/comments" method="POST">
<service class="Magento\Sales\Api\ShipmentCommentRepositoryInterface" method="save"/>
<resources>
<resource ref="Magento_Sales::shipment" />
</resources>
</route>
<route url="/V1/shipment/:id/emails" method="POST">
<service class="Magento\Sales\Api\ShipmentManagementInterface" method="notify"/>
<resources>
<resource ref="Magento_Sales::shipment" />
</resources>
</route>
<route url="/V1/shipment/track" method="POST">
<service class="Magento\Sales\Api\ShipmentTrackRepositoryInterface" method="save"/>
<resources>
<resource ref="Magento_Sales::shipment" />
</resources>
</route>
<route url="/V1/shipment/track/:id" method="DELETE">
<service class="Magento\Sales\Api\ShipmentTrackRepositoryInterface" method="deleteById"/>
<resources>
<resource ref="Magento_Sales::shipment" />
</resources>
</route>
<route url="/V1/shipment/" method="POST">
<service class="Magento\Sales\Api\ShipmentRepositoryInterface" method="save"/>
<resources>
<resource ref="Magento_Sales::shipment" />
</resources>
</route>
<route url="/V1/shipment/:id/label" method="GET">
<service class="Magento\Sales\Api\ShipmentManagementInterface" method="getLabel"/>
<resources>
<resource ref="Magento_Sales::shipment" />
</resources>
</route>
<route url="/V1/order/:orderId/ship" method="POST">
<service class="Magento\Sales\Api\ShipOrderInterface" method="execute"/>
<resources>
<resource ref="Magento_Sales::ship" />
</resources>
</route>
<route url="/V1/orders/" method="POST">
<service class="Magento\Sales\Api\OrderRepositoryInterface" method="save"/>
<resources>
<resource ref="Magento_Sales::create" />
</resources>
</route>
<route url="/V1/transactions/:id" method="GET">
<service class="Magento\Sales\Api\TransactionRepositoryInterface" method="get"/>
<resources>
<resource ref="Magento_Sales::transactions_fetch" />
</resources>
</route>
<route url="/V1/transactions" method="GET">
<service class="Magento\Sales\Api\TransactionRepositoryInterface" method="getList"/>
<resources>
<resource ref="Magento_Sales::transactions_fetch" />
</resources>
</route>
<route url="/V1/order/:orderId/invoice" method="POST">
<service class="Magento\Sales\Api\InvoiceOrderInterface" method="execute"/>
<resources>
<resource ref="Magento_Sales::invoice" />
</resources>
</route>
</routes>
The PR is #20170 and will be merged in 2.3.1 release.