Skip to content

feat(access): add short-lived opaque grant domain - #506

Open
seonghobae wants to merge 31 commits into
developfrom
feat/access-grant-domain-413
Open

feat(access): add short-lived opaque grant domain#506
seonghobae wants to merge 31 commits into
developfrom
feat/access-grant-domain-413

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Buyer and security impact

Issue #413 identifies a material enterprise-security gap: ScopeWeave still carries the general session JWT in URL query parameters for browser mechanisms that cannot reliably supply an Authorization header. This bounded root slice establishes the framework-neutral security domain required to replace that broad URL credential with short-lived, purpose-bound opaque grants without prematurely changing protected runtime transports.

This PR does not close #413. It adds no route, database migration, calendar subscription, SSE client migration, attachment-view migration, or UI. Existing protected behavior remains unchanged until those follow-up slices are independently implemented and verified.

Exact current scope

  • protected live base: develop@2c328875e00e86537df3e965170be80532571cad;
  • exact contributor head: f3ae1f1f4ee66024776507d75f8fb752b2bf748c;
  • exact current merge base is protected develop@2c328875...;
  • GitHub reports this PR Ready, non-Draft, and mechanically mergeable;
  • the effective protected-base diff remains exactly seven access-grant/evidence paths:
    • server/access_grant_domain.mjs;
    • tests/unit/access-grant-domain.test.mjs;
    • tests/unit/access-grant-domain-edge.test.mjs;
    • tests/unit/coverage-script-contract.test.mjs;
    • package.json;
    • docs/doctoring/short-lived-access-grant-domain.md;
    • CHANGELOG.md.

The reconciliation preserves protected application behavior outside those seven paths. No existing auth/session implementation, Hono route, database schema, Clearfolio, attachment refresh, billing, workflow, dependency, lockfile, or protected-branch policy is changed by the effective diff.

Any contributor-head, protected-base, review, or required-gate movement invalidates revision-sensitive evidence until freshly refetched and reconciled.

Security and domain contract

  • generates 32 cryptographically random bytes per grant, encoded as unpadded base64url;
  • generates an independent random grant_id correlation identifier, never derived from the secret or token hash;
  • allows only a SHA-256 token hash to cross the persistence port; plaintext secrets never enter persistence or audit records;
  • caps lifetime at 300 seconds;
  • fixes purpose/audience pairs: streamscopeweave:stream, attachment_viewscopeweave:attachment-view;
  • requires one exact attachment binding for attachment-view grants and forbids one for stream grants;
  • checks project authorization before minting with a tenant-nondisclosing failure contract;
  • rechecks membership before redemption and passes the captured membership version into consumeGrantAtomically(...), which production adapters must validate atomically;
  • requires membership versions to be non-negative safe integers or trimmed, control-free strings no longer than 128 characters;
  • collapses malformed, unknown, expired, used, revoked, stale-membership, wrong-purpose, wrong-audience, wrong-project, wrong-attachment, replay, and unusable-version cases into the same unauthorized redemption result;
  • treats exact expiry as non-usable (now >= expires_at);
  • validates the repository's returned consumed record against the requested transition, including the expected used_at_ms, so a faulty adapter cannot turn an unconsumed record into a successful principal;
  • keeps one-time use as an atomic repository transition;
  • prevents a downstream audit-sink outage from turning an already durable mint or consume into a client-visible failure and unsafe retry; production persistence that requires durable audit evidence must use a transactional audit outbox; and
  • leaves long-lived calendar subscription credentials outside this domain because they require independent rotation, revocation, and usage semantics.

The module is independent of Hono, SQLite, Clearfolio, and browser code and accepts explicit repository, clock, random-source, audit, project-authorization, and membership-revocation ports.

TDD and review-driven hardening

The first contract commit imported an absent server/access_grant_domain.mjs; focused Node execution failed RED with ERR_MODULE_NOT_FOUND before production implementation existed.

