feat(core): let apps report a connection auth failure with a reason - #25297
feat(core): let apps report a connection auth failure with a reason#25297abdulrahmancodes wants to merge 8 commits into
Conversation
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.
|
👋 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! |
App docs drift check
|
Greptile SummaryThis PR lets installed applications report that one of their own connections has failed authentication, including an optional human-readable reason.
Confidence Score: 5/5The 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
Sequence DiagramsequenceDiagram
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
Reviews (1): Last reviewed commit: "feat(core): let apps report a connection..." | Re-trigger Greptile |
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
🤖 PR Review
🛡️ Security Review✅ No high-severity vulnerabilities detected. 🚦 Auto-approve🙋 Manual review recommended for the following reason(s):
Automated pre-review — human approval still required. |
✅ Quality review · no findings
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 Reviewed against the |
varchar over text for authFailedReason, shared predicate for the request-user connection privacy rule, and a single object argument on reportConnectionAuthFailure.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
|
server-integration-test (1) failed on c298fd9, and the failure is not this PR's diff. The shard's workspace seeding died first ( Generated by Claude Code |
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
authFailedAtfor 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 withinvalid_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
reportAppConnectionAuthFailuremutation 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.authFailedReasoncolumn oncore.connectedAccount(generated 2.38.0 fast instance command, auto-registered), threaded through the app connections DTO, themyConnectedAccountsDTO, and the sharedAppConnectiontype. All three reconnect flows (app OAuth, connected-account reconnect, IMAP/SMTP/CalDAV) clear the reason together withauthFailedAt.reportConnectionAuthFailure(connectionId, reason?)SDK helper intwenty-sdk/logic-function, following the existing connections helpers;listConnections/getConnectionnow also returnauthFailedReason.authFailedAt, which apps can now actually set.Out of scope
token_rejectedprobe to call the new helper: the public apps pin the publishedtwenty-sdkfrom 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.Testing
Generated by Claude Code