Skip to content

feat(api): scope API keys to organization in Electric sync#1458

Open
saddlepaddle wants to merge 1 commit into
mainfrom
satya/super-286-org-scoped-api-keys
Open

feat(api): scope API keys to organization in Electric sync#1458
saddlepaddle wants to merge 1 commit into
mainfrom
satya/super-286-org-scoped-api-keys

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented Feb 13, 2026

Summary

  • Filter Electric SQL apikeys shape by organizationId extracted from the metadata JSON field instead of userId
  • Users now only see API keys belonging to the active organization, not all their keys across orgs

Details

The metadata column already stores organizationId (set at key creation time via tRPC). This change uses Postgres JSON extraction (metadata::jsonb->>'organizationId') in the Electric WHERE clause to filter server-side, matching the pattern used by all other org-scoped tables.

No schema migration needed — uses the existing metadata field.

Test plan

  • Create API keys in two different organizations
  • Verify each org's settings page only shows its own keys
  • Verify MCP auth still works (agent route reads organizationId from metadata independently)

Linear: SUPER-286

Summary by CodeRabbit

  • New Features

    • Per-organization API key management and display: API keys are now surfaced and managed per organization.
  • Refactor

    • Streamlined API key access filtering for improved organization-level access control and consistency.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 13, 2026

📝 Walkthrough

Walkthrough

Replaces table-based apikeys filtering with a JSONB metadata fragment in the API's buildWhereClause, removes the apikeys schema import, and adds per-organization apiKeys collection support in the desktop CollectionsProvider (new ApiKeyDisplay schema, per-org collection creation and preload).

Changes

Cohort / File(s) Summary
API: auth predicate update
apps/api/src/app/api/electric/[...path]/utils.ts
Removed apikeys schema import and changed auth.apikeys branch to emit a JSONB fragment that checks metadata.organizationId (returns fragment + params) instead of using the apikeys table builder.
Desktop: per-org apiKeys collection
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/collections.ts
Added ApiKeyDisplay type and apiKeys: Collection<ApiKeyDisplay> to OrgCollections; removed global apiKeys, create per-org apikeys-{organizationId} collection, updated preload path and createOrgCollections/getCollections handling to surface per-org apiKeys.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 nose wiggles, ears alert
From tables deep to fragments bright,
Per-org keys hop into sight,
Metadata holds the map tonight,
Hooray—tiny paws, big delight! 🎉

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: scoping API keys to organizations in the Electric sync layer, which aligns with all file-level changes.
Description check ✅ Passed The description covers key sections including Summary, Details, and Test plan, but is missing formal sections from the template (Related Issues, Type of Change, Testing, Screenshots, Additional Notes).
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch satya/super-286-org-scoped-api-keys

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/collections.ts (1)

28-36: apiKeyDisplaySchema is defined but never used at runtime.

The Zod schema is only consumed via z.infer for type inference. A plain type or interface would be sufficient here, or you could wire the schema into runtime validation (e.g., pass it to the collection for shape validation). As-is, it's dead code.

Simpler alternative using a plain type
-const apiKeyDisplaySchema = z.object({
-	id: z.string(),
-	name: z.string().nullable(),
-	start: z.string().nullable(),
-	createdAt: z.coerce.date(),
-	lastRequest: z.coerce.date().nullable(),
-});
-
-type ApiKeyDisplay = z.infer<typeof apiKeyDisplaySchema>;
+interface ApiKeyDisplay {
+	id: string;
+	name: string | null;
+	start: string | null;
+	createdAt: Date;
+	lastRequest: Date | null;
+}

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 and usage tips.

Filter apikeys by organizationId from metadata JSON instead of userId,
so users only see keys belonging to the active organization.
@saddlepaddle saddlepaddle force-pushed the satya/super-286-org-scoped-api-keys branch from b265505 to e83dd8d Compare February 13, 2026 07:11
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 13, 2026

🚀 Preview Deployment

🔗 Preview Links

Service Status Link
Neon Database (Neon) View Branch
Fly.io Electric (Fly.io) View App
Fly.io Streams (Fly.io) View App
Vercel API (Vercel) Open Preview
Vercel Web (Vercel) Open Preview
Vercel Marketing (Vercel) Open Preview
Vercel Admin (Vercel) Open Preview
Vercel Docs (Vercel) Open Preview

Preview updates automatically with new commits

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