|
| 1 | +--- |
| 2 | +sidebar_position: 4 |
| 3 | +title: Namespace, Auth, And Worker Registration |
| 4 | +description: Reference for server namespace resolution, role-scoped authentication, and worker registration contracts. |
| 5 | +tags: |
| 6 | + - server |
| 7 | + - namespaces |
| 8 | + - authentication |
| 9 | + - worker-protocol |
| 10 | +keywords: |
| 11 | + - Durable Workflow namespace auth |
| 12 | + - role scoped server tokens |
| 13 | + - worker registration contract |
| 14 | + - X-Namespace |
| 15 | +--- |
| 16 | + |
| 17 | +# Namespace, Auth, And Worker Registration |
| 18 | + |
| 19 | +Use this reference when provisioning a standalone server, issuing automation |
| 20 | +credentials, or implementing a worker runtime. The server has three separate |
| 21 | +contracts that must line up before work can flow: |
| 22 | + |
| 23 | +- the request names a namespace through `X-Namespace`, `?namespace=`, or the |
| 24 | + server default namespace |
| 25 | +- the credential has the role required by the route family |
| 26 | +- workers register the same namespace, task queue, runtime, type keys, and |
| 27 | + capacity that workflow starts and task polls use |
| 28 | + |
| 29 | +## Request Authority |
| 30 | + |
| 31 | +Durable Workflow treats namespace, auth role, and protocol version as request |
| 32 | +authority. Do not infer them from workflow ids, task ids, or display labels. |
| 33 | + |
| 34 | +| Request family | Required credential role | Required version header | Namespace source | |
| 35 | +| --- | --- | --- | --- | |
| 36 | +| Discovery `GET /api/cluster/info` | `worker`, `operator`, or `admin` | none | optional `X-Namespace` for context | |
| 37 | +| Namespace list/describe | `operator` or `admin` | `X-Durable-Workflow-Control-Plane-Version: 2` | route target or request context | |
| 38 | +| Namespace create/update/storage policy | `admin` | `X-Durable-Workflow-Control-Plane-Version: 2` | route target or request body | |
| 39 | +| Workflow, schedule, task queue, bridge adapter, worker visibility | `operator` or `admin` | `X-Durable-Workflow-Control-Plane-Version: 2` | `X-Namespace`, `?namespace=`, then default | |
| 40 | +| System passes and storage tests | `admin` | `X-Durable-Workflow-Control-Plane-Version: 2` | `X-Namespace`, `?namespace=`, then default | |
| 41 | +| Worker registration, polling, heartbeats, completion | `worker` | `X-Durable-Workflow-Protocol-Version: 1.0` | `X-Namespace`, `?namespace=`, then default | |
| 42 | + |
| 43 | +The server checks the route role before namespace existence on role-gated |
| 44 | +endpoints. A wrong-role token receives an auth failure instead of a namespace |
| 45 | +existence signal. After the role and version checks pass, namespace-scoped |
| 46 | +routes reject unknown namespaces with `reason: "namespace_not_found"`. |
| 47 | + |
| 48 | +## Auth Roles |
| 49 | + |
| 50 | +Token auth is the default production path: |
| 51 | + |
| 52 | +```bash |
| 53 | +DW_AUTH_DRIVER=token |
| 54 | +DW_WORKER_TOKEN=worker-secret |
| 55 | +DW_OPERATOR_TOKEN=operator-secret |
| 56 | +DW_ADMIN_TOKEN=admin-secret |
| 57 | +``` |
| 58 | + |
| 59 | +If a deployment uses one shared `DW_AUTH_TOKEN`, that token effectively has all |
| 60 | +route permissions. Prefer role-scoped tokens for production so a worker process |
| 61 | +cannot mutate namespaces or run system maintenance passes. |
| 62 | + |
| 63 | +The same role split exists for signature auth: |
| 64 | + |
| 65 | +```bash |
| 66 | +DW_AUTH_DRIVER=signature |
| 67 | +DW_WORKER_SIGNATURE_KEY=worker-signature-secret |
| 68 | +DW_OPERATOR_SIGNATURE_KEY=operator-signature-secret |
| 69 | +DW_ADMIN_SIGNATURE_KEY=admin-signature-secret |
| 70 | +``` |
| 71 | + |
| 72 | +`DW_AUTH_DRIVER=none` is for local development only. It removes the auth |
| 73 | +boundary from every route and should never be exposed outside a trusted local |
| 74 | +network. |
| 75 | + |
| 76 | +## Namespace Contract |
| 77 | + |
| 78 | +The bootstrap process seeds the default namespace. Set |
| 79 | +`DW_DEFAULT_NAMESPACE` when omitted namespace headers should resolve somewhere |
| 80 | +other than `default`: |
| 81 | + |
| 82 | +```bash |
| 83 | +DW_DEFAULT_NAMESPACE=default |
| 84 | +``` |
| 85 | + |
| 86 | +Create every tenant or environment namespace before directing clients or |
| 87 | +workers at it: |
| 88 | + |
| 89 | +```bash |
| 90 | +curl -sS -X POST "$DURABLE_WORKFLOW_SERVER_URL/api/namespaces" \ |
| 91 | + -H "Authorization: Bearer $DW_ADMIN_TOKEN" \ |
| 92 | + -H "X-Durable-Workflow-Control-Plane-Version: 2" \ |
| 93 | + -H "Content-Type: application/json" \ |
| 94 | + -d '{ |
| 95 | + "name": "orders-prod", |
| 96 | + "description": "production order workflows", |
| 97 | + "retention_days": 90 |
| 98 | + }' |
| 99 | +``` |
| 100 | + |
| 101 | +Namespace names are normalized to lowercase and may contain letters, numbers, |
| 102 | +dot, underscore, and dash. They are unique after normalization. For example, |
| 103 | +creating `Production` and then `production` is a conflict with |
| 104 | +`reason: "namespace_already_exists"`. |
| 105 | + |
| 106 | +A normal workflow start names the namespace with `X-Namespace`: |
| 107 | + |
| 108 | +```bash |
| 109 | +curl -sS -X POST "$DURABLE_WORKFLOW_SERVER_URL/api/workflows" \ |
| 110 | + -H "Authorization: Bearer $DW_OPERATOR_TOKEN" \ |
| 111 | + -H "X-Namespace: orders-prod" \ |
| 112 | + -H "X-Durable-Workflow-Control-Plane-Version: 2" \ |
| 113 | + -H "Content-Type: application/json" \ |
| 114 | + -d '{ |
| 115 | + "workflow_type": "orders.fulfillment", |
| 116 | + "workflow_id": "order-1001", |
| 117 | + "task_queue": "orders", |
| 118 | + "input": ["order-1001"] |
| 119 | + }' |
| 120 | +``` |
| 121 | + |
| 122 | +Control-plane reads, workflow commands, schedule operations, search-attribute |
| 123 | +operations, task-queue visibility, and worker visibility use that same |
| 124 | +namespace context. Namespace administration routes themselves are the |
| 125 | +exception: they target the namespace in the route or request body and do not |
| 126 | +require that namespace to already exist before create or describe can run. |
| 127 | + |
| 128 | +## Worker Registration Contract |
| 129 | + |
| 130 | +Every worker process must register before polling. Registration is namespaced, |
| 131 | +so the tuple `(namespace, worker_id)` identifies the worker record. The |
| 132 | +registered `task_queue` must match future poll requests for that worker id. |
| 133 | + |
| 134 | +```bash |
| 135 | +curl -sS -X POST "$DURABLE_WORKFLOW_SERVER_URL/api/worker/register" \ |
| 136 | + -H "Authorization: Bearer $DW_WORKER_TOKEN" \ |
| 137 | + -H "X-Namespace: orders-prod" \ |
| 138 | + -H "X-Durable-Workflow-Protocol-Version: 1.0" \ |
| 139 | + -H "Content-Type: application/json" \ |
| 140 | + -d '{ |
| 141 | + "worker_id": "py-orders-1", |
| 142 | + "task_queue": "orders", |
| 143 | + "runtime": "python", |
| 144 | + "sdk_version": "0.2.0", |
| 145 | + "build_id": "orders-worker-2026-04-22", |
| 146 | + "supported_workflow_types": ["orders.fulfillment"], |
| 147 | + "workflow_definition_fingerprints": { |
| 148 | + "orders.fulfillment": "sha256:definition-fingerprint" |
| 149 | + }, |
| 150 | + "supported_activity_types": ["payments.capture"], |
| 151 | + "max_concurrent_workflow_tasks": 10, |
| 152 | + "max_concurrent_activity_tasks": 50 |
| 153 | + }' |
| 154 | +``` |
| 155 | + |
| 156 | +| Field | Required | Contract | |
| 157 | +| --- | --- | --- | |
| 158 | +| `worker_id` | no | Stable process identity. The server generates one when omitted, but long-running runtimes should set it for logs and task queue diagnostics. | |
| 159 | +| `task_queue` | yes | Queue this worker polls. Poll requests for a different queue fail with `reason: "task_queue_mismatch"`. | |
| 160 | +| `runtime` | yes | One of `php`, `python`, `typescript`, `go`, or `java`. | |
| 161 | +| `sdk_version` | no | Runtime SDK version shown in worker visibility and diagnostics. | |
| 162 | +| `build_id` | no | Deploy/build identity used by task queue build-id visibility. | |
| 163 | +| `supported_workflow_types` | no | Workflow type keys this worker can replay. Empty means no workflow-type filter. | |
| 164 | +| `workflow_definition_fingerprints` | no | Per-workflow deterministic definition fingerprints. Active re-registration with a changed fingerprint is rejected. | |
| 165 | +| `supported_activity_types` | no | Activity type keys this worker can execute. Empty means no activity-type filter. | |
| 166 | +| `max_concurrent_workflow_tasks` | no | Advertised local workflow-task slots. Defaults to `100`; minimum `1`. | |
| 167 | +| `max_concurrent_activity_tasks` | no | Advertised local activity-task slots. Defaults to `100`; minimum `1`. | |
| 168 | + |
| 169 | +Active re-registration with the same worker id is allowed when the advertised |
| 170 | +definition fingerprints are unchanged. If a running worker changes workflow |
| 171 | +code for an already advertised type, it must restart with a new `worker_id`; |
| 172 | +otherwise registration fails with `reason: "workflow_definition_changed"`. |
| 173 | + |
| 174 | +## Polling And Visibility |
| 175 | + |
| 176 | +Worker poll requests must use the same namespace, worker id, and task queue |
| 177 | +that registration used: |
| 178 | + |
| 179 | +```bash |
| 180 | +curl -sS -X POST "$DURABLE_WORKFLOW_SERVER_URL/api/worker/workflow-tasks/poll" \ |
| 181 | + -H "Authorization: Bearer $DW_WORKER_TOKEN" \ |
| 182 | + -H "X-Namespace: orders-prod" \ |
| 183 | + -H "X-Durable-Workflow-Protocol-Version: 1.0" \ |
| 184 | + -H "Content-Type: application/json" \ |
| 185 | + -d '{ |
| 186 | + "worker_id": "py-orders-1", |
| 187 | + "task_queue": "orders", |
| 188 | + "timeout_seconds": 30 |
| 189 | + }' |
| 190 | +``` |
| 191 | + |
| 192 | +Operators can inspect the same registration state through control-plane |
| 193 | +visibility: |
| 194 | + |
| 195 | +```bash |
| 196 | +curl -sS "$DURABLE_WORKFLOW_SERVER_URL/api/task-queues/orders" \ |
| 197 | + -H "Authorization: Bearer $DW_OPERATOR_TOKEN" \ |
| 198 | + -H "X-Namespace: orders-prod" \ |
| 199 | + -H "X-Durable-Workflow-Control-Plane-Version: 2" | jq '.pollers, .admission' |
| 200 | +``` |
| 201 | + |
| 202 | +Task queue visibility is the first place to check when workers receive no |
| 203 | +tasks. It distinguishes missing workers from queue mismatches, unsupported |
| 204 | +workflow/activity type filters, saturated worker slots, server active-lease |
| 205 | +caps, dispatch-rate caps, and query-task backpressure. |
| 206 | + |
| 207 | +## Error Surface |
| 208 | + |
| 209 | +Automation should branch on named reasons rather than prose messages. |
| 210 | + |
| 211 | +| Reason | Where | Meaning | Operator action | |
| 212 | +| --- | --- | --- | --- | |
| 213 | +| `missing_control_plane_version` | control-plane route | The request omitted `X-Durable-Workflow-Control-Plane-Version: 2`. | Add the version header or upgrade the client profile. | |
| 214 | +| `missing_protocol_version` | worker route | The request omitted `X-Durable-Workflow-Protocol-Version: 1.0`. | Fix the worker client or SDK version negotiation. | |
| 215 | +| `namespace_not_found` | namespace-scoped route | The namespace from `X-Namespace`, query string, or server default does not exist. | Create the namespace or correct the client namespace. | |
| 216 | +| `namespace_already_exists` | `POST /api/namespaces` | A normalized namespace name already exists. | Reuse it or choose a distinct name. | |
| 217 | +| `task_queue_mismatch` | worker poll route | A worker id registered for one queue attempted to poll another. | Restart with a new worker id or poll the registered queue. | |
| 218 | +| `workflow_definition_changed` | `POST /api/worker/register` | Active worker id tried to advertise changed workflow fingerprints. | Restart the changed process with a new worker id. | |
| 219 | +| `validation_failed` | any JSON route | A field is missing, malformed, too large, or outside allowed bounds. | Read `errors` or `validation_errors` and correct the payload. | |
| 220 | + |
| 221 | +## See Also |
| 222 | + |
| 223 | +- [Server API Reference](/docs/2.0/polyglot/server-api-reference) |
| 224 | +- [Worker Protocol](/docs/2.0/polyglot/worker-protocol) |
| 225 | +- [Task Queue Admission](/docs/2.0/polyglot/task-queue-admission) |
| 226 | +- [CLI Command Reference](/docs/2.0/polyglot/cli-reference) |
0 commit comments