feat(core): Add validation on workflow with dynamic credentials#26423
feat(core): Add validation on workflow with dynamic credentials#26423guillaumejacquart wants to merge 5 commits intomasterfrom
Conversation
…tivation Block workflow activation when dynamic (resolvable) credentials are used but no webhook trigger is present. Schedule and polling triggers cannot establish the user identity context required for dynamic credential resolution. Ref: https://linear.app/n8n/issue/IAM-149 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
cubic analysis
No issues found across 5 files
Linked issue analysis
Linked issue: IAM-354: Add validation on workflow with dynamic credentials
| Status | Acceptance criteria | Notes |
|---|---|---|
| ✅ | When a dynamic credential is configured and the workflow resolver is not set, publishing fails and a clear error indicates the dynamic credential requires a resolver in production. | Checks credentialsWithoutResolver and errors if no workflow resolver |
| ✅ | When a dynamic credential is configured and workflow triggers have no identity extractors, publishing fails and a clear error indicates the dynamic credential requires an identity extractor in production. | Checks for extractor hooks on triggers and errors when none found |
| ✅ | Resolver can be set either on the credential itself (resolverId) or as a workflow-level fallback (workflowSettings.credentialResolverId). | Uses c.resolverId and workflowSettings.credentialResolverId as fallback |
| ✅ | Both checks run at workflow activation time, before the workflow goes live (pre-publication validation). | workflow.service calls _validateDynamicCredentials during activation and throws on failure |
| ✅ | Disabled nodes are skipped when collecting credentials (disabled nodes should not cause validation to run for their credentials). | Collects credentialIds skipping node.disabled nodes |
| ✅ | Only resolvable credentials used by nodes are checked; non-resolvable credentials don't block activation. | Queries credentialsRepository for isResolvable:true and returns valid if none |
| ✅ | Errors surfaced should name the affected credentials (clear error messages indicating which credentials are problematic). | Constructs credNames from c.name and includes in error strings |
| ✅ | At least one trigger node must have contextEstablishmentHooks configured (identity extractor) for dynamic credential resolution. | Uses toExecutionContextEstablishmentHookParameter and checks hooks.length > 0 on trigger nodes |
Architecture diagram
sequenceDiagram
participant UI as Client / API
participant WS as WorkflowService
participant V as WorkflowValidationService
participant DB as CredentialsRepository
participant NT as NodeTypes
Note over UI,NT: Workflow Activation Flow (Pre-publication)
UI->>WS: activateWorkflow(workflowId)
WS->>WS: _detectWebhookConflicts()
WS->>WS: _validateNodes()
rect rgb(23, 37, 84)
WS->>V: NEW: validateDynamicCredentials(nodes, settings)
V->>V: Filter active nodes for credential IDs
alt Workflow contains credentials
V->>DB: CHANGED: find resolvable credentials (isResolvable=true)
DB-->>V: List of dynamic credentials (id, name, resolverId)
opt Has dynamic credentials
V->>V: NEW: Check for Resolver (cred.resolverId OR settings.fallback)
alt No Resolver Configured
V-->>WS: Return isValid: false (Missing Resolver)
else Resolver Valid
V->>NT: Get node type definitions for triggers
V->>V: NEW: Validate contextEstablishmentHooks (Identity Extractor)
alt No triggers have extractor hooks
V-->>WS: Return isValid: false (Missing Identity Extractor)
else Extractor Valid
V-->>WS: Return isValid: true
end
end
end
else No credentials
V-->>WS: Return isValid: true
end
end
alt Validation Failed
WS->>WS: Log warning & throw WorkflowValidationError
WS-->>UI: 400 Bad Request (Validation Error)
else Validation Passed
WS->>WS: Continue activation (Sub-workflow checks, etc.)
WS-->>UI: 200 OK / Workflow Active
end
…namic-credentials
This comment has been minimized.
This comment has been minimized.
…namic-credentials
|
|
||
| const resolvableCredentials = await this.credentialsRepository.find({ | ||
| where: { id: In([...credentialIds]), isResolvable: true }, | ||
| select: ['id', 'name', 'resolverId'], |
There was a problem hiding this comment.
i think i missed this: did we move the resolver to the credential itself?
| } | ||
|
|
||
| // A credential is covered if it has its own resolver OR the workflow has a defined resolver | ||
| const workflowResolverId = workflowSettings?.credentialResolverId; |
There was a problem hiding this comment.
i guess we only need to get const credentialsWithoutResolver = resolvableCredentials.filter((c) => !c.resolverId); if no workflow ersolver exists no?
| if (!workflowResolverId && credentialsWithoutResolver.length > 0) { | ||
| const credNames = credentialsWithoutResolver.map((c) => `"${c.name}"`).join(', '); | ||
| return { | ||
| isValid: false, |
There was a problem hiding this comment.
i think we should also check for extractor hook before returning so it's easier to debug for the workflow developer as they get all problems back
Summary
Adds pre-publication validation for workflows that use dynamic (resolvable) credentials, blocking activation when the required runtime dependencies are not configured.
Two checks are enforced:
set either on the credential itself (resolverId) or as a workflow-level fallback
(workflowSettings.credentialResolverId). If neither is present, activation is blocked with a
clear error naming the affected credentials.
configured. These hooks extract user identity from incoming requests (e.g. bearer tokens from
HTTP headers), which is required for the resolver to determine which credential values to return.
Triggers without hooks (e.g. schedule, polling) cannot establish this context.
Both checks run at workflow activation time, before the workflow goes live, preventing silent
runtime failures when dynamic credentials cannot be resolved.
Related Linear tickets, Github issues, and Community forum posts
https://linear.app/n8n/issue/IAM-354/add-validation-on-workflow-with-dynamic-credentials
Review / Merge checklist
release/backport(if the PR is an urgent fix that needs to be backported)