Dev Mode Access

dev-mode-access.conf is loaded when the dev-mode feature is enabled in _features.conf. It is a second, independent gate on top of the dev-mode flag: enabling dev-mode alone no longer makes the /v1/dev/* endpoints (initial-setup, database-recreate, add-example-data, webhook-test) reachable. Every request to those endpoints must also include a matching X-Dev-Mode-Token header.

/v1/dev/* includes destructive, unauthenticated-by-design endpoints (dropping and reseeding the database, among others). Never enable dev-mode on a deployment reachable outside a trusted network, even with accessToken set — treat this as a convenience for local/CI use, not a security boundary on its own.

Example File

This is exactly the shipped template - commented out, so dev-mode stays non-functional until you act on it:

dev-mode-access.conf
# accessToken = "replace-with-a-per-deployment-secret"

Fields

accessToken

String, optional — defaults to unset (null). This is deliberately fail-closed: if the dev-mode feature is enabled but accessToken is unset, /v1/dev/* refuses every request with 503 Service Unavailable, rather than falling back to open access. A startup warning is logged in this case as well.

Startup refuses to proceed at all if accessToken is set to the literal placeholder above, "replace-with-a-per-deployment-secret". That exact string is published in walt.id's own source and documentation, so uncommenting the template without changing it provides no protection - the check exists specifically to catch that. Replace it with a real, secret, per-deployment value.

Once set, every call to /v1/dev/* must include a matching header:

curl -X POST http://localhost:3000/v1/dev/database-recreate \
  -H 'X-Dev-Mode-Token: <your accessToken value>'

A missing or mismatched header returns 401 Unauthorized. The header is also documented as a request parameter in Swagger, so it can be set directly from the "Try it out" panel for each /v1/dev/* operation.

Use a real, secret, per-deployment value for anything beyond local/CI use. A shared or well-known value provides no protection on its own, the same way an unset value provides none.

Last updated on September 28, 2026