This document covers the REST API architecture, resource management patterns, and authentication/authorization mechanisms in n8n. It explains how HTTP requests are processed, how resources like workflows and credentials are managed, and how access control is enforced.
The REST API layer lives almost entirely within packages/cli/src/. Child pages cover each major subsystem:
| Page | Title | Primary Files |
|---|---|---|
| 3.1 | Workflows API and Service Layer | workflows/workflows.controller.ts, workflows/workflow.service.ts |
| 3.2 | Credentials API and Security | credentials/credentials.controller.ts, credentials/credentials.service.ts |
| 3.3 | Execution Management API | executions/execution.service.ts, executions/execution.repository.ts |
| 3.4 | User Management and Authentication | controllers/users.controller.ts, controllers/auth.controller.ts |
| 3.5 | Project-Based Authorization and Sharing | services/project.service.ee.ts, @n8n/permissions |
| 3.6 | External Secrets Provider Integration | external-secrets/ |
| 3.7 | Source Control and Environment Management | environments-ee/source-control/ |
For information about workflow execution internals, see page 2. For user interface interactions, see page 6.
The n8n API is built using Express.js with a controller-service-repository pattern. Controllers handle HTTP requests, services contain business logic, and repositories manage database operations. The architecture enforces separation of concerns and enables testability.
REST API request flow through decorators and service layers
Sources: packages/cli/src/workflows/workflows.controller.ts75-101 packages/cli/src/workflows/workflow.service.ts70-96 packages/@n8n/db/src/repositories/workflow.repository.ts57-66
Controllers are defined using decorators from @n8n/decorators and follow a consistent pattern:
Decorator stack on a typical controller method
@RestController('/workflows') ā registers the Express router prefix@Get, @Post, @Patch, @Delete, @Put ā HTTP method and sub-path@ProjectScope('workflow:read') ā enforces per-resource scope check@GlobalScope('user:list') ā enforces instance-wide scope check@Licensed('feat:sharing') ā gates the route behind a license feature flag@Body, @Param, @Query ā bind and validate DTO arguments via class-validator / ZodSources: packages/cli/src/workflows/workflows.controller.ts75-101 packages/cli/src/controllers/users.controller.ts112-116 packages/cli/src/controllers/auth.controller.ts53-67
The requests.ts file defines strongly-typed request interfaces for all API endpoints:
| Request Type | Purpose | Key Properties |
|---|---|---|
AuthenticatedRequest | Base type for authenticated endpoints | user: User, authInfo |
AuthlessRequest | Unauthenticated endpoints | No user context |
ListQuery.Request | List endpoints with filtering | listQueryOptions: Options |
CredentialRequest.* | Credential operations | Credential-specific params |
WorkflowRequest.* | Workflow operations | Workflow-specific params |
UserRequest.* | User management | User-specific params |
Sources: packages/cli/src/requests.ts1-320
Workflows are managed through the WorkflowsController and WorkflowService, with sharing handled through the SharedWorkflow entity and project-based access control.
WorkflowsController route map and backing services
Sources: packages/cli/src/workflows/workflows.controller.ts103-846
Workflows are always created as inactive (active: false, activeVersionId: null). Activation and archiving are explicit state transitions:
| State | active | activeVersionId | Description |
|---|---|---|---|
| Draft | false | null | Newly created or deactivated |
| Active | true | <versionId> | Running, triggers registered |
| Archived | false | null | Immutable, cannot be edited |
| Deleted | ā | ā | Removed from DB |
Creation flow (POST /workflows ā WorkflowsController.create):
CreateWorkflowDto)active: false, generate versionIdWorkflowEntity, SharedWorkflow (owner role), WorkflowHistory entryscopes and checksumActivation flow (POST /workflows/:id/activate ā WorkflowService.activateWorkflow):
CollaborationServiceWorkflowHistory versionWebhookService.findWebhookConflicts)activeVersionId in DBActiveWorkflowManagerWorkflowPublishHistoryRepositorySources: packages/cli/src/workflows/workflows.controller.ts103-276 packages/cli/src/workflows/workflow.service.ts608-736 packages/cli/src/workflows/workflow.service.ts852-907
Core entities involved in workflow ownership and sharing
Workflow roles on SharedWorkflow.role:
workflow:owner ā full control: delete, share, transfer, activateworkflow:editor ā edit and execute; cannot delete, share, or transferFor full details on the sharing system, see page 3.5.
Sources: packages/cli/src/workflows/workflows.controller.ts708-788 packages/cli/src/workflows/workflow.service.ee.ts60-91 packages/@n8n/db/src/repositories/workflow.repository.ts57-66
Credentials are managed with encryption at rest, project-based access control, and field redaction for security. The system supports both personal and shared credentials.
CredentialsController route map and backing services
For credential encryption, redaction, and external secrets integration, see pages 3.2 and 3.6.
Sources: packages/cli/src/credentials/credentials.controller.ts1-389
Credentials are encrypted at rest and redacted when sent to the frontend:
| Operation | Encryption | Redaction | Use Case |
|---|---|---|---|
save() | ā Encrypts data field | - | Store new credential |
decrypt(includeRawData=false) | ā Decrypts | ā Redacts passwords | Display to UI |
decrypt(includeRawData=true) | ā Decrypts | - | Execute workflow |
redact() | - | ā Replaces with sentinel | Prepare for frontend |
unredact() | - | ā Restores from saved | Merge UI updates |
Sentinel Values:
CREDENTIAL_BLANKING_VALUE = '__n8n_redacted__' - Used for populated fieldsCREDENTIAL_EMPTY_VALUE = '' - Used for empty fieldsSources: packages/cli/src/credentials/credentials.service.ts365-384 packages/cli/src/credentials/credentials.service.ts484-570 packages/cli/src/constants.ts
Access to credentials is determined by project membership and scopes:
Credential Roles:
credential:owner - Full control in owning projectcredential:user - Read-only access for shared credentialsSources: packages/cli/src/credentials/credentials.service.ts616-625 packages/@n8n/permissions
The getCredentialsAUserCanUseInAWorkflow() method determines which credentials are available when editing a workflow:
credential:read onThis prevents users from adding credentials to workflows that the workflow cannot access.
Sources: packages/cli/src/credentials/credentials.service.ts225-256
User management encompasses user lifecycle, role assignment, and project relationships.
Controller map for user management and authentication
For full authentication flows (JWT, MFA, SSO, LDAP) and user lifecycle, see page 3.4.
Sources: packages/cli/src/controllers/users.controller.ts53-397 packages/cli/src/controllers/me.controller.ts29-297 packages/cli/src/controllers/auth.controller.ts38-271 packages/cli/src/controllers/invitation.controller.ts31-147 packages/cli/src/controllers/owner.controller.ts1-60
When deleting a user, their resources can be transferred to another user's project:
Sources: packages/cli/src/controllers/users.controller.ts224-343
The GET /users endpoint (backed by UsersController.listUsers) accepts UsersListFilterDto query parameters:
| Parameter | Type | Purpose | Example |
|---|---|---|---|
filter | JSON | Filter by fields | {"email":"[email protected]","isOwner":true} |
select[] | Array | Restrict returned fields | select[]=email&select[]=firstName |
take | Number | Limit results | take=10 |
skip | Number | Pagination offset | skip=20 |
sortBy[] | Array | Sort order | sortBy[]=role:desc |
expand[] | Array | Include relations | expand[]=projectRelations |
Supported filter fields: email, firstName, lastName, isOwner, mfaEnabled, isPending, ids, fullText.
Field visibility: Users without user:create global scope receive a reduced userBaseSchema payload for other users; full details (userDetailSchema) are returned only for the requesting user or by privileged roles.
Sources: packages/cli/src/controllers/users.controller.ts112-150 packages/cli/src/requests.ts31-51
n8n uses JWT-based authentication with cookie storage and a comprehensive scope-based authorization system. Full details are in page 3.4.
Token management:
n8n-auth HTTP-only, SameSite cookieInvalidAuthTokenRepositorycreateBodyKeyedRateLimiterSources: packages/cli/src/controllers/auth.controller.ts53-107
Scope enforcement: global vs. project-level
Global scopes (instance-wide, hasGlobalScope):
user:list, user:create, user:update, user:delete, user:resetPassword, user:changeRolecredential:list, credential:createworkflow:list, workflow:createproject:list, project:createResource scopes (per-resource, @ProjectScope):
workflow:read, workflow:update, workflow:delete, workflow:execute, workflow:publish, workflow:unpublish, workflow:share, workflow:movecredential:read, credential:update, credential:delete, credential:share, credential:moveproject:read, project:update, project:deleteFor the full scope definition list and RBAC role matrix, see page 3.5.
Sources: packages/cli/src/workflows/workflows.controller.ts358-366 packages/cli/src/controllers/users.controller.ts112-113 packages/@n8n/permissions
User scopes for a resource are computed by RoleService.combineResourceScopes, which unions:
user.role (e.g. global:owner, global:admin, global:member)ProjectRelation.role (e.g. project:admin, project:editor, project:viewer)SharedWorkflow.role / SharedCredentials.roleScope calculation chain
WorkflowService.getWorkflowScopes(user, workflowId) is the primary call-site ā it fetches the user's SharedWorkflow entries and calls RoleService.combineResourceScopes('workflow', ...).
Sources: packages/cli/src/workflows/workflow.service.ts936-944 packages/cli/src/services/role.service.ts
The list query system provides standardized filtering, pagination, sorting, and field selection across all list endpoints. It is attached as the listQueryMiddleware function in packages/cli/src/middlewares/.
The middleware parses raw query string parameters into a typed ListQuery.Options object attached to req.listQueryOptions:
| Input Param | Parsed As | Type |
|---|---|---|
filter={"name":"foo"} | options.filter | Record<string, unknown> |
take=20 | options.take | number |
skip=40 | options.skip | number |
select[]=id&select[]=name | options.select | Record<string, true> |
sortBy[]=updatedAt:desc | options.sortBy | string |
Additional per-endpoint booleans are passed as separate query params: includeScopes, includeFolders, onlySharedWithMe, includeData.
Repositories implement access-aware query methods. For example, WorkflowRepository exposes:
getManyAndCountWithSharingSubquery(user, sharingOptions, listQueryOptions) ā subquery-based access filtergetWorkflowsAndFoldersWithCountWithSharingSubquery(...) ā combined workflow + folder union queryWorkflowService.getMany orchestrates these with post-processing steps: adding ownership metadata (addOwnedByAndSharedWith), computing scopes (addUserScopes), merging folder results, and stripping the internal shared field before returning.
Sources: packages/cli/src/requests.ts31-51 packages/cli/src/workflows/workflow.service.ts98-201 packages/@n8n/db/src/repositories/workflow.repository.ts178-264
Resources (workflows and credentials) can be shared with projects and transferred between projects. Full sharing and RBAC details are in page 3.5.
workflow:share scope to add sharees; workflow:unshare to removerole: 'workflow:editor'; owner role stays with the source project@Licensed('feat:sharing')PUT /workflows/:id/transfer ā EnterpriseWorkflowService.transferWorkflow:
workflow:move on source, workflow:create on destinationActiveWorkflowManager if currently activeSharedWorkflow ownership to destination projectEnterpriseCredentialsServiceActiveWorkflowManager if it was activeSources: packages/cli/src/workflows/workflows.controller.ts708-806 packages/cli/src/workflows/workflow.service.ee.ts60-91 packages/cli/src/workflows/workflow.service.ee.ts217-355
All API requests and responses use strongly-typed interfaces defined in packages/cli/src/requests.ts.
Request type namespace map (packages/cli/src/requests.ts)
Key request namespaces:
| Namespace | Members | File |
|---|---|---|
WorkflowRequest.* | Create, Update, Get, GetMany, ManualRun, Activate, Deactivate, Share | packages/cli/src/workflows/workflow.request.ts |
CredentialRequest.* | Get, GetMany, Update, Test, Share, Transfer, ForWorkflow | packages/cli/src/requests.ts66-112 |
UserRequest.* | Get, Delete, InviteResponse, PasswordResetLink | packages/cli/src/requests.ts126-153 |
ListQuery.* | Request, Params, Options | packages/cli/src/requests.ts31-51 |
Controllers return plain objects serialised to JSON. The three standard shapes:
{ ...resource, scopes: Scope[], checksum?: string }{ data: Resource[], count: number } (count is pre-pagination total){ success: true } or trueThe scopes field is computed at response time by WorkflowService.getWorkflowScopes or the equivalent credential method, so the frontend knows which actions to enable.
Sources: packages/cli/src/requests.ts1-322 packages/cli/src/workflows/workflow.request.ts1-95 packages/cli/src/workflows/workflows.controller.ts272-276
Services contain business logic and orchestrate between controllers and repositories.
Service dependency map for workflow and credential resources
Service categories:
| Category | Services | Responsibility |
|---|---|---|
| Core CRUD | WorkflowService, CredentialsService, UserService | Primary resource operations |
| Enterprise | EnterpriseWorkflowService, EnterpriseCredentialsService | Sharing, transfer (EE features) |
| Finder | WorkflowFinderService, CredentialsFinderService | Access-controlled DB queries |
| Supporting | ProjectService, RoleService, OwnershipService | Cross-cutting: scopes, ownership |
Sources: packages/cli/src/workflows/workflow.service.ts70-96 packages/cli/src/workflows/workflow.service.ee.ts42-58 packages/cli/src/credentials/credentials.service.ts1-70
The API uses custom error classes that map to HTTP status codes:
| Error Class | HTTP Status | Use Case |
|---|---|---|
BadRequestError | 400 | Invalid input, validation failures |
UnauthorizedError | 401 | Missing or invalid authentication |
ForbiddenError | 403 | Insufficient permissions |
NotFoundError | 404 | Resource not found |
ConflictError | 409 | Resource conflict |
InternalServerError | 500 | Unexpected server errors |
Custom Errors:
AuthError - Authentication failures with optional MFA codeInvalidMfaCodeError - Invalid MFA codeTransferWorkflowError - Workflow transfer failuresTransferCredentialError - Credential transfer failuresRefresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.