Skip to content

feat(credentials): add v2 credential lifecycle APIs - #6664

Open
TheodoreSpeaks wants to merge 23 commits into
stagingfrom
feat/credential-v2-api
Open

feat(credentials): add v2 credential lifecycle APIs#6664
TheodoreSpeaks wants to merge 23 commits into
stagingfrom
feat/credential-v2-api

Conversation

@TheodoreSpeaks

@TheodoreSpeaks TheodoreSpeaks commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Problem:

The V2 API could list stored credentials, but clients could not discover the complete set of credential methods, create service-account credentials, start or reconnect OAuth credentials safely, or disconnect credentials. OAuth still has to cross into an authenticated browser session, and the old browser entrypoint accepted mutable target parameters instead of an API-created connection intent.

Solution:

  • Put the complete lifecycle under /api/v2/credentials.
  • Discover all 52 OAuth services (53 provider IDs) and 23 service-account providers, including caller-specific availability and the exact fields needed to connect each one.
  • Verify and store service-account credentials through the existing credential table and encrypted secret pipeline; no new table or migration.
  • Create short-lived, user-bound OAuth connection drafts and return a browser URL. The browser requires login, reauthorizes the draft, and finishes at /oauth/credential-connected.
  • Support OAuth reconnection by credential ID while preserving the existing display name.
  • Disconnect OAuth or service-account credentials with credential-admin authorization and clear stored workflow, deployment, paused-run, knowledge-connector, and webhook references.
  • Keep all responses on the standard V2 { data } / { data, nextCursor } / { error } envelopes.

API shapes:

GET /api/v2/credentials?workspaceId={workspaceId}

{
  "data": [
    {
      "id": "credential-id",
      "type": "oauth",
      "displayName": "Work Gmail",
      "description": null,
      "providerId": "google-email",
      "accountId": "provider-account-id",
      "hasServiceAccountKey": false,
      "role": "admin",
      "createdAt": "2026-08-13T18:00:00.000Z",
      "updatedAt": "2026-08-13T18:00:00.000Z"
    }
  ],
  "nextCursor": null
}

GET /api/v2/credentials/providers?workspaceId={workspaceId}

OAuth entry:

{
  "type": "oauth",
  "serviceId": "salesforce",
  "name": "Salesforce",
  "description": "Connect to Salesforce CRM data and operations.",
  "providerFamily": "salesforce",
  "available": true,
  "supportsReconnect": true,
  "authorizationOptions": [
    { "providerId": "salesforce", "label": "Production" },
    { "providerId": "salesforce-sandbox", "label": "Sandbox" }
  ]
}

Service-account entry:

{
  "type": "service_account",
  "serviceId": "zoom-service-account",
  "providerId": "zoom-service-account",
  "name": "Zoom server-to-server app",
  "description": "Connect Zoom with a server-to-server app.",
  "providerFamily": "zoom",
  "available": true,
  "docsUrl": "https://docs.sim.ai/integrations/zoom-service-account",
  "requiresClientGeneratedCredentialId": false,
  "fields": [
    { "id": "clientId", "label": "Client ID", "placeholder": "Paste the client ID", "required": true, "secret": false, "multiline": false },
    { "id": "clientSecret", "label": "Client secret", "placeholder": "Paste the client secret", "required": true, "secret": true, "multiline": false },
    { "id": "orgId", "label": "Account ID", "placeholder": "Paste the account ID", "required": true, "secret": false, "multiline": false }
  ]
}

The endpoint returns { "data": [oauthEntry, serviceAccountEntry], "nextCursor": null }.

POST /api/v2/credentials

Creates a service-account credential. displayName is optional because providers may derive it from the verified account identity.

{
  "workspaceId": "workspace-id",
  "type": "service_account",
  "providerId": "zoom-service-account",
  "displayName": "Zoom automation",
  "clientId": "YOUR_CLIENT_ID",
  "clientSecret": "YOUR_CLIENT_SECRET",
  "orgId": "YOUR_ACCOUNT_ID"
}

Returns 201 { "data": credential } for a new credential or 200 { "data": credential } for an accepted replay. Secret fields are write-only and never returned.

POST /api/v2/credentials/connections

New OAuth credential:

{
  "workspaceId": "workspace-id",
  "providerId": "google-email",
  "displayName": "Work Gmail"
}

Reconnect an existing OAuth credential:

{
  "workspaceId": "workspace-id",
  "credentialId": "credential-id"
}
{
  "data": {
    "authorizationUrl": "https://www.sim.ai/api/auth/oauth2/authorize?draftId=draft-id",
    "expiresAt": "2026-08-13T18:30:00.000Z"
  }
}

This write requires a personal API key because the draft is bound to the human who must sign in in the browser. Workspace API keys can still list credentials and providers.

DELETE /api/v2/credentials/{credentialId}?workspaceId={workspaceId}

{
  "data": {
    "id": "credential-id",
    "deleted": true
  }
}

Validation:

  • bun run lint
  • bunx turbo run type-check --filter=sim --filter=@sim/auth
  • focused V2, application, OAuth, service-account, deletion, and visibility tests: 87 passed
  • bun run check:audits: 26 passed
  • bun run check:api-validation:strict
  • bun run check:openapi
  • OpenAPI regenerated and current: 7 documents, 139 operations, 141 contracts, 265 JSON Schema examples, and 113 runtime examples validated

@vercel

vercel Bot commented Aug 13, 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 14, 2026 10:05pm

Request Review

@TheodoreSpeaks
TheodoreSpeaks marked this pull request as ready for review August 13, 2026 18:17
@cursor

cursor Bot commented Aug 13, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Touches credential storage, OAuth token binding, and authorization across many providers; incorrect draft handling could mis-bind credentials or break reconnect flows.

Overview
Adds the full v2 credentials lifecycle under /api/v2/credentials: provider discovery, service-account create, OAuth connection/reconnect via short-lived drafts, and disconnect with reference cleanup. OpenAPI specs and docs are updated (including CREDENTIAL_ADMIN_ACCESS_REQUIRED on 403).

OAuth browser flows no longer rely on mutable query targets alone. Connection intents are created through createCredentialConnection / launchCredentialConnection; authorize routes for OAuth2, Instagram, Trello, and Shopify carry draftId (cookies or signed state) through to callbacks, with custom providers routed to their dedicated authorize URLs. Internal account/list/disconnect routes move to shared defineInternalJsonRoute use cases.

A minor docs fix removes a stray blank line in the LogRocket integration output table.

Reviewed by Cursor Bugbot for commit 7b74299. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds the complete v2 credential lifecycle, including provider discovery, service-account creation, OAuth connection drafts, reconnection, listing, and deletion. The latest follow-up correctly allows renamed reconnect targets to retry, but the retained draft presentation can make the resulting audit event identify the credential by its old name.

  • Adds public v2 credential routes and contracts with standardized response envelopes.
  • Introduces user-bound OAuth drafts and exact-draft callback processing across OAuth providers.
  • Adds service-account verification/storage and credential deletion cleanup.
  • Extends tests and generated OpenAPI documents for the new lifecycle.

Confidence Score: 4/5

The PR should not merge until reconnect audit events use the credential’s current display name after an active draft survives a rename.

Credential-ID-only reconnect retries preserve the original draft display name, and reconnect completion writes that stale value into the audit resource name and description.

Files Needing Attention: apps/sim/lib/credentials/connect-draft.ts and apps/sim/lib/credentials/draft-hooks.ts

Important Files Changed

Filename Overview
apps/sim/lib/credentials/connect-draft.ts Makes OAuth draft conflict refreshes immutable by target, but reconnect refreshes retain a stale display name that later appears in audit data.
apps/sim/lib/credentials/application/save-credential-draft.ts Correctly treats credential ID alone as reconnect intent while retaining display-name identity for new connections.
apps/sim/lib/credentials/draft-hooks.ts Reconnects update only account binding, but their audit event consumes the potentially stale draft display name.
apps/sim/lib/credentials/draft-processor.ts Processes exact drafts with authenticated user and provider constraints, preventing foreign-user draft completion.
apps/sim/app/api/auth/instagram/authorize/route.ts Carries supplied draft IDs into OAuth completion; downstream exact-draft processing enforces session-user and provider ownership.
apps/sim/app/api/v2/credentials/connections/route.ts Exposes authenticated OAuth connection and reconnection draft creation through the v2 response contract.

Reviews (15): Last reviewed commit: "fix(credentials): allow renamed reconnec..." | Re-trigger Greptile

Comment thread apps/sim/lib/credentials/connect-draft.ts Outdated
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/lib/credentials/connect-draft.ts Outdated
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit e4b09dc. Configure here.

@TheodoreSpeaks TheodoreSpeaks changed the title feat(credentials): add v2 OAuth connection APIs feat(credentials): add v2 credential lifecycle APIs Aug 13, 2026
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/lib/credentials/deletion.ts Outdated
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 7fcf26f. Configure here.

Comment thread apps/sim/lib/credentials/connect-draft.ts Outdated

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 036bfa0. Configure here.

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/lib/credentials/connect-draft.ts Outdated
Comment thread apps/sim/app/api/auth/instagram/authorize/route.ts
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/lib/credentials/application/save-credential-draft.ts Outdated

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 2cb08cd. Configure here.

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/lib/credentials/connect-draft.ts

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 147b161. Configure here.

Comment thread apps/sim/lib/auth/auth.ts
Comment thread apps/sim/lib/oauth/shopify-state.ts
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

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