CodeRabbit identified predecessor-head concerns around independent grant correlation identity, atomic membership authority at consume, audit-failure semantics after durable transitions, edge-test coverage registration, and consumed-state validation. Current source addresses those findings and their enumerated threads are resolved. Membership-version hardening rejects missing, negative/NaN, blank, control-character, overlength, and object versions.

Focused tests cover hash-only persistence, secret-free audit events, purpose/audience/resource isolation, TTL boundaries, inaccessible projects, membership revocation and its check/consume race, audit-sink failure after durable transitions, malformed/unknown secrets, replay rejection, concurrent two-consumer one-time use, consumed-state adapter failures, and membership-version adapter failures.

The dismissed OpenCode CHANGES_REQUESTED review is predecessor-head evidence on 59c10080696972b2955b229edf37a4e9a649dbbc and reported the then-live merge conflict. Current head is mechanically mergeable against the live protected base, so that predecessor verdict does not transfer. Current Devin unresolved threads are informational observations about the explicit repository-port contract, fail-closed authorization error mapping, grant-bound membership inputs, and ordering assumptions; none presently demonstrates a new current-head product defect and they remain visible rather than being status-cleaned.

Current exact-head evidence boundary

All six repository workflow runs currently associated with exact contributor head f3ae1f1f4ee66024776507d75f8fb752b2bf748c are terminal GitHub-success:

  • Server Tests 32562230719 — success;
  • Fuzz 32562230702 — success;
  • Security Scan 32562230689 — success;
  • Dependency Review 32562230686 — success;
  • OSV Scanner 32562230943 — success; and
  • SAST Semgrep 32562230734 — success.

Those labels are regression evidence, not immutable contributor-head merge authority while the known revision-evidence defects remain unresolved. ScopeWeave #523 owns repository-native exact-head Server Tests/coverage integrity. ContextualWisdomLab/.github#1222 owns the reusable required SAST/Security exact-head checkout repair through that repository's existing dedicated writer/control path. No current CodeQL Required workflow run was returned for this contributor head, so required CodeQL evidence remains absent/non-passing rather than implicitly successful.

The organization-central evidence defects tracked by .github#1002 (required review-verdict evidence) and .github#955 (provider-unavailability false-green behavior) also remain separate owner boundaries. ScopeWeave does not add leaf workarounds or promote synthetic/status-only/model-only evidence.

There is no qualifying independent current-head/last-push approval. Do not self-approve or manufacture one.

Standards, rollback, and integration boundary

docs/doctoring/short-lived-access-grant-domain.md records active-PR versus protected-shipped truth, threat and port boundaries, membership-race and audit-durability contracts, rollback, and APA 7 references to RFC 6750, RFC 9700/BCP 240, and RFC 8725.

Rollback removes the domain module, focused tests, coverage registrations, doctoring record, and changelog entries together. Because this slice changes no route or persisted schema, rollback requires no data migration.

This PR does not close #413. SQLite/PostgreSQL adapters, authenticated exchange routes, stream/attachment client migrations, revocation hooks, calendar-subscription lifecycle, Figma/UI flows, browser acceptance, and eventual rejection of full session JWT query transport remain separate bounded work. The current calendar domain child is #539, its persistence child is #541, and runtime integration continues in #549.

Merge gate

Do not merge or enable auto-merge until this unchanged exact contributor head remains reconciled to freshly resolved protected develop, the repository and central exact-head evidence controls are protected-shipped where applicable, every applicable repository/organization CI/browser/owned statement-branch-function-line coverage/docstring/CodeQL/SAST/security/dependency/supply-chain/package/provenance/required-review gate is substantively terminal-passing under corrected evidence contracts, valid unresolved findings are zero, and the qualifying independent current-head/last-push approval required by live governance genuinely exists.

Pending, queued, skipped-required, cancelled, absent, neutral-required, failed, stale, predecessor, synthetic-only, status-only, author-only, model-only, rate-limited, or infrastructure-only evidence is non-passing.

