Skip to content

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

Merged
TheodoreSpeaks merged 33 commits into
stagingfrom
feat/credential-v2-api
Aug 15, 2026
Merged

feat(credentials): add v2 credential lifecycle APIs#6664
TheodoreSpeaks merged 33 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
  }
}

Behavior-preservation audit:

  • Restored legacy authorization, concealment, query normalization, lookup response, redirect, audit, analytics, and environment-credential behavior.
  • Isolated overlapping Shopify OAuth return destinations in signed per-flow state.
  • Escaped newly connected values rendered inside Shopify’s inline script.
  • Preserved audit and analytics for credential deletions committed before a later disconnect failure.
  • Added regression coverage for all nine behavior changes, documented in findings.txt.
  • Updated the application-operation migration skill to require compatibility baselines, failure sequencing, concurrent-flow, and rendering-boundary tests.
  • No database migration is required.

Validation:

  • bun run type-check: 23/23 tasks passed
  • bun run lint:check: 23/23 tasks passed
  • Focused credential and OAuth tests: 27 files, 151 tests passed
  • bun run check:audits: 26 audits passed
  • Block-registry compatibility checks passed
  • Migration skill validation passed

@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 15, 2026 3:52am

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
Changes authentication, authorization, OAuth connection state, and credential deletion side effects across public v2 APIs and browser OAuth callbacks; regressions could break connects, reconnects, or disconnect cleanup.

Overview
Adds a full v2 credentials lifecycle under /api/v2/credentials: provider discovery (OAuth and service-account fields), POST to verify and store service-account credentials (200 on idempotent replay, 201 on create), POST /connections for short-lived browser OAuth URLs (personal API keys only), and DELETE with credential-admin checks and reference cleanup. OpenAPI and shared 403 docs now include CREDENTIAL_ADMIN_ACCESS_REQUIRED.

OAuth browser entrypoints no longer trust mutable connect parameters alone. Legacy oauth2/authorize, Instagram authorize, and related internal routes delegate to createCredentialConnection / launchCredentialConnection and bind flows to draft IDs (cookies or signed Shopify state) so overlapping connects keep separate return URLs and draft processing. Internal accounts, oauth/connections, and oauth/disconnect routes move to the same application-layer use cases with standardized auth errors.

Docs and agent commands gain a “freeze observable behavior” section plus extra test categories (compatibility, failure sequencing, concurrency, rendering boundaries) for application-operation migrations.

Reviewed by Cursor Bugbot for commit 4430cd5. 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, consolidates authorization and credential operations behind shared application use cases, and hardens OAuth draft handling. The follow-up fixes preserve immutable connection intents, bind Shopify completion to signed per-flow state, and source reconnect audit names from canonical credential records.

  • Adds provider discovery, service-account creation, OAuth connection/reconnection, credential listing, and disconnection under /api/v2/credentials.
  • Introduces short-lived, user-bound OAuth drafts with conflict-safe retry behavior.
  • Preserves legacy authorization, response, audit, analytics, and callback behavior while centralizing credential operations.
  • Expands regression coverage for OAuth concurrency, rendering boundaries, failure sequencing, and API contracts.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains in the previously reported credential-draft, OAuth-flow, or reconnect-audit paths.

No blocking failure remains.

Important Files Changed

Filename Overview
apps/sim/lib/credentials/connect-draft.ts Conflict refreshes preserve the active draft ID and immutable target while permitting credential-ID-based reconnect retries after renames.
apps/sim/lib/credentials/application/save-credential-draft.ts Legacy draft creation now follows the same immutable-intent semantics as the v2 connection path.
apps/sim/lib/credentials/draft-hooks.ts Reconnect audit projection reads the current credential display name from the canonical credential record.
apps/sim/app/api/auth/oauth2/authorize/route.ts OAuth launch validates provider configuration and carries the exact authorized draft through the callback URL.
apps/sim/lib/oauth/shopify-state.ts Shopify state cryptographically binds the user, shop, draft, return destination, nonce, and expiry.
apps/sim/app/api/v2/credentials/connections/route.ts The v2 endpoint creates authorized, human-bound OAuth connection intents and returns the browser authorization URL.
apps/sim/app/api/v2/credentials/route.ts The v2 credentials collection route provides authorized listing and service-account creation through shared contracts and use cases.
apps/sim/app/api/v2/credentials/[credentialId]/route.ts Credential deletion uses the shared authorized lifecycle and presents the standard v2 response envelope.

Sequence Diagram

sequenceDiagram
  participant Client
  participant V2 as V2 Credentials API
  participant Drafts as Credential Draft Store
  participant Browser as Authenticated Browser
  participant Provider as OAuth Provider
  participant Callback as OAuth Callback
  participant Credentials as Credential Application Use Case

  Client->>V2: POST /credentials/connections
  V2->>Credentials: Authorize connection operation
  Credentials->>Drafts: Create or refresh immutable intent
  Drafts-->>V2: draftId and expiry
  V2-->>Client: authorizationUrl
  Client->>Browser: Open authorizationUrl
  Browser->>Drafts: Reauthorize exact user-bound draft
  Browser->>Provider: Start OAuth with per-flow state
  Provider->>Callback: Authorization callback
  Callback->>Drafts: Load exact active draft
  Callback->>Credentials: Create or reconnect credential
  Credentials-->>Browser: Redirect to credential-connected
Loading

Reviews (21): Last reviewed commit: "fix(credentials): prevent stale secrets ..." | 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
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

Comment thread apps/sim/app/api/auth/shopify/authorize/route.ts
@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 ae46594. Configure here.

…-api

# Conflicts:
#	scripts/check-api-validation-contracts.ts
…-api

# Conflicts:
#	apps/sim/app/api/credentials/route.ts
#	apps/sim/lib/credentials/queries.ts
@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 b413183. Configure here.

…-api

# Conflicts:
#	apps/sim/app/api/credentials/[id]/members/route.ts
#	apps/sim/app/api/credentials/[id]/route.ts
#	apps/sim/app/api/credentials/draft/route.ts
#	apps/sim/app/api/credentials/memberships/route.ts
#	apps/sim/app/api/credentials/route.ts
#	apps/sim/lib/credentials/application/authorization.ts
#	apps/sim/lib/credentials/orchestration/index.ts
#	scripts/check-api-validation-contracts.ts
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/lib/credentials/orchestration/credential-create.ts
Comment thread apps/sim/app/api/auth/oauth2/authorize/route.ts
@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 4430cd5. Configure here.

@TheodoreSpeaks
TheodoreSpeaks merged commit 6006870 into staging Aug 15, 2026
30 checks passed
@TheodoreSpeaks
TheodoreSpeaks deleted the feat/credential-v2-api branch August 15, 2026 04:47
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