You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
DX: developers cannot obtain a credential matching a published app's permissions #494
A developer can't get a credential that matches production, so local success doesn't predict published success.
The two credentials
A personal API token — the only kind an individual can mint. Full access to all of /v2.
A static app viewer token — what a published app actually runs on. Minted only server-side, handed to the app for a signed-in viewer, with a short (~15 minute) life. It allows exactly three operations:
GET /v2/notebooks/:id — block content stripped, last-run pointers nulled
POST /v2/runs — detached runs only
GET /v2/runs/:runId — the viewer's own run only, raw snapshot withheld
Everything else → 403 This endpoint is not available to static app tokens.
Why that's a DX problem
No way to test the real surface. You cannot obtain a restricted token, so every local run necessarily has more authority than production. Publishing is the only functional test.
The gap is silent. Off-allowlist calls 403, and well-written clients swallow that into an empty state — so a feature disappears rather than errors. Nothing points at permissions as the cause.
Same URL, different payload. Even the allowed routes return less data in production (stripped content, nulled run pointers, no raw snapshot). A client can depend on a field that is always null once published — a 200 either way, so no error surfaces at all.
Devs hardcode the policy. The workaround is guessing in client code — if (isEmbedded) return in examples/local-runner/cloud-app/index.html, where isEmbedded is merely window !== window.parent. That's an assumption about server behavior baked into a client, free to drift silently.
The concrete instance
The cloud-app run-history panel worked all through development (older ?token= path, personal token) and vanished when published, because enumerating a notebook's runs is off the allowlist. No error, just a missing panel.
Two candidate fixes
Emulate the restrictions in the CLI — duplicates the policy in a second place, where it drifts, and would almost certainly miss the field-level redactions.
Issue a real restricted token to developers (the preferred direction) — local requests then traverse the actual production guard, so parity holds by construction, including the redactions. The server already performs the equivalent authorization check when it mints one of these tokens today, and such a token is less privileged than what the developer already holds, so it isn't an escalation. Main open question is lifetime, since ~15 minutes is painful for a dev loop.
Also worth noting
There's no capability discovery — even with a restricted token, a client learns its limits only by collecting 403s.
#492 is a partial mitigation: it makes deepnote publish say out loud that an embedded app gets a narrower token, and documents the boundary in the command help and the CLI reference. It does not close the gap — a developer still cannot obtain a matching credential, which is what this issue tracks.
Activity
jamesbhobbs commentedon Aug 26, 2026
#492 is a partial mitigation: it makes
deepnote publishsay out loud that an embedded app gets a narrower token, and documents the boundary in the command help and the CLI reference. It does not close the gap — a developer still cannot obtain a matching credential, which is what this issue tracks.