Finding (from staging MCP e2e)
The MCP surface authenticates a sys_api_key (via resolveExecutionContext, Phase 1a), but the REST data API does NOT:
On a live staging env, same key:
POST /api/v1/mcp with x-api-key → works (initialize, tools/list, tools/call all succeed).
GET /api/v1/data/<obj> with x-api-key → 401 unauthenticated.
GET /api/v1/data/<obj> with the session cookie → 200.
Root cause (likely)
/api/v1/data + /api/v1/meta are mounted by @objectstack/rest (not the dispatcher-plugin), and that package's auth gate only accepts the better-auth session/Bearer — it doesn't run the sys_api_key resolution that resolveExecutionContext (the dispatch/MCP path) does. So Phase 1a wired the key into the dispatch path but the REST surface has a separate, un-updated auth check.
Impact
The "every app is a REST API you can drive with a key" story (ADR-0036 Phase 1b, the Integrations page cURL sample using x-api-key) doesn't actually work against /api/v1/data yet — only MCP honors the key.
Fix direction
Have @objectstack/rest's auth middleware resolve sys_api_key (x-api-key / Authorization: ApiKey) into the principal the same way resolveExecutionContext does — ideally share the one code path so REST + MCP never drift. Add a live/integration test (not just a handler unit test) that a minted key authenticates GET /api/v1/data/<obj>.
Finding (from staging MCP e2e)
The MCP surface authenticates a
sys_api_key(viaresolveExecutionContext, Phase 1a), but the REST data API does NOT:On a live staging env, same key:
POST /api/v1/mcpwithx-api-key→ works (initialize, tools/list, tools/call all succeed).GET /api/v1/data/<obj>withx-api-key→ 401 unauthenticated.GET /api/v1/data/<obj>with the session cookie → 200.Root cause (likely)
/api/v1/data+/api/v1/metaare mounted by@objectstack/rest(not the dispatcher-plugin), and that package's auth gate only accepts the better-auth session/Bearer — it doesn't run thesys_api_keyresolution thatresolveExecutionContext(the dispatch/MCP path) does. So Phase 1a wired the key into the dispatch path but the REST surface has a separate, un-updated auth check.Impact
The "every app is a REST API you can drive with a key" story (ADR-0036 Phase 1b, the Integrations page cURL sample using
x-api-key) doesn't actually work against/api/v1/datayet — only MCP honors the key.Fix direction
Have
@objectstack/rest's auth middleware resolvesys_api_key(x-api-key /Authorization: ApiKey) into the principal the same wayresolveExecutionContextdoes — ideally share the one code path so REST + MCP never drift. Add a live/integration test (not just a handler unit test) that a minted key authenticatesGET /api/v1/data/<obj>.