Native clients (Android/Flatpak) can't manage Personal Access Tokens #386

Closed
opened 2026-06-29 18:31:13 +00:00 by james · 0 comments
Owner

Problem

The PAT management endpoints — GET/POST /api/account/tokens and DELETE /api/account/tokens/{id} — gate on a cookie session (getSession(req), session-only by ADR-0021). Native clients (Android, Linux Flatpak) authenticate with the native bearer access token (cat_…, ADR-0027) and have no cookie, so the account → tokens screen 401s on those platforms. The client UI (apps/client/app/(app)/account.tsx) exists and works on web; it's simply locked out natively.

Why session-only was chosen, and why it's now too strict

ADR-0021's threat model is "a stolen PAT shouldn't infinitely re-provision itself" — so PAT auth is refused on token-management. That carve-out predates native access tokens (ADR-0027). The cat_ access token is the interactive-sign-in equivalent of a cookie session: short-lived (15-min TTL), minted only by the password or OAuth authorization_code grant on POST /api/auth/token. Admitting it preserves the threat model exactly — a stolen PAT still can't mint or revoke PATs.

Fix

Accept interactive credentials (cookie session or native access token) on the three token-management handlers; keep rejecting PATs.

  • apps/api/lib/auth/identity.ts: add getInteractiveIdentity(req) — returns the identity for session / access_token, null for pat and unauthenticated.
  • The three handlers: getSessiongetInteractiveIdentity.
  • OpenAPI: register a distinct accessTokenAuth scheme so the three routes advertise cookie or native access token, not PAT accurately; regenerate openapi.json + @carol/api-client.
  • Amend ADR-0021 with a native-access-token note cross-referencing ADR-0027.
  • Tests (tests/api/account-tokens.test.ts): access token can list/create/revoke; PAT bearer is rejected 401 on all three.

No client change needed — the screen starts working natively once the endpoints accept the access token.

## Problem The PAT management endpoints — `GET`/`POST /api/account/tokens` and `DELETE /api/account/tokens/{id}` — gate on a **cookie session** (`getSession(req)`, session-only by ADR-0021). Native clients (Android, Linux Flatpak) authenticate with the **native bearer access token** (`cat_…`, ADR-0027) and have no cookie, so the account → tokens screen 401s on those platforms. The client UI (`apps/client/app/(app)/account.tsx`) exists and works on web; it's simply locked out natively. ## Why session-only was chosen, and why it's now too strict ADR-0021's threat model is *"a stolen PAT shouldn't infinitely re-provision itself"* — so PAT auth is refused on token-management. That carve-out predates native access tokens (ADR-0027). The `cat_` access token is the interactive-sign-in equivalent of a cookie session: short-lived (15-min TTL), minted only by the `password` or OAuth `authorization_code` grant on `POST /api/auth/token`. Admitting it preserves the threat model exactly — a stolen **PAT** still can't mint or revoke PATs. ## Fix Accept **interactive** credentials (cookie session **or** native access token) on the three token-management handlers; keep rejecting **PATs**. - `apps/api/lib/auth/identity.ts`: add `getInteractiveIdentity(req)` — returns the identity for `session` / `access_token`, null for `pat` and unauthenticated. - The three handlers: `getSession` → `getInteractiveIdentity`. - OpenAPI: register a distinct `accessTokenAuth` scheme so the three routes advertise *cookie or native access token, not PAT* accurately; regenerate `openapi.json` + `@carol/api-client`. - Amend ADR-0021 with a native-access-token note cross-referencing ADR-0027. - Tests (`tests/api/account-tokens.test.ts`): access token can list/create/revoke; PAT bearer is rejected 401 on all three. No client change needed — the screen starts working natively once the endpoints accept the access token.
james closed this issue 2026-06-29 18:56:17 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
james/carol#386
No description provided.