GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix(credentials): let workspace admins disconnect a teammate's OAuth credential by waleedlatif1 · Pull Request #6737 · simstudioai/sim

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Disconnecting an OAuth credential routed through POST /api/auth/oauth/disconnect, a credential user operation scoped to the acting user's own account rows. A workspace or org admin acting on a credential another user created matched no accounts, so it returned { credentials: [] } and the route still answered 200 — the UI navigated away and the credential was still there. Not a denial, a silent no-op.
  • Route every credential type through the workspace-scoped credential delete, which authorizes against credential admin and already resolves workspace/org admins as derived credential admins for shared credential types.
  • That path only deleted the credential row, so send oauth through deleteCredentialRecord — the manager that also tears down a credential's secret source — and have it delete the backing account grant once no credential references it. Scoped by account id, not owner: the caller is already authorized against the credential. A grant still used by a credential in another workspace survives.
  • Collapse the delete use case's remaining service_account carve-out. Both arms reached the same tail, but the carve-out skipped the Slack custom-bot credential-group guard — and custom bots are exactly the type it guards, so the single-delete surface could orphan a credential group that the batch path refuses to.
  • deleteOrphanedOAuthAccount is one conditional statement rather than a read then a write. credential.accountId is ON DELETE CASCADE, so a credential racing the gap would be reaped by Postgres without clearCredentialRefs running, stranding its id in workflow state.
  • Point the reconnect hook at that shared helper; it carried its own copy of the same orphan-grant rule.
  • Invalidate the OAuth connections query on credential delete — the removed disconnect hook owned that invalidation and the detail page reads it. Retires the hand-dispatched oauth-credentials-updated event from the delete path; connect/reconnect still dispatches it. Deletes the now-callerless useDisconnectOAuthService.
  • Make RoleLockTooltip layout-transparent. It wrapped locked controls in an inline-flex div, letting the chip shrink to its label while unwrapped controls stretched to the member row's fixed role track — so one members list rendered the same role at two widths. A grid wrapper takes the width its parent offers and passes it through, aligning the credential, secrets, and skills member lists that share the row.

Type of Change

  • Bug fix

Testing

  • bun run type-check clean; bun run check:api-validation passes
  • 193 test files / 1800 tests pass across lib/credentials, hooks, app/api/credentials, app/api/auth/oauth
  • Added regression tests for the grant teardown and the delete routing, and verified both fail against the pre-fix source
  • Width change is code-verified across all three member-list surfaces, not browser-verified

Follow-ups (not in this PR)

  • POST /api/auth/oauth/disconnect and its use case now have no caller. Left in place rather than removing an authenticated endpoint in a bugfix PR.
  • performDeleteCredential in credential orchestration also appears to have no remaining callers.
  • MemberRow's role track is 120px when the viewer can manage and 200px when not — a width difference across viewers, never within one list.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

