docs(reference): correct the X-API-Key auth claim — it is not general-purpose (#3247) - #3251
docs(reference): correct the X-API-Key auth claim — it is not general-purpose (#3247)#3251bdunncompany wants to merge 1 commit into
Conversation
…-purpose (LanternOps#3247) `reference/api.mdx` told readers an API key authenticates the REST API and gave `GET /api/v1/devices` as the example. That call returns 401: `authMiddleware` (middleware/auth.ts:448) reads the `Authorization` header and nothing else, and devices/core.ts:276 puts the whole devices surface behind it, so the key is never consulted. It was the first page anyone scripting Breeze reads, and it pointed at a wall of 401s. `X-API-Key` is honoured on three surfaces only, each of them dual-auth (key when the header is present, user JWT when it is absent): - `/api/v1/mcp/*` — the MCP server (index.ts:1114, mcpServer.ts:221) - `POST /api/v1/dev/push` — scope `devices:execute` (index.ts:1115, devPush.ts:79) - `GET`/`PATCH /api/v1/devices/:id/custom-fields` — scopes `devices:read` / `devices:write` (devices/customFieldValues.ts:87, mounted at devices/index.ts:39) Both reference pages now say so, with a table of the accepting routes and their required scopes, and the broken `/devices` example is replaced by one that works. Added the point that scopes gate what a key may DO on those routes but do not widen WHERE it is accepted — a `devices:read` key still cannot call `GET /api/v1/devices`. Also documented the other thing that silently breaks a scripted integration: the `requireMfa()` gate on `POST /orgs/partners` (orgs.ts:394), `POST /orgs/organizations` (:1279) and `POST /orgs/sites` (:1855), so an account without MFA enrolled cannot create tenancy unattended. Verified: `astro build` clean, 150 pages, both pages render, the new `#where-api-keys-work` anchor is generated and the link resolves to it, and the `/features/mcp-server/` target exists. `pnpm test:docs-automation` passes 5/5.
c52febc to
99506cb
Compare
|
Superseded by #3286 — closing this rather than leaving a duplicate. Yours is the better version and should land instead: it covers the same two files, adds One nuance from mine that I did not find in #3286, offered only in case you want it — no need to act on it:
That was the specific wrong inference I expected a reader to draw: a key page listing |
Fixes #3247 — the top item in your #3249 ordering, and the one that costs hours rather than days.
What was wrong
reference/api.mdxsaid an API key authenticates the REST API and usedGET /api/v1/devicesas the example. That call returns401 Missing or invalid authorization header.Confirmed against
origin/mainrather than taken from the issue:authMiddleware(middleware/auth.ts:448) reads theAuthorizationheader and nothing else, throwing at:451when it is absent or notBearer-prefixed.devices/core.ts:276puts the entire devices surface behind it, so the documented example is specifically one of the calls that cannot work.Where keys actually work
Three surfaces, all dual-auth — key when
X-API-Keyis present, user JWT when it is absent:/api/v1/mcp/*ai:*index.ts:1114,mcpServer.ts:221POST /api/v1/dev/pushdevices:executeindex.ts:1115,devPush.ts:79GET /api/v1/devices/:id/custom-fieldsdevices:readdevices/customFieldValues.ts:87PATCH /api/v1/devices/:id/custom-fieldsdevices:writeBoth reference pages now carry that table, and the broken
/devicesexample is replaced by one that works. I added the distinction that made this trap easy to fall into: scopes gate what a key may do on those routes, not where it is accepted. Adevices:readkey still cannot callGET /api/v1/devices, which is exactly the wrong inference a scope list invites.Also covered your third point — the
requireMfa()gate onPOST /orgs/partners(orgs.ts:394),POST /orgs/organizations(:1279) andPOST /orgs/sites(:1855), so nobody discovers mid-migration that an MFA-less service account cannot create tenancy.Two line-number corrections
Not substantive, but so the issue isn't a false trail later:
apiKeyAuthMiddlewareis mounted atmcpServer.ts:221(not 219) and the devicesauthMiddlewareis atdevices/core.ts:276(not 268). Everything else in the issue checked out exactly, including that the three mount sites are the only non-test ones —servicePrincipals.ts:20even carries a comment asserting it never imports it.On the cross-link I did not add
Your issue points at
migration/toolkit.mdxas the source of truth for the accurate behaviour, and it is — but that page only exists in #3250, which is still open. Linking to it from here would ship a dead link until that merges, so I kept the MFA guidance self-contained. Worth adding the cross-link when #3250 lands; happy to do it in that PR or a follow-up, whichever you prefer.Verification
astro build— exit 0, 150 pages, both pages render#where-api-keys-workheading generates its anchor and the in-page link resolves to it (checked in the built HTML, not assumed)/features/mcp-server/link target exists indistpnpm test:docs-automation— 5/5 passDiff is two
.mdxfiles; no lockfile or manifest churn.