Skip to content

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

Draft
seonghobae wants to merge 9 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 9 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@f2b08715663946405719f742f2f5597a4f45ee4a (#512).
Current contributor head: 7717f4401e84a81a40f25d79e236628d60b22b6d.

Fresh parent→child comparison is ahead-only, zero-behind, and limited to nine realtime client/security gateway, focused API/unit regression, test-registration, and doctoring paths. The current parent attachment-view grant runtime, SQLite persistence/audit evidence, Microsoft Project XML hardening, and protected security documentation remain unchanged.

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 43-character opaque grant and no session JWT or legacy token parameter;
  • the public 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 a grant that is otherwise valid for its bound project;
  • 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 closes the failed native EventSource, obtains a fresh grant, and never replays the consumed grant URL;
  • secured SSE responses are private, no-store, no-referrer, and nosniff while preserving the connected preamble and project-update fan-out;
  • the compatibility bridge consumes the predecessor core's token-bearing constructor string locally and does not send that broad token over the network.

TDD and parent reconciliation

The stream runtime was built test-first: the missing-module contract preceded implementation, focused fan-out and revocation assertions were strengthened before the production gateway, and stale broad-JWT smoke expectations were removed only after the scoped path existed.

After #512 advanced, this branch was reconciled semantically onto its exact current parent. The parent-only Microsoft Project XML hardening lives in cloud-sync-core.js, security/doctoring, changelog, and parser regression paths that this child does not own; those parent versions are carried unchanged. The nine-file parent→child diff therefore contains only the stream-grant slice and cannot silently revert the attachment or XML-import security boundaries.

Current exact-head evidence

All predecessor-head CI/review evidence is historical. Fresh exact-current-head evidence for 7717f4401e84a81a40f25d79e236628d60b22b6d is authoritative and non-passing until terminal. This PR remains Draft until every applicable repository and organization check succeeds, owned coverage/docstrings are established, valid findings are zero, and qualifying independent current-head/last-push approval exists.

Standards and rollback

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. RFC 10017 publication-transition material is treated only as supplementary research because authoritative publication surfaces were not yet internally consistent when this slice was documented.

Rollback must not represent broad JWT query transport as a security-safe steady state. If operational rollback becomes necessary, disable the affected browser realtime capability or place it behind a controlled compatibility boundary while restoring the scoped-grant path.

Integration boundary

Do not integrate independently of #512, which depends on #510 and #506. After the prerequisite stack reaches protected develop, reconcile this semantic slice onto the resulting live protected head and require every applicable exact-head repository/organization CI, browser E2E, owned coverage/docstrings, SAST/security/dependency/supply-chain gate, zero valid unresolved findings, and one qualifying current-head/last-push independent approval under the live rulesets. Predecessor-head, skipped-required, neutral, status-only, synthetic, or model-only evidence does not transfer.

@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: 6294d793-f3d4-4e70-8d8f-1fe5a2c5133f

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
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