greptile-apps[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
waleedlatif1 added 2 commits August 15, 2026 11:54
@waleedlatif1
fix(credentials): let workspace admins disconnect a teammate's OAuth …
91c9da5
…credential

Disconnecting an OAuth credential routed through POST /api/auth/oauth/disconnect,
a credential *user* operation scoped to the acting user's own `account` rows. A
workspace or org admin acting on a teammate's connection matched no accounts, so
the call returned `{ credentials: [] }` and the route still answered 200 — the UI
navigated away and the credential was still there. Not a denial, a silent no-op.

Route every type through the workspace-scoped credential delete instead, which
authorizes against credential admin and already resolves workspace and org admins
as derived credential admins for shared credential types.

That path only deleted the `credential` row, so send `oauth` through
`deleteCredentialRecord` — the manager that also tears down a credential's secret
source — and teach it to revoke the backing `account` grant once no credential
references it. Scoped by account id, not owner: the caller is already authorized
against the credential, and the grant belongs to the teammate.

Also make RoleLockTooltip layout-transparent. It wrapped locked controls in an
`inline-flex` div, which let the chip shrink to its label while unwrapped
controls stretched to the member row's fixed role track — so a credential's own
members list rendered Admin at two different widths. A `grid` wrapper stretches
like the unwrapped control, aligning the credential, secrets, and skills member
lists that share the row.
@waleedlatif1
refactor(credentials): consolidate credential deletion onto one path
d1d76bc
Follow-ups from review of the previous commit.

- Collapse the delete use case's remaining `service_account` carve-out. Both
  ternary arms reached the same `deleteConnectionCredential` tail, but the
  carve-out skipped `deleteCredentialRecord`'s Slack custom-bot guard — and
  custom bots are exactly the type it guards, so the single-delete surface
  could orphan a credential group that the batch path refuses to.
- Make `deleteOrphanedOAuthAccount` one conditional statement instead of a
  read then a write. `credential.accountId` is ON DELETE CASCADE, so a
  credential racing the gap would have been reaped by Postgres without
  `clearCredentialRefs` running, stranding its id in workflow state.
- Give oauth its own branch in `deleteCredentialRecord`, matching the shape
  the env types already use, rather than a conditional tail after the return.
- Point `handleReconnectCredential` at the shared helper; it carried its own
  copy of the same orphan-grant rule.
- Invalidate the OAuth connections query on credential delete. The removed
  disconnect hook owned that invalidation, and the detail page reads it. This
  also retires the hand-dispatched `oauth-credentials-updated` event from the
  delete path; the connect/reconnect path still dispatches it for its listener.
- Delete `useDisconnectOAuthService`, now callerless.
- Trim comments to the behavior rather than the bug that motivated it.
@vercel

vercel Bot commented Aug 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 15, 2026 9:01pm

Request Review

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@cursor

cursor Bot commented Aug 15, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes credential deletion and OAuth grant lifecycle (authz path + orphan account cleanup); scope is credentials/integrations with added regression tests, but mistaken grant deletion or auth gaps would affect shared integrations.

Overview
Fixes silent OAuth disconnect failures when a workspace admin disconnects a teammate’s integration: the UI now always calls workspace credential delete (credential-admin auth, including derived workspace admins) instead of the user-scoped OAuth disconnect API that could return success without removing the row.

Backend teardown is unified on deleteCredentialRecord for all types in the delete use case, so OAuth deletes clear refs and remove the credential row, then deleteOrphanedOAuthAccount drops the backing account grant only when no credential still references it (same helper reused on reconnect). Slack custom-bot deletes keep the credential-group guard on the shared path.

Client/cache: useDisconnectOAuthService is removed; credential delete invalidates OAuth connections queries. RoleLockTooltip uses a grid wrapper so locked role controls match unlocked row width in member lists.

Reviewed by Cursor Bugbot for commit d1d76bc. Configure here.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@greptile-apps

greptile-apps Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR consolidates credential disconnection onto the workspace-authorized deletion path and safely removes orphaned OAuth account grants while preserving shared grants.

  • Routes OAuth and service-account deletion through the canonical credential record manager and credential-admin authorization.
  • Adds an atomic orphan-account cleanup shared by deletion and reconnect flows.
  • Refreshes OAuth connection query state after deletion and removes the obsolete disconnect hook.
  • Applies the Slack credential-group guard consistently and aligns locked role-control widths.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete blocking or independently actionable non-blocking issues identified.

The consolidated path retains canonical credential-admin authorization, performs type-specific cleanup, protects shared OAuth grants with an atomic all-reference check, and refreshes the affected client caches.

Important Files Changed

Filename Overview
apps/sim/lib/credentials/deletion.ts Adds an atomic conditional deletion for OAuth account grants after all credential references are gone.
apps/sim/lib/credentials/orchestration/index.ts Extends canonical record deletion to clean up orphaned OAuth grants while retaining type-specific guards and environment cleanup.
apps/sim/lib/credentials/application/service-account.ts Consolidates all permitted credential types onto the canonical deletion manager without changing principal-specific type policy.
apps/sim/lib/credentials/draft-hooks.ts Reuses the atomic orphan-account helper when reconnecting a credential to a different OAuth account.
apps/sim/app/workspace/[workspaceId]/integrations/connected/[credentialId]/connected-credential-detail.tsx Routes every credential disconnect through the workspace-scoped credential deletion mutation.
apps/sim/hooks/queries/credentials.ts Invalidates the matching OAuth connections query after credential deletion.
apps/sim/components/permissions/role-lock.tsx Makes the locked-control tooltip wrapper stretch within its parent role track.

Sequence Diagram

sequenceDiagram
  participant UI as Credential detail UI
  participant API as DELETE /api/credentials/:id
  participant UC as Authorized delete use case
  participant Manager as Credential record manager
  participant DB as PostgreSQL
  UI->>API: Disconnect credential
  API->>UC: Principal + credential ID
  UC->>UC: Load canonical scope and require credential admin
  UC->>Manager: deleteCredentialRecord
  Manager->>DB: Clear credential references
  Manager->>DB: Delete credential row
  alt OAuth credential with account ID
    Manager->>DB: Delete account WHERE NOT EXISTS credential reference
  end
  Manager-->>UC: Authoritative deletion result
  UC-->>API: Audit and result
  API-->>UI: Success
  UI->>UI: Invalidate credential and OAuth connection queries
Loading

Reviews (1): Last reviewed commit: "refactor(credentials): consolidate crede..." | Re-trigger Greptile

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@waleedlatif1
waleedlatif1 merged commit 03ba95a into staging Aug 15, 2026
30 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@waleedlatif1
waleedlatif1 deleted the fix/credential-admin-disconnect branch August 15, 2026 21:09
@waleedlatif1 waleedlatif1 mentioned this pull request Aug 16, 2026
v0.8.3: sim cli, new tools, credential groups, splunk, finder-like files refactor, security hardening #6765
Merged

This branch was previously deployed

1 inactive deployment
Preview — d1d76bca Deployed Aug 15, 2026 by vercel[bot]
View deployment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@waleedlatif1
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.