Skip to content

fix(security): replace stream URL JWTs with one-time grants - #513

Draft
seonghobae wants to merge 11 commits into
fix/attachment-view-grant-runtime-413from
fix/stream-access-grant-runtime-413
Draft

fix(security): replace stream URL JWTs with one-time grants#513
seonghobae wants to merge 11 commits into
fix/attachment-view-grant-runtime-413from
fix/stream-access-grant-runtime-413

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Buyer/security outcome

Refs #413. This stacked slice replaces the browser realtime stream's broad session-JWT query credential with a short-lived, one-time, project-bound opaque stream grant. Calendar subscription credentials remain separate because they require a durable rotation/revocation lifecycle rather than a one-time connection grant.

Exact current stack

  • current base: fix/attachment-view-grant-runtime-413@712be4148637ebd69334ca34245e4b2ab41b0305 (fix(security): replace attachment-view URL JWTs with one-time grants #512);
  • exact contributor head: 569ffa00fc0f75f36c3615d34121927748f28c8f;
  • exact contributor tree: d6f1efec51a38ac052db4d0cfe0608c488817807;
  • fresh parent→child ancestry: ahead, 11 commits ahead, 0 behind;
  • fresh semantic delta remains exactly nine paths: cloud-sync.js, docs/doctoring/stream-access-grant-runtime.md, package.json, server/app.mjs, stream-access-grant.js, tests/api/session-revocation.test.mjs, tests/api/smoke.mjs, tests/api/stream-access-grant.test.mjs, and tests/unit/stream-access-grant-client.test.mjs.

The current parent attachment-view grant runtime, SQLite persistence/audit outbox, tenant-bound contextual-orchestrator cost attribution, current dependency versions/test registrations, Microsoft Project XML hardening, accessible toast regression, and protected security/documentation behavior are preserved outside those nine paths.

Reconciliation repair

Fresh state showed this child had diverged from its live parent after #512 was repaired, leaving it 42 parent commits behind. The old child package also carried stale dependency versions and omitted current parent OpenCode/changelog/orchestrator-attribution test registrations. Reusing that stale tree would therefore have silently weakened already-integrated parent evidence.

The causal repair at 569ffa00... rebuilds the stream child from exact current parent tree ed1714d6d257e657e081a1a91ba1fba5f560ec95 and overlays only the stream-owned semantic files. package.json is merged semantically: it retains parent @hono/node-server ^2.1.1, Playwright 1.62.1, OpenCode/changelog/orchestrator-attribution and attachment-view coverage/test registrations while adding the stream grant API/client and stream-access-grant.js coverage. Fresh comparison now proves exact-parent ancestry and the intended nine-file delta only.

Implemented contract

  • the browser exchanges its current session only through an Authorization: Bearer header on POST /api/projects/:id/access-grants with { purpose: "stream" };
  • the issued EventSource URL contains one opaque grant, not a session JWT or legacy token query parameter;
  • the stream gateway rejects legacy query JWTs, mixed/duplicate/extra query credentials, malformed grants, wrong-project grants, expired/replayed grants, and unauthorized subjects;
  • wrong-project probes do not consume an otherwise-valid project-bound grant;
  • successful grant redemption is one-time and replay-resistant;
  • direct Authorization-header SSE remains available for capable API clients and retains database-backed session revocation checks;
  • browser reconnect obtains a fresh grant and does not replay the consumed URL;
  • secured SSE responses remain private/no-store, no-referrer and nosniff while preserving connected preamble and project-update fan-out; and
  • compatibility code never sends the predecessor broad token over the network.

TDD and current evidence

The stream runtime was built test-first: missing-module/client contracts and focused fan-out/revocation assertions preceded the production gateway. All predecessor-head CI/review evidence is historical. Fresh exact-current-head Server Tests, Dependency Review and OSV workflows for 569ffa00... have been created and are non-passing until terminal. The central organization-owned exact-head SAST/Security evidence defect remains tracked on its existing .github#1222 owner path; synthetic/predecessor/status-only evidence is not merge authority.

No current review submissions or unresolved review threads exist on this exact head. This PR remains Draft until every applicable repository and organization check is terminal-success, exact owned-production coverage/docstrings are established, valid findings are zero, and qualifying independent current-head/last-push approval exists under live policy.

Standards, rollback, and integration boundary

docs/doctoring/stream-access-grant-runtime.md records the transport threat, staged gateway boundary, acceptance/rollback conditions, and APA 7 references to final RFC 6750 and RFC 9700. Rollback must not represent broad JWT query transport as a secure steady state; operational rollback should disable the affected browser realtime capability or use a controlled compatibility boundary while restoring the scoped-grant path.

This PR does not close #413. Calendar subscription rotation/revocation, PostgreSQL adapter parity, management UI/Figma flows, observability/quotas, and final rejection of all general session JWT query transports remain separate bounded work.

Do not integrate independently of #512, #510 and #506. After the prerequisite stack reaches protected develop, reconcile this bounded semantic diff onto the resulting live protected head and regenerate every then-applicable CI, browser E2E, coverage/docstring, SAST/security/dependency/supply-chain, package/provenance, migration/recovery, resolved-thread and qualifying independent-approval gate.

@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e4c07e5d-7c41-4e0a-a831-04950b59b84b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@seonghobae
seonghobae marked this pull request as ready for review August 15, 2026 21:10
@seonghobae
seonghobae marked this pull request as draft August 16, 2026 08:11
@opencode-agent opencode-agent Bot added area: auth Authentication, authorization, identity, or tenant isolation area: security Security boundary, hardening, or vulnerability prevention priority: medium Normal-priority or P2 work status: draft Draft pull request type: bug Defect or incorrect behavior labels Aug 22, 2026
@seonghobae seonghobae added the bug Something isn't working label Sep 7, 2026 — with ChatGPT Codex Connector
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: auth Authentication, authorization, identity, or tenant isolation area: security Security boundary, hardening, or vulnerability prevention bug Something isn't working priority: medium Normal-priority or P2 work status: draft Draft pull request type: bug Defect or incorrect behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant