Skip to content

feat(core): let apps report a connection auth failure with a reason - #25297

Open
abdulrahmancodes wants to merge 8 commits into
mainfrom
claude/cool-pascal-5ay683
Open

feat(core): let apps report a connection auth failure with a reason#25297
abdulrahmancodes wants to merge 8 commits into
mainfrom
claude/cool-pascal-5ay683

Conversation

@abdulrahmancodes

@abdulrahmancodes abdulrahmancodes commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Platform follow-up agreed in the design discussion on #25240: the connection row in settings is the right generic place to surface a dead credential, but nothing ever set authFailedAt for providers whose tokens the platform never refreshes. A revoked Slack bot token, for example, only fails at call time inside the app, so the row kept showing Connected while every call died with invalid_auth. The reconnect UI (red "Reconnect needed" status plus the Reconnect button on the connection detail page) already existed and simply never triggered for these providers.

What this adds

  • reportAppConnectionAuthFailure mutation on the app connections resolver: an app can mark one of its own connections as auth-failed, with an optional human-readable reason (capped at 1000 chars). Scoping matches reading a connection: the calling app's own rows only, same workspace, and a request user can only act on their own user-visibility credentials.
  • authFailedReason column on core.connectedAccount (generated 2.38.0 fast instance command, auto-registered), threaded through the app connections DTO, the myConnectedAccounts DTO, and the shared AppConnection type. All three reconnect flows (app OAuth, connected-account reconnect, IMAP/SMTP/CalDAV) clear the reason together with authFailedAt.
  • reportConnectionAuthFailure(connectionId, reason?) SDK helper in twenty-sdk/logic-function, following the existing connections helpers; listConnections/getConnection now also return authFailedReason.
  • Settings: the connection detail page shows an "Auth failure reason" row. The existing status pill and Reconnect button needed no changes; they key off authFailedAt, which apps can now actually set.

Out of scope

  • Wiring the Slack app's token_rejected probe to call the new helper: the public apps pin the published twenty-sdk from npm, so the app adopts this in its own PR once the next SDK version ships. Until then the app keeps its own settings-tab callouts from feat(slack): surface broken connections and failed auto-link sweeps in the settings tab #25240.
  • The synchronous pre-persist connection validation hook (failing the connect flow when a claim is already held) stays a separate proposal.

Testing

  • Server, SDK, and frontend typechecks clean; diff lint clean.
  • New SDK spec for the helper (mutation shape, optional reason, error propagation); existing connections and applications-settings suites pass.
  • Metadata codegen regenerated against a locally running server with the new schema.

Generated by Claude Code

Review in cubic

Providers whose tokens the platform never refreshes (Slack bot tokens, for
example) had no path that set authFailedAt: a revoked token failed only at
call time inside the app, while the settings connection row kept showing
Connected. The reconnect UI already existed and simply never triggered.

Add an authFailedReason column on connectedAccount plus a
reportAppConnectionAuthFailure mutation on the app connections resolver,
scoped to the calling app's own connections with the same privacy rule as
reading them. The reconnect flows clear the reason together with
authFailedAt. Expose the reason through the app connections DTO, the
myConnectedAccounts DTO, the shared AppConnection type, and a new
reportConnectionAuthFailure SDK helper, and show it on the connection
detail page in settings.
@twenty-ci-bot-public

Copy link
Copy Markdown

👋 Thanks for contributing to Twenty!

Your PR has been set to draft while you work on it. Once you're done, mark it as Ready for review and our automated checks will run.

Looking forward to your contribution!

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

App docs drift check

Change Docs page Status Suggested fix
New reportConnectionAuthFailure({ connectionId, reason? }) exported from twenty-sdk/logic-function packages/twenty-docs/developers/extend/apps/logic/connections.mdx ✅ already updated in this PR
New authFailedReason: string | null field on AppConnection packages/twenty-docs/developers/extend/apps/logic/connections.mdx ✅ already updated in this PR
authFailedAt description expanded to cover app-reported failures packages/twenty-docs/developers/extend/apps/logic/connections.mdx ✅ already updated in this PR

@greptile-apps

greptile-apps Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR lets installed applications report that one of their own connections has failed authentication, including an optional human-readable reason.

  • Adds a workspace- and application-scoped GraphQL mutation and SDK helper for reporting failures.
  • Persists and exposes auth-failure reasons through server, shared, SDK, and frontend contracts.
  • Clears the reason alongside reconnect state across OAuth and direct-protocol reconnect flows.
  • Displays the reported reason on the application connection detail page.

Confidence Score: 5/5

The PR appears safe to merge, with connection scoping, persistence, SDK contracts, reconnect cleanup, and settings display aligned.

The new mutation applies the same application, workspace, provider, and user-visibility constraints as connection reads; the schema migration and cross-package field shapes agree, and every affected reconnect flow clears both failure fields together.

Important Files Changed

Filename Overview
packages/twenty-server/src/engine/core-modules/application/connection-provider/connections/services/application-connection-auth-failure.service.ts Adds application-, workspace-, provider-, and user-scoped persistence of connection authentication failures.
packages/twenty-server/src/engine/core-modules/application/connection-provider/connections/application-connections.resolver.ts Exposes the authenticated metadata mutation and forwards token-bound caller context to the failure service.
packages/twenty-server/src/database/commands/upgrade-version-command/2-38/2-38-instance-command-fast-1788445931849-add-auth-failed-reason-to-connected-account.ts Adds a reversible nullable text column consistent with the connected-account entity.
packages/twenty-sdk/src/sdk/logic-function/connections/report-connection-auth-failure.ts Adds the logic-function runtime helper with the expected metadata GraphQL mutation shape and error propagation.
packages/twenty-server/src/engine/metadata-modules/connected-account/entities/connected-account.entity.ts Adds the nullable persisted auth-failure reason with the matching upgrade annotation.
packages/twenty-front/src/pages/settings/applications/SettingsApplicationConnectionDetail.tsx Displays the optional authentication failure reason on the existing connection detail surface.

Sequence Diagram

sequenceDiagram
  participant App as Installed app
  participant SDK as Logic-function SDK
  participant API as Metadata GraphQL API
  participant DB as Connected account
  participant UI as Connection settings
  App->>SDK: reportConnectionAuthFailure(id, reason)
  SDK->>API: reportAppConnectionAuthFailure
  API->>API: Validate app, workspace, and user visibility
  API->>DB: Set authFailedAt and authFailedReason
  DB-->>UI: Return failed connection state
  UI-->>UI: Show reconnect status and failure reason
  UI->>API: Complete reconnect flow
  API->>DB: Clear authFailedAt and authFailedReason
Loading

Reviews (1): Last reviewed commit: "feat(core): let apps report a connection..." | Re-trigger Greptile

@mintlify

mintlify Bot commented Sep 3, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
twenty 🟢 Ready View Preview Sep 3, 2026, 7:11 PM

💡 Tip: Enable Automations to automatically generate PRs for you.

@twenty-ci-bot-public

twenty-ci-bot-public Bot commented Sep 3, 2026

Copy link
Copy Markdown

🤖 PR Review

Check Result
🔍 Build safety ⏭️ skipped — external-only
🛡️ Security ✅ passed
🧭 Triage ⏭️ skipped — external-only
📐 Quality ✅ passed
🚦 Auto-approve 👀 needs review — Touches high-blast-radius paths: Auth / permissions code

🛡️ Security Review

No high-severity vulnerabilities detected.


🚦 Auto-approve

🙋 Manual review recommended for the following reason(s):

  • Touches high-blast-radius paths: Auth / permissions code

  • Complexity is medium

  • 🧠 Complexity: medium

  • 📏 Size: +444 / -48 lines across 33 file(s)

  • High-blast-radius paths: packages/twenty-server/src/engine/core-modules/auth/services/update-connected-ac…


View details

Automated pre-review — human approval still required.

@twenty-ci-bot-public

twenty-ci-bot-public Bot commented Sep 3, 2026

Copy link
Copy Markdown

✅ Quality review · no findings

Safe to merge — no findings; all prior nits and bot-flagged issues are fixed or human-answered

High-level — Additive core column gated by @WasIntroducedInUpgrade plus a 2.38.0 fast instance command keeps runtime writes deploy-safe, reusing the connections module's existing auth/privacy seam and one twenty-shared AppConnection shape across FE/BE/SDK
Low-level — Both cubic concurrency findings and the three carried-over nits are fixed, the DTO validators match file convention, the reconnect-race guard and full-scope re-fetch are sound, and the remaining comments are genuine provider/concurrency WHYs


Reviewed against the pr-review standard — high-level then low-level. Advisory; human review still required. Run details.

varchar over text for authFailedReason, shared predicate for the
request-user connection privacy rule, and a single object argument on
reportConnectionAuthFailure.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Scope the update on lastCredentialsRefreshedAt so a report describing the
pre-reconnect token matches zero rows instead of resurrecting a cleared
failure, and treat zero affected rows with a missing row as NotFound.
The msw handlers answer MyConnectedAccounts by operation name, so the
query's new field was missing from their responses and Apollo dropped the
result as incomplete, breaking the workflow email action story.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 12 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/twenty-server/src/engine/core-modules/application/connection-provider/connections/utils/is-connection-hidden-from-request-user.util.ts">

<violation number="1" location="packages/twenty-server/src/engine/core-modules/application/connection-provider/connections/utils/is-connection-hidden-from-request-user.util.ts:15">
P1: When `requestUserWorkspaceId` is absent, this guard allows every user-scoped connection instead of enforcing ownership. Application-only tokens legitimately have no user workspace ID, so an app or cron-triggered function can report another user’s credential as auth-failed by ID. Distinguish trusted background execution from application-only requests and deny user-scoped rows unless the caller’s user workspace matches.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Without ResolverValidationPipe the MaxLength cap on the failure reason
was decorative.

Copy link
Copy Markdown
Contributor Author

server-integration-test (1) failed on c298fd9, and the failure is not this PR's diff. The shard's workspace seeding died first (DataSeedWorkspaceCommand: FlatEntityMapsException: Could not find flat entity with universal identifier 124e82e5-b98e-48a7-bbdf-1b7442c010d4, an id generated at runtime that exists nowhere in the repo), and every test failure downstream is the same seeding symptom: "Unable to build actor metadata - no valid actor information found in auth context" in nested-relation-queries and admin-panel-application-registration-stats, suites this PR does not touch (the diff adds a connectedAccount column, an app-connections mutation, and SDK/frontend plumbing; no seeding, flat-entity-map, or actor code). I do not have permission to re-run the job from this session; a re-run of the shard should clear it.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant