fix(cli): unwrap API response envelope in device flow login#72
fix(cli): unwrap API response envelope in device flow login#72travisbreaks wants to merge 3 commits intoemdash-cms:mainfrom
Conversation
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/blocks
@emdash-cms/cloudflare
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
🦋 Changeset detectedLatest commit: 5db20d3 The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
All contributors have signed the CLA ✍️ ✅ |
4b3ebb6 to
2300bee
Compare
|
I have read the CLA Document and I hereby sign the CLA |
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
|
Can you rebase this on main |
…ow login Fixes emdash-cms#54. The server wraps successful responses in { data: { ... } } via apiSuccess(), but the CLI was casting the raw response body directly as DeviceCodeResponse / TokenResponse, causing all fields to resolve to undefined. Also adds scope: "admin" to the device code request so tokens receive proper scopes. Co-Authored-By: Claude Opus 4.6 (1M context) <tadao@travisfixes.com>
Co-Authored-By: Tadao <tadao@travisfixes.com>
75cf358 to
ff50368
Compare
Without it the server issues a token with no scopes and all subsequent CLI commands fail. Mirrors the second fix in upstream emdash-cms/emdash#72. Also updates patch docs to cover both fixes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
I am unable to replicate this bug with my Cloudflare deployed (via DashHost) EmDash instance. When I login via the CLI, it works fine.
|
|
Thanks for testing, @BenjaminPrice. A few questions to narrow down the discrepancy: Were you testing via DashHost or a self-deployed Cloudflare instance? This bug is specific to self-deployed instances (direct The API contract is documented: AGENTS.md explicitly states that handlers return Quick verification you can run: curl -s -X POST https://YOUR_INSTANCE/_emdash/api/oauth/device/code \
-H "Content-Type: application/json" \
-d '{"client_id": "emdash-cli"}' | python3 -m json.toolIf the response looks like On the Independent of the envelope issue, could you check your stored token? Look at Happy to provide more reproduction detail if needed. |
|
@travisbreaks I tested on DashHost. As the creator of DashHost, I can attest that there's no middleware or anything that strips away anything from the request/response. The infrastructure deploys via wrangler using Workers for Platforms for each tenant. |
There was a problem hiding this comment.
Pull request overview
Fixes emdash login against remote (Cloudflare-deployed) instances by aligning the CLI’s device-flow parsing and request parameters with the server’s OAuth device-flow implementation.
Changes:
- Unwrap
{ data: ... }API success envelopes for device-code and token polling responses. - Add a
scopeparameter to the device-code request to ensure issued tokens carry required scopes. - Add a changeset to publish the CLI fix as a patch release.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/core/src/cli/commands/login.ts | Unwraps API success envelopes in device flow and adds requested scope to device-code request. |
| .changeset/fix-cli-login.md | Declares a patch release for the CLI login fix. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| }, | ||
| body: JSON.stringify({ | ||
| client_id: "emdash-cli", | ||
| scope: "admin", |
There was a problem hiding this comment.
scope: "admin" requests only the admin scope. On the server, device-flow authorization clamps scopes by intersection (see packages/auth/src/rbac.ts), so non-admin users will end up with zero effective scopes and the device authorization step will fail with INSUFFICIENT_ROLE. If the intent is "admin for admins, otherwise clamped", request the full default scope set plus admin (space-separated) so non-admin roles still retain permitted scopes.
| scope: "admin", | |
| scope: "read write admin", |
| if (res.ok) { | ||
| return (await res.json()) as TokenResponse; | ||
| const body = (await res.json()) as { data: TokenResponse }; | ||
| return body.data; | ||
| } | ||
|
|
||
| const body = (await res.json()) as { error?: string; interval?: number }; |
There was a problem hiding this comment.
In the non-ok branch, the token endpoint can return standard API errors shaped like { error: { code, message } } (e.g. invalid device_code / unsupported grant_type), but this code parses { error?: string }. That leads to unhelpful messages like Token exchange failed: [object Object] and skips the server-provided message. Consider handling both shapes (RFC 8628 flat { error: string } and the standard { error: { message } }) when building the thrown Error.
Summary
Fixes #54. Two bugs in
emdash loginagainst remote (Cloudflare-deployed) instances:{ data: { ... } }viaapiSuccess(), but the CLI casts the raw response body directly asDeviceCodeResponse/TokenResponse. All fields resolve toundefined.scope: "admin", causing issued tokens to have no scopes. Subsequent CLI commands fail withINSUFFICIENT_SCOPE.Changes
.datafrom device code response.datafrom token polling success response (error responses are already flat, no change needed)scope: "admin"to device code request bodyTest plan
emdash loginagainst a remote Cloudflare-deployed instance completes successfullyemdash whoamisucceeds after loginCo-Authored-By: Claude Opus 4.6 (1M context) tadao@travisfixes.com