feat(web): Add ability to refresh permissions from account linking settings#945
Conversation
…sync (SOU-578) Adds POST /api/trigger-account-permission-sync that creates and enqueues an AccountPermissionSyncJob for a given accountId, with entitlement and provider validation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Introduces `LinkedAccount` type in `ee/features/sso/actions.ts` covering all OAuth providers (SSO + account_linking), replacing the narrower `LinkedAccountProviderState` - Rewrites linked accounts UI with Linear-style Connect / Connected dropdown pattern; dropdown includes Disconnect and Refresh Permissions actions - Adds `triggerAccountPermissionSync` server action and worker API call for per-account permission refresh - Renames settings page from "Permission Syncing" to "Linked Accounts" - Removes `getLinkedAccountProviderStates` in favour of `getLinkedAccounts` - Moves SSO-related components and actions from `ee/features/permissionSyncing/` to `ee/features/sso/` Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThe PR refactors permission syncing from a provider-centric to account-centric architecture. It moves permission sync constants to the shared package, adds a new backend API endpoint for triggering account permission syncs, replaces the permission-syncing UI with a unified linked-accounts interface under SSO entitlements, and restructures frontend/backend service actions accordingly. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant UI as Frontend UI
participant Action as Worker Action
participant API as Backend API
participant Queue as Job Queue
participant DB as Database
User->>UI: Click "Refresh Permissions"
UI->>Action: triggerAccountPermissionSync(accountId)
Action->>API: POST /api/trigger-account-permission-sync
API->>API: Validate provider support<br/>Check feature flag & entitlement
API->>Queue: Schedule accountPermissionSyncJob
Queue->>DB: Create AccountPermissionSyncJob record
DB-->>Queue: Return jobId
Queue-->>API: Job enqueued
API-->>Action: Return jobId
Action-->>UI: jobId received
UI->>UI: Poll getAccountSyncStatus(jobId)
DB->>UI: Return isSyncing status
UI->>User: Show sync progress
Estimated code review effort🎯 4 (Complex) | ⏱️ ~55 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
packages/backend/src/ee/accountPermissionSyncer.ts (1)
118-132: Validation already occurs at the API endpoint level.The
triggerAccountPermissionSyncendpoint inpackages/backend/src/api.ts(lines 128–131) validates thataccount.provideris inPERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERSbefore callingschedulePermissionSyncForAccount. This prevents unsupported providers from reaching the method.Adding validation within the method would provide defense-in-depth, but it is not required since the only caller currently validates. If this method is intended for internal use only and always called through the validated endpoint, the refactor is optional.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/backend/src/ee/accountPermissionSyncer.ts` around lines 118 - 132, The reviewer notes validation already happens in the API endpoint, so you can leave schedulePermissionSyncForAccount as-is; if you prefer defense-in-depth, add a guard at the start of schedulePermissionSyncForAccount that checks account.provider against PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS and throw a clear error (or return early) when unsupported; reference the schedulePermissionSyncForAccount method, the triggerAccountPermissionSync caller, and the PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS constant when implementing the optional check.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/backend/src/api.ts`:
- Around line 119-134: The handler currently fetches an account by raw accountId
without validating ownership; update the account lookup to require the
requesting user's id (e.g. include userId: req.user.id in the Prisma where
clause) so the query mirrors unlinkLinkedAccountProvider's pattern and returns
404 if no matching record is found; after that keep the existing provider
support check (PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS) and call
accountPermissionSyncer.schedulePermissionSyncForAccount(account) only for a
validated account.
In `@packages/web/src/ee/features/sso/components/connectAccountsCard.tsx`:
- Around line 52-53: The list renderer in connectAccountsCard.tsx uses
account.provider as the React key which can duplicate if a user links multiple
accounts for the same provider; update the key to a unique, stable identifier
from the account object (e.g., account.id or account.providerAccountId) where
the element uses key={account.provider} and passes linkedAccount={account} so
React reconciliation remains correct.
---
Nitpick comments:
In `@packages/backend/src/ee/accountPermissionSyncer.ts`:
- Around line 118-132: The reviewer notes validation already happens in the API
endpoint, so you can leave schedulePermissionSyncForAccount as-is; if you prefer
defense-in-depth, add a guard at the start of schedulePermissionSyncForAccount
that checks account.provider against
PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS and throw a clear error (or return
early) when unsupported; reference the schedulePermissionSyncForAccount method,
the triggerAccountPermissionSync caller, and the
PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS constant when implementing the
optional check.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (26)
CHANGELOG.mdpackages/backend/src/api.tspackages/backend/src/constants.tspackages/backend/src/ee/accountPermissionSyncer.tspackages/backend/src/ee/repoPermissionSyncer.tspackages/backend/src/index.tspackages/shared/src/constants.tspackages/web/src/app/[domain]/layout.tsxpackages/web/src/app/[domain]/settings/layout.tsxpackages/web/src/app/[domain]/settings/linked-accounts/page.tsxpackages/web/src/app/[domain]/settings/permission-syncing/page.tsxpackages/web/src/app/api/(server)/ee/permissionSyncStatus/route.tspackages/web/src/auth.tspackages/web/src/ee/features/permissionSyncing/actions.tspackages/web/src/ee/features/permissionSyncing/components/linkButton.tsxpackages/web/src/ee/features/permissionSyncing/components/linkedAccountProviderCard.tsxpackages/web/src/ee/features/permissionSyncing/components/providerBadge.tsxpackages/web/src/ee/features/permissionSyncing/components/providerInfo.tsxpackages/web/src/ee/features/permissionSyncing/components/unlinkButton.tsxpackages/web/src/ee/features/permissionSyncing/types.tspackages/web/src/ee/features/sso/actions.tspackages/web/src/ee/features/sso/components/connectAccountsCard.tsxpackages/web/src/ee/features/sso/components/linkedAccountProviderCard.tsxpackages/web/src/ee/features/sso/components/providerIcon.tsxpackages/web/src/ee/features/sso/tokenRefresh.tspackages/web/src/features/workerApi/actions.ts
💤 Files with no reviewable changes (8)
- packages/web/src/ee/features/permissionSyncing/components/providerBadge.tsx
- packages/web/src/ee/features/permissionSyncing/components/providerInfo.tsx
- packages/web/src/ee/features/permissionSyncing/components/linkedAccountProviderCard.tsx
- packages/web/src/ee/features/permissionSyncing/components/unlinkButton.tsx
- packages/web/src/ee/features/permissionSyncing/actions.ts
- packages/web/src/app/[domain]/settings/permission-syncing/page.tsx
- packages/web/src/ee/features/permissionSyncing/components/linkButton.tsx
- packages/web/src/ee/features/permissionSyncing/types.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/web/src/ee/features/sso/sso.ts`:
- Around line 159-160: Remove the unsafe hardcoded
allowDangerousEmailAccountLinking: true in the SSO provider options (references:
allowDangerousEmailAccountLinking in sso.ts) or, alternatively, add a signIn
callback to your NextAuth configuration (NextAuthOptions in auth.ts) that
prevents account linking unless the provider asserts email verification;
implement signIn to inspect account.provider and account/email_verified /
id_token claims and return false when the provider did not assert a verified
email, otherwise return true. Ensure the change is applied for all providers
currently using allowDangerousEmailAccountLinking (the instances in sso.ts) so
the safer behavior is enforced consistently.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
docs/docs/configuration/environment-variables.mdxpackages/shared/src/env.server.tspackages/web/src/ee/features/sso/sso.ts
💤 Files with no reviewable changes (1)
- docs/docs/configuration/environment-variables.mdx
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/web/src/app/api/`(client)/client.ts:
- Line 23: Change the value imports to type-only imports for server-only types:
replace the current import that brings in AccountSyncStatusResponse (and the
similar PermissionSyncStatusResponse on the adjacent line) with an "import type"
form so the client module only imports types from the "(server)" module and
avoids client/server boundary build issues.
In
`@packages/web/src/app/api/`(server)/ee/accountPermissionSyncJobStatus/route.ts:
- Around line 9-11: The schema currently allows empty jobId because z.string()
accepts "", so update the validator to reject empty values by adding .min(1) to
the jobId string schema; specifically modify queryParamsSchema (the const
queryParamsSchema = z.object({ jobId: z.string(), })) to use jobId:
z.string().min(1) and do the same for the identical rawParams extraction schema
(the other z.object that defines jobId) so empty jobId values produce a 400
validation error instead of reaching the DB and returning 404.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
packages/web/src/app/api/(client)/client.tspackages/web/src/app/api/(server)/ee/accountPermissionSyncJobStatus/api.tspackages/web/src/app/api/(server)/ee/accountPermissionSyncJobStatus/route.tspackages/web/src/app/api/(server)/ee/permissionSyncStatus/route.tspackages/web/src/ee/features/sso/components/linkedAccountProviderCard.tsx
✅ Files skipped from review due to trivial changes (1)
- packages/web/src/app/api/(server)/ee/permissionSyncStatus/route.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/web/src/ee/features/sso/components/linkedAccountProviderCard.tsx
Summary
LinkedAccounttype inee/features/sso/actions.tscovering all OAuth providers (SSO + account_linking), replacing the narrowerLinkedAccountProviderStatetriggerAccountPermissionSyncserver action and backend API endpoint for per-account permission sync refreshgetLinkedAccountProviderStatesin favour of the consolidatedgetLinkedAccountsee/features/permissionSyncing/toee/features/sso/AUTH_EE_ALLOW_EMAIL_ACCOUNT_LINKINGto default totrueTest plan
account_linkingproviders show a "Connect ↗" button that initiates OAuth flow and redirects back correctlyaccount_linkingproviders🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
Improvements