Skip to content

feat(api): send an app-user token to app-user-only operations in api fetch - #689

Closed
NitzanSirota wants to merge 1 commit into
mainfrom
feat/api-fetch-app-user-token
Closed

NitzanSirota wants to merge 1 commit into
mainfrom
feat/api-fetch-app-user-token

Conversation

@NitzanSirota

@NitzanSirota NitzanSirota commented Nov 2, 2026 •

Copy link
Copy Markdown

Note

Description

base44 api fetch sent the platform login token to every route, including app runtime routes (entities, User, count, trash) that only understand an app user's token — so the server treated those calls as anonymous and returned empty or wrong results with no error. This PR teaches api fetch to read the AppUserTokenAuth security scheme from the API spec and, for operations marked with it, exchange the platform login for an app-user token via GET /api/apps/{app_id}/auth/token (the same flow base44 exec already uses) before sending the request. Workspace API keys, unmarked operations, non-app paths, and older servers whose spec lacks the scheme all behave exactly as before.

Related Issue

None. Depends on the spec change in base44-dev/apper#36784, which adds the AppUserTokenAuth scheme to the marked operations.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Other (please describe):

Changes Made

  • core/api-spec/operations.ts — parse the AppUserTokenAuth security scheme into a new ApiOperation.appUserToken flag (operation-level security, falling back to the spec-level default), and add pathParameter() to read a concrete path's value for a {name} segment of the matched operation's template.
  • core/api-spec/request.ts — add appUserTokenFor(method, path, { refresh }): short-circuits on a workspace API key or a non-/api/apps/{id}/ path, loads and matches the spec, and exchanges for an app-user token only when the matched operation is marked. A spec that fails to load is swallowed (.catch(() => null)) so an older server falls back to sending the login as before. sendApiRequest() takes an optional appUserToken and routes through the app-user client when present.
  • core/clients/base44-client.ts — new getAppUserClient(token) ky factory that sends Authorization: Bearer <app-user-token>, keeps X-Request-ID and request-body capture, and deliberately omits the refresh-on-401 hook (a retry with the platform login would just run as anonymous again). Exported from core/clients/index.ts.
  • core/project/api.ts — getAppUserToken() now accepts an optional appId (defaulting to getAppContext().id) and calls base44Client with an explicit api/apps/{appId}/auth/token path instead of getAppClient(), so it works for an app id taken from the request path without requiring initialized app context.
  • cli/commands/api/fetch.ts — resolve the app-user token inside the runTask callback before sending, passing refresh: options.refresh && !options.readOnly to avoid re-fetching a spec that --read-only already refreshed.
  • CHANGELOG.md — entry under Changed describing the new behaviour.

Testing

  • I have tested these changes locally
  • I have added/updated tests as needed
  • All tests pass (npm test)

New app user token suite in packages/cli/tests/cli/api.spec.ts covering the three paths, with the spec fixture extended to mark GET /api/apps/{app_id}/entities/{entity_name} with AppUserTokenAuth:

  • a marked operation with a platform login performs exactly one token exchange (asserting the exchange itself is authorized with the login and hits the right app_id) and sends Bearer app-user-token;
  • an unmarked operation (/api/apps/68a1/workflows/runs) performs no exchange and sends the login;
  • a workspace API key (BASE44_API_KEY) performs no exchange and is sent as the api_key header with no Authorization.

The marked-operation test also asserts the exchanged token never appears in stdout or stderr. The specFetches === 0 assertion moved to the test where it still holds, since resolving the token now consults the cached spec.

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (if applicable)
  • My changes generate no new warnings
  • I have updated docs/ (AGENTS.md) if I made architectural changes

Additional Notes

  • No X-Bypass-RLS header is sent: the call runs as the caller's app user under the app's own access rules, not with elevated privileges.
  • Per the author, lint, typecheck and knip are clean and the suite passes apart from the dev.spec.ts Deno-fallback test, which also fails on main when Deno is not installed.
  • docs/ was not updated — the change adds a client factory and a spec-driven auth branch rather than altering documented architecture — but reviewers may want docs/api-patterns.md to mention getAppUserClient alongside base44Client/getAppClient.

🤖 Generated by Claude | 2026-11-02 06:07 UTC | 072f10a

…fetch

App runtime routes (entities, User, count, trash) only understand app-user
tokens; the platform login was read as anonymous, giving wrong or empty
results with no error. When the spec marks the matched operation with the
AppUserTokenAuth scheme and the CLI runs on a platform login, exchange it
via getAppUserToken (as exec does) and send that instead. Workspace API keys
and specs without the scheme are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

🚀 Package Preview Available!


Install this PR's preview build with npm:

npm i @base44-preview/cli@0.2.7-pr.689.072f10a

Prefer not to change any import paths? Install using npm alias so your code still imports base44:

npm i "base44@npm:@base44-preview/cli@0.2.7-pr.689.072f10a"

Or add it to your package.json dependencies:

{
  "dependencies": {
    "base44": "npm:@base44-preview/cli@0.2.7-pr.689.072f10a"
  }
}

Preview published to npm registry — try new features instantly!

@NitzanSirota
NitzanSirota marked this pull request as ready for review November 2, 2026 06:16
@NitzanSirota
NitzanSirota marked this pull request as draft November 2, 2026 08:39
@NitzanSirota

Copy link
Copy Markdown
Author

Superseded by base44-dev/apper#36893: the server now runs a CLI token as the caller's app user on app routes, so the client-side exchange isn't needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant