adom-molecule
Public Made by Adomby adom
Adom Molecule CLI — import a wiki molecule into Hydrogen (reuses the published GLB, no re-optimization), plus create/optimize/list/delete from KiCad, Fusion 360, and EasyEDA files.
Switch adom-molecule CLI auth from Authorization: Bearer to X-Api-Key
Background
The molecule CLI talks to Hydrogen's molecule API (/api/molecules/*). Hydrogen
was just updated (Hydrogen repo) to authenticate and authorize those
endpoints using the same convention as the editor/panels API:
- Browser users →
session_tokencookie - AI / containers / CLI →
X-Api-Keyheader (a Carbonc_-prefixed token)
Hydrogen resolves the caller's identity from Carbon GET /user, their org
membership from GET /user/orgs, and enforces that the target owner/
username is the caller's own username, an org they belong to, or that the
caller is an admin. S3 itself is unauthenticated; Carbon is the identity
authority; Hydrogen enforces ownership.
The CLI currently sends Authorization: Bearer <token>. Hydrogen does not
read that header for the molecule endpoints — it reads X-Api-Key. So the CLI
must switch headers.
Note: the token value is unchanged. Carbon accepts the same
c_…token; only the header name on the request to Hydrogen changes.
Scope of this issue (CLI repo only)
src/client.rs:
- In
apply_auth()(or wherever the auth header is attached), send the token as theX-Api-Keyheader instead ofAuthorization: Bearer <token>.- Apply it to every authenticated call:
get_json,post_json,delete,post_multipart. head_ok(health) stays unauthenticated.
- Apply it to every authenticated call:
- Keep the existing 3-tier token resolution unchanged
(
~/.config/adom-cli/config.jsonapi_token→ADOM_API_TOKENenv →/var/run/adom/api-key).
Example (ureq):
fn apply_auth(req: ureq::Request) -> ureq::Request {
match resolve_token() {
Some(token) => req.set("X-Api-Key", &token),
None => req,
}
}
That's the whole code change. No new dependencies.
Why no Hydrogen-side change is needed for the internal S3 hop
For info only: create/delete/generate-json internally call
/api/curium/get-s3-api-key to fetch the shared S3 key. SvelteKit does not
auto-forward custom headers like X-Api-Key to internal fetches, so Hydrogen
now threads the token explicitly into CuriumClientTs.create(fetch, token).
That is already handled in Hydrogen — the CLI just needs to send X-Api-Key.
Test plan
Against a CLI build pointed at prod Hydrogen (ADOM_HYDROGEN_URL,
default https://hydrogen.adom.inc):
- Own user:
adom-molecule create --owner <your-username> ...→ succeeds. - Member org:
--owner <an-org-you-belong-to>→ succeeds. - Forbidden owner:
--owner <an-owner-you-do-NOT-belong-to>→ Hydrogen returns 403 (Forbidden - <you> cannot act on behalf of '<owner>'). - No / bad token: unset all token sources → 401.
delete,optimize(queue), andcreateall exercise the same auth path — smoke-test each.
Quick header sanity check (token belongs to kcknox):
curl -sk -H "X-Api-Key: c_…" https://carbon.adom.inc/user # 200 + identity
curl -sk -H "X-Api-Key: c_…" https://carbon.adom.inc/user/orgs # 200 + org list
Out of scope (separate follow-ups)
- Unify resolvers: Hydrogen now has two near-identical token resolvers —
src/lib/server/editorAuth.ts(resolveCallerIdentity) and the newsrc/lib/server/apiAuth.ts(resolveCaller). Collapse to one shared helper. /api/workspaces/repo/[owner]/[repo]/current(the non-editorworkspace endpoints) authenticate by forwarding the browser cookie to Carbon withcredentials: 'include'; they have noX-Api-Keypath and won't work for containers. Decide whether containers ever need them and gate accordingly.- Consider adding
X-Api-Keysupport to any other non-editor mutating routes surfaced during review.
# Switch `adom-molecule` CLI auth from `Authorization: Bearer` to `X-Api-Key`
## Background
The molecule CLI talks to Hydrogen's molecule API (`/api/molecules/*`). Hydrogen
was just updated (Hydrogen repo) to authenticate and **authorize** those
endpoints using the same convention as the editor/panels API:
- **Browser users** → `session_token` cookie
- **AI / containers / CLI** → `X-Api-Key` header (a Carbon `c_`-prefixed token)
Hydrogen resolves the caller's identity from Carbon `GET /user`, their org
membership from `GET /user/orgs`, and **enforces that the target `owner`/
`username` is the caller's own username, an org they belong to, or that the
caller is an admin**. S3 itself is unauthenticated; Carbon is the identity
authority; Hydrogen enforces ownership.
The CLI currently sends `Authorization: Bearer <token>`. Hydrogen does **not**
read that header for the molecule endpoints — it reads `X-Api-Key`. So the CLI
must switch headers.
> Note: the token *value* is unchanged. Carbon accepts the same `c_…` token; only
> the header name on the request to Hydrogen changes.
## Scope of this issue (CLI repo only)
`src/client.rs`:
1. In `apply_auth()` (or wherever the auth header is attached), send the token as
the `X-Api-Key` header instead of `Authorization: Bearer <token>`.
- Apply it to every authenticated call: `get_json`, `post_json`, `delete`,
`post_multipart`.
- `head_ok` (health) stays unauthenticated.
2. Keep the existing 3-tier token resolution unchanged
(`~/.config/adom-cli/config.json` `api_token` → `ADOM_API_TOKEN` env →
`/var/run/adom/api-key`).
Example (ureq):
```rust
fn apply_auth(req: ureq::Request) -> ureq::Request {
match resolve_token() {
Some(token) => req.set("X-Api-Key", &token),
None => req,
}
}
```
That's the whole code change. No new dependencies.
## Why no Hydrogen-side change is needed for the internal S3 hop
For info only: `create`/`delete`/`generate-json` internally call
`/api/curium/get-s3-api-key` to fetch the shared S3 key. SvelteKit does not
auto-forward custom headers like `X-Api-Key` to internal `fetch`es, so Hydrogen
now threads the token explicitly into `CuriumClientTs.create(fetch, token)`.
That is already handled in Hydrogen — the CLI just needs to send `X-Api-Key`.
## Test plan
Against a CLI build pointed at prod Hydrogen (`ADOM_HYDROGEN_URL`,
default `https://hydrogen.adom.inc`):
1. **Own user:** `adom-molecule create --owner <your-username> ...` → succeeds.
2. **Member org:** `--owner <an-org-you-belong-to>` → succeeds.
3. **Forbidden owner:** `--owner <an-owner-you-do-NOT-belong-to>` →
Hydrogen returns **403** (`Forbidden - <you> cannot act on behalf of '<owner>'`).
4. **No / bad token:** unset all token sources → **401**.
5. `delete`, `optimize` (queue), and `create` all exercise the same auth path —
smoke-test each.
Quick header sanity check (token belongs to `kcknox`):
```sh
curl -sk -H "X-Api-Key: c_…" https://carbon.adom.inc/user # 200 + identity
curl -sk -H "X-Api-Key: c_…" https://carbon.adom.inc/user/orgs # 200 + org list
```
## Out of scope (separate follow-ups)
- **Unify resolvers:** Hydrogen now has two near-identical token resolvers —
`src/lib/server/editorAuth.ts` (`resolveCallerIdentity`) and the new
`src/lib/server/apiAuth.ts` (`resolveCaller`). Collapse to one shared helper.
- **`/api/workspaces/repo/[owner]/[repo]/current`** (the non-`editor` workspace
endpoints) authenticate by forwarding the browser cookie to Carbon with
`credentials: 'include'`; they have no `X-Api-Key` path and won't work for
containers. Decide whether containers ever need them and gate accordingly.
- Consider adding `X-Api-Key` support to any other non-editor mutating routes
surfaced during review.
```