English | 中文
wdl token manages a local credential store at ~/.config/wdl/credentials
($XDG_CONFIG_HOME/wdl/credentials, or %APPDATA%\wdl\credentials on Windows)
so commands resolve a control URL and token without a per-shell ADMIN_TOKEN
export or a token in every project's .env.
There is no "login". A WDL token is issued by your operator; wdl token set
just stores it (after checking it against /whoami and confirming its principal
is the namespace you are storing it under), and wdl token rm deletes the local
copy — it does not revoke the token.
The store is the same dotenv/INI dialect a project .env uses, keyed by
namespace, with each entry self-contained. A base WDL_NS line (before any
section) names the default namespace — the one used when you do not pass --ns
— exactly as a base WDL_NS works in a project .env:
WDL_NS="acme"
[acme]
CONTROL_URL="https://api.example"
ADMIN_TOKEN="<token>"
LABEL="production"It is command-owned: wdl token rewrites it canonically (default first, then
sorted, quoted sections), so hand-edit a project .env for project-specific
values instead. The file is written with 0600 permissions.
# Store a token. The token is read from stdin (hidden on a TTY), validated
# against /whoami, checked to belong to --ns, then stored. The control URL comes
# from --control-url or CONTROL_URL — never from the store itself. The first
# stored namespace becomes the default; --default makes any set the default.
wdl token set --ns acme --control-url https://api.example
wdl token set --ns acme --control-url https://api.example --label production
wdl token set --ns demo --control-url https://api.example --default
printf '%s' "$TOKEN" | wdl token set --ns acme --control-url https://api.example
# List stored namespaces with masked tokens; the default is marked with *
# (--json for scripting; each row carries a "default" boolean, still masked).
wdl token list
# Choose which stored namespace is the default (used when --ns is omitted).
wdl token use acme
# Remove the local copy for a namespace (does not revoke on the control plane).
wdl token rm --ns acmeThe store is the lowest-precedence credential layer:
CLI flag > shell/CI env > project ./.env > global token store > unset (error)
A value from a higher layer always wins; the store only fills gaps. Resolution
is per namespace: a namespace selects the entry, which supplies both the control
URL and the token. wdl config explain shows token store [<ns>].… as the
source when a value came from the store.
Which namespace is selected follows its own chain, with the store's default at
the bottom — the same shape, one layer lower than a project .env's base
WDL_NS:
--ns > shell/CI WDL_NS > project ./.env WDL_NS > store default (base WDL_NS)
So with a stored default you can run wdl deploy, wdl doctor, etc. without
--ns; pass --ns (or wdl token use <ns>) to pick a different one. When the
namespace comes from the store default, wdl config explain shows the source as
token store default.
The wdl token subcommands are the exception to that chain: set, use, and
rm mutate the store, so they take the namespace from an explicit --ns (or
use's positional) only — never the ambient WDL_NS — so a stray shell value
can't write, switch, or delete the wrong entry.
The store is trusted (it lives in your home directory and you wrote it via
wdl token, so its token and endpoint are same-source). A project .env is
not: a .env that supplies a control endpoint without also supplying the token
is still dropped, so an untrusted project directory can never redirect your
stored token to a host it chose.
wdl deploy runs the project's local Wrangler dry-run and any build commands or
dependency hooks as your OS user, before uploading. Scrubbing ADMIN_TOKEN
and the control-plane variables from that child's environment only closes the
environment path — it is not a sandbox. The on-disk store at
~/.config/wdl/credentials stays readable by that code, the same way
~/.aws/credentials or ~/.npmrc would. So a malicious project can read it, and
because the store can hold tokens for several namespaces, one untrusted
deploy can exfiltrate tokens for namespaces unrelated to that project.
- Only run
wdl deployon projects you trust. - For an untrusted or third-party project, don't keep a global store: supply an
ephemeral
ADMIN_TOKEN/CONTROL_URLfrom your shell or--token/--control-urlscoped to that one namespace, and ideally use a dedicated OS user or a container. --no-token-store(orWDL_TOKEN_STORE=off) makes the CLI resolve credentials from flags / env /.envonly and never read the store. This is a resolution opt-out, not protection for the file — the bytes on disk are still readable by project code. The protection comes from not having a store present, not from the flag.
- ❌ Treating
wdl token rmas revocation. It deletes the local copy only; the token still works until your operator revokes it. - ❌ Hand-editing
~/.config/wdl/credentials. It is rewritten on the nextwdl tokenwrite and your edits (including comments) are lost. Use a project.envfor hand-managed overrides. - ❌ Passing the token as a command-line argument.
setreads it from stdin so it stays out of shell history; type it at the prompt or pipe it in. - ❌ Expecting the store to override a token already set in your shell or a
project
.env. It is the lowest layer and only fills gaps.
- deploy.md —
ADMIN_TOKEN/CONTROL_URLprecedence and the.envlayout the store sits beneath. - secrets.md —
wdl secret, for a worker's runtime secrets (a different thing from the deploy token managed here).