Refs #413

@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@seonghobae, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 18 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c35681e-5a9d-4714-9da1-dcd66c317161

📥 Commits

Reviewing files that changed from the base of the PR and between c5162f4 and f3ae1f1.

📒 Files selected for processing (2)
  • server/access_grant_domain.mjs
  • tests/unit/access-grant-domain-edge.test.mjs
📝 Walkthrough

Walkthrough

프레임워크 중립적인 단기 접근 권한 도메인을 추가했다. streamattachment_view 목적을 지원한다. 5분 TTL, SHA-256 해시 저장, 권한·멤버십 재검증, 원자적 1회 소비를 적용했다. 소비 결과의 바인딩도 재검증한다.

Changes

단기 접근 권한 도메인

Layer / File(s) Summary
정책과 포트 계약
docs/doctoring/short-lived-access-grant-domain.md, server/access_grant_domain.mjs
목적, audience, TTL, 프로젝트·대상·첨부파일 바인딩, 저장소 포트, 오류 형식, 난수와 시계 검증을 정의하고 구현했다.
발급과 소비 흐름
server/access_grant_domain.mjs, tests/unit/access-grant-domain.test.mjs
mint는 비밀값의 SHA-256 해시만 저장한다. redeem은 바인딩과 멤버십을 재검증하고 원자적 1회 소비를 수행한다. 소비된 grant의 식별자와 바인딩도 검증한다.
계약 검증과 등록
tests/unit/access-grant-domain-edge.test.mjs, tests/unit/coverage-script-contract.test.mjs, package.json, CHANGELOG.md, docs/doctoring/short-lived-access-grant-domain.md
입력 오류, TTL, 멤버십 경쟁 조건, 감사 실패, 변조된 소비 결과 및 동시 소비를 검증한다. 테스트와 커버리지 대상을 등록하고 구현 범위와 계약을 문서화했다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🟠 High · up to c5162

The new grant domain can accept an invalid consume result as successful because it does not verify the one-time transition, allowing a repeated redemption to be authorized. The PR is not merge-ready until the consumed-state checks and corresponding test are fixed.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant AccessGrantService
  participant ProjectAuthorizationPort
  participant AccessGrantRepository
  participant MembershipRevocationPort
  participant AccessGrantAuditSink

  Client->>AccessGrantService: mint 요청
  AccessGrantService->>ProjectAuthorizationPort: 프로젝트 발급 권한 확인
  AccessGrantService->>AccessGrantRepository: grant 해시 저장
  AccessGrantService->>AccessGrantAuditSink: 발급 감사 기록

  Client->>AccessGrantService: redeem 요청
  AccessGrantService->>AccessGrantRepository: 해시로 grant 조회
  AccessGrantService->>MembershipRevocationPort: 멤버십 재검증
  AccessGrantService->>AccessGrantRepository: 원자적 1회 소비
  AccessGrantService->>AccessGrantService: 소비 결과 바인딩 재검증
  AccessGrantService->>AccessGrantAuditSink: 소비 감사 기록
  AccessGrantService-->>Client: 검증된 grant 결과
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 3 files. (2 skipped: 2 unsupported.) Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 단기 불투명 접근 권한 도메인을 추가하는 주요 변경 사항을 정확하고 간결하게 설명합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/access-grant-domain-413

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.

coderabbitai[bot]

This comment was marked as resolved.

@cursor

cursor Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Copy link
Copy Markdown
Contributor Author

@opencode-agent review

Please submit a formal review for exact current head 6f2cbf39d4fb547517aff64cfe09f083c11303b9 against protected develop@44e7903cf8891c65410f7fc6ca5144de3fdb5185. Re-evaluate only current source after all predecessor CodeRabbit findings were addressed: independent random grant correlation identity, atomic membership-version enforcement during consume, audit-failure semantics after durable transitions, edge-test coverage registration, bounded TTL/purpose/audience/resource isolation, replay rejection, and secret-hash-only persistence. Current opencode-review check 95240617942 is terminal success; no exact-head formal review exists. Review only; do not mutate, merge, weaken gates, or transfer predecessor findings.

@cursor
cursor Bot force-pushed the feat/access-grant-domain-413 branch from 6f2cbf3 to 59c1008 Compare August 17, 2026 18:58
cursor Bot pushed a commit that referenced this pull request Aug 17, 2026
Rebase onto current #506 dropped the return-boundary entries from
package.json and the coverage-script contract. Restore them so the
isolated atomic-return regression stays in test:unit and c8.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

OpenCode reviewed the current-head mergeability evidence and changed-file flow before approval, then found merge conflicts on the affected path.

Findings

1. HIGH Merge Conflict Guidance - Resolve the PR branch against the latest base branch

  • Problem: GitHub reports mergeStateStatus DIRTY for this pull request.
  • Root cause: Branch feat/access-grant-domain-413 cannot be merged cleanly into develop; the changed-file flow below shows which review/runtime path is blocked by the conflict.
  • Fix: Merge or rebase the latest develop into feat/access-grant-domain-413, resolve conflict markers in the PR branch, rerun the focused checks, and push the same branch.
  • Repair commands:
gh pr checkout 506 --repo ContextualWisdomLab/scopeweave
git fetch origin develop
git merge --no-ff origin/develop  # or: git rebase origin/develop
git status --short
# resolve files, then git add <resolved-files>
# merge path: git commit
# rebase path: git rebase --continue
git push origin HEAD:feat/access-grant-domain-413
# rebase path only: git push --force-with-lease origin HEAD:feat/access-grant-domain-413
  • Regression test: Keep OpenCode approval gated on mergeability so model-output failures cannot approve a conflicted PR.

Merge Conflict Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (3 files)"]
  S1 --> I1["repository behavior"]
  I1 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V1["required checks"]
  Evidence --> S2["Docs: short-lived-access-grant-domain.md"]
  S2 --> I2["operator or user guidance"]
  I2 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V2["docs review"]
  Evidence --> S3["Test (3 files)"]
  S3 --> I3["regression suite"]
  I3 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V3["targeted test run"]
Loading
  • Result: REQUEST_CHANGES
  • Reason: mergeStateStatus is DIRTY; mergeable is CONFLICTING.
  • Head SHA: 59c10080696972b2955b229edf37a4e9a649dbbc
  • Workflow run: 32188776233
  • Workflow attempt: 1

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (3 files)"]
  S1 --> I1["repository behavior"]
  I1 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V1["required checks"]
  Evidence --> S2["Docs: short-lived-access-grant-domain.md"]
  S2 --> I2["operator or user guidance"]
  I2 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V2["docs review"]
  Evidence --> S3["Test (3 files)"]
  S3 --> I3["regression suite"]
  I3 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V3["targeted test run"]
Loading

@opencode-agent

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

  • Head SHA: 59c10080696972b2955b229edf37a4e9a649dbbc
  • Workflow run: 32188776233
  • Workflow attempt: 1
  • Gate result: REQUEST_CHANGES (approval step)

Pull request overview

OpenCode reviewed the current-head mergeability evidence and changed-file flow before approval, then found merge conflicts on the affected path.

Findings

1. HIGH Merge Conflict Guidance - Resolve the PR branch against the latest base branch

  • Problem: GitHub reports mergeStateStatus DIRTY for this pull request.
  • Root cause: Branch feat/access-grant-domain-413 cannot be merged cleanly into develop; the changed-file flow below shows which review/runtime path is blocked by the conflict.
  • Fix: Merge or rebase the latest develop into feat/access-grant-domain-413, resolve conflict markers in the PR branch, rerun the focused checks, and push the same branch.
  • Repair commands:
gh pr checkout 506 --repo ContextualWisdomLab/scopeweave
git fetch origin develop
git merge --no-ff origin/develop  # or: git rebase origin/develop
git status --short
# resolve files, then git add <resolved-files>
# merge path: git commit
# rebase path: git rebase --continue
git push origin HEAD:feat/access-grant-domain-413
# rebase path only: git push --force-with-lease origin HEAD:feat/access-grant-domain-413
  • Regression test: Keep OpenCode approval gated on mergeability so model-output failures cannot approve a conflicted PR.

Merge Conflict Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (3 files)"]
  S1 --> I1["repository behavior"]
  I1 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V1["required checks"]
  Evidence --> S2["Docs: short-lived-access-grant-domain.md"]
  S2 --> I2["operator or user guidance"]
  I2 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V2["docs review"]
  Evidence --> S3["Test (3 files)"]
  S3 --> I3["regression suite"]
  I3 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V3["targeted test run"]
Loading
  • Result: REQUEST_CHANGES
  • Reason: mergeStateStatus is DIRTY; mergeable is CONFLICTING.
  • Head SHA: 59c10080696972b2955b229edf37a4e9a649dbbc
  • Workflow run: 32188776233
  • Workflow attempt: 1

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (3 files)"]
  S1 --> I1["repository behavior"]
  I1 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V1["required checks"]
  Evidence --> S2["Docs: short-lived-access-grant-domain.md"]
  S2 --> I2["operator or user guidance"]
  I2 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V2["docs review"]
  Evidence --> S3["Test (3 files)"]
  S3 --> I3["regression suite"]
  I3 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V3["targeted test run"]
Loading

Merge Conflict Guidance

  • Current merge state: DIRTY
  • Base branch: develop
  • Head branch: feat/access-grant-domain-413
  • Fix direction: merge or rebase origin/develop into feat/access-grant-domain-413, resolve conflict markers in the changed files, rerun the focused checks, then push the same branch.
  • Repair commands:
gh pr checkout 506 --repo ContextualWisdomLab/scopeweave
git fetch origin develop
git merge --no-ff origin/develop  # or: git rebase origin/develop
git status --short
# resolve files, then git add <resolved-files>
# merge path: git commit
# rebase path: git rebase --continue
git push origin HEAD:feat/access-grant-domain-413
# rebase path only: git push --force-with-lease origin HEAD:feat/access-grant-domain-413

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

coderabbitai[bot]

This comment was marked as resolved.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 5 new potential issues.

Open in Devin Review

Comment thread server/access_grant_domain.mjs
Comment thread server/access_grant_domain.mjs
Comment thread server/access_grant_domain.mjs
Comment thread server/access_grant_domain.mjs
Comment thread server/access_grant_domain.mjs
devin-ai-integration[bot]

This comment was marked as resolved.

@opencode-agent opencode-agent Bot added priority: medium Normal-priority or P2 work status: needs-review Open pull request requiring current-head review or checks type: feature New or expanded product capability labels Aug 22, 2026
@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 3 files. (2 skipped: 2 unsupported.) Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 단기 불투명 접근 권한 도메인을 추가하는 PR의 핵심 변경 사항을 정확하고 간결하게 설명합니다.

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 dismissed opencode-agent[bot]’s stale review August 23, 2026 17:39

This changes-requested verdict is anchored to predecessor head 59c1008 and solely reported a then-live merge conflict. Current exact head f3ae1f1 is based on protected develop@2c328875e00e86537df3e965170be80532571cad and GitHub currently reports the PR mergeable. The historical conflict finding is therefore stale; dismissal removes predecessor review state without manufacturing approval. Current-head checks, findings, and independent approval remain required.

@seonghobae seonghobae added the enhancement New feature or request 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

enhancement New feature or request priority: medium Normal-priority or P2 work status: needs-review Open pull request requiring current-head review or checks type: feature New or expanded product capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Product Gap] Replace full JWT query tokens with scoped ephemeral access grants

1 participant