Schedule and Service Permission Model#
Dokploy's schedule permission model applies a two-track authorization pattern based on the schedule's type. Schedules attached to an application or compose service go through a service-scoped check; standalone server-level and host-level schedules go through an org-role-gated check. All schedule permissions (read, create, update, delete) are classified as enterprise-only resources in the access-control layer β for static roles (owner, admin, member) the resource-level check is bypassed, and fine-grained enforcement via custom roles requires an enterprise license.
Schedule Types#
The scheduleType field determines which authorization branch is taken :
scheduleType | Attached to | Auth track |
|---|---|---|
application | applicationId | Service-scoped (checkServicePermissionAndAccess) |
compose | composeId | Service-scoped (checkServicePermissionAndAccess) |
server | serverId | Org-role check + org ownership of target server |
dokploy-server | organizationId | Org-role check + owner/admin only + blocked in Cloud |
checkServicePermissionAndAccess#
Defined in permission.ts, this is the central guard for all service-linked operations:
- Looks up the caller's member record in the active organization via
findMemberByUserId. - Runs the generic
checkPermissionwhich resolves the member's role (static:owner/admin/member, or custom enterprise role) and authorizes against the requested actions. - For non-owner/non-admin members, also verifies the
serviceIdis inmemberRecord.accessedServices. If not, throwsUNAUTHORIZED.
This means a regular member can pass the RBAC check but still be blocked if they haven't been explicitly granted access to the specific service.
Host / Server Schedule Checks#
For schedules without a service (scheduleType === "server" or "dokploy-server"), every mutating endpoint (create, update, delete, runManually) runs three sequential checks :
checkPermission(ctx, { schedule: ["create"|"update"|"delete"] })β base RBAC check.- Role guard:
findMemberByUserIdis called again; if the member's role is notowneroradmin, aFORBIDDENerror is thrown: "Only owners and admins can manage server-level schedules." - Org ownership check (
servertype only): loads the target server viafindServerByIdand comparestargetServer.organizationIdtoctx.session.activeOrganizationId; throwsUNAUTHORIZEDif mismatched.
dokploy-server schedules are additionally blocked entirely in the Cloud tier and are keyed to organizationId rather than serverId.
deployment.allByType Resolution Fix#
A prior bug (fixed in PR #4733) passed a raw scheduleId into checkServicePermissionAndAccess, which expects a service id, causing 401s for valid members. The fix in deployment.ts now resolves the schedule first:
- If
input.type === "schedule": fetch schedule β deriveserviceIdfromschedule.applicationId || schedule.composeIdβ call service check, or fall back to org ownership check forserverId-based schedules. - All other types: pass
input.iddirectly as a service id (previous behavior).
This pattern of resolving the schedule to its service before the permission check should be applied consistently whenever a schedule id is used to gate access to service-scoped resources.
Role Definitions#
The three static roles are defined in access-control.ts:
ownerRoleβ full access to all schedule actions.adminRoleβ identical to owner for schedules; differs only in org-deletion.memberRoleβ fullscheduleCRUD actions, but only within services inaccessedServices; cannot touchserverordokploy-serverschedules (those requireowner/admin).
For custom roles, schedule is an enterprise-only resource, so the resolveRole function checks for a valid license before loading the custom role.
Key Source Files#
| File | Purpose |
|---|---|
apps/dokploy/server/api/routers/schedule.ts | Schedule router β all CRUD and runManually endpoints with inline auth logic |
packages/server/src/services/permission.ts | checkPermission, checkServicePermissionAndAccess, findMemberByUserId |
packages/server/src/lib/access-control.ts | statements, role definitions, enterpriseOnlyResources |
apps/dokploy/server/api/routers/deployment.ts | allByType with schedule-to-service resolution |
Related PRs: