Files
openwork/docs/initial-admin-bootstrap.md

5.5 KiB

Initial Administrator Bootstrap

Private OpenWork Den deployments often disable public signup before anyone has an account. Configuring an owner or bootstrap administrator email authorizes that person after an account exists; it does not create the account and it does not make knowing the email sufficient to claim the deployment.

Use the initial-administrator bootstrap flow to create the first account without enabling public signup and without requiring SMTP.

How It Works

  1. The deployment must have zero Better Auth users.
  2. The Better Auth user table must still be empty.
  3. The submitted email must be eligible.
  4. The submitted one-time setup code must match the server-side setup-code secret.
  5. The server issues a short-lived, email-bound bootstrap grant.
  6. The final account creation goes through Better Auth email/password signup.
  7. OpenWork creates or reuses the singleton organization, grants owner membership, adds platform-admin authorization, and signs the admin in.

After the first user exists, rotating or re-adding the setup-code secret cannot reopen bootstrap. Existing users are never deleted or mutated to recover setup.

Eligible Emails

For single_org deployments:

  1. If DEN_SINGLE_ORG_OWNER_EMAILS is set, those normalized emails are eligible to claim /setup.
  2. If DEN_SINGLE_ORG_OWNER_EMAILS is empty, DEN_BOOTSTRAP_ADMIN_EMAILS is used as the eligible bootstrap email list.

On successful setup, the created first owner is inserted into the platform-admin allowlist even if the email came from DEN_SINGLE_ORG_OWNER_EMAILS.

Environment Variables

Required for private bootstrap:

DEN_SINGLE_ORG_ALLOW_PUBLIC_SIGNUP=false

DEN_SINGLE_ORG_OWNER_EMAILS=admin@example.com or DEN_BOOTSTRAP_ADMIN_EMAILS=admin@example.com

DEN_INITIAL_ADMIN_BOOTSTRAP_CODE=<one-time setup code>

Alternative file-based injection:

DEN_INITIAL_ADMIN_BOOTSTRAP_CODE_FILE=/run/secrets/initial-admin-bootstrap-code

The code is a plain string. Generate a unique value for each deployment and provide it through your secret-management system.

Generate A Code Safely

Run these commands on an operator workstation or in a trusted secret-management shell. They avoid placing the raw code in shell history.

umask 077
code_file=$(mktemp)
openssl rand -base64 32 | tr -d '\n' > "$code_file"

Store the raw code from code_file in your password manager or break-glass secret store and in the OpenWork deployment secret.

Remove local files after the first administrator has signed in:

rm -f "$code_file"

Kubernetes Secret

Create or update the chart Secret with the setup code:

kubectl create secret generic openwork-ee \
  --namespace openwork-ee \
  --from-file=DEN_INITIAL_ADMIN_BOOTSTRAP_CODE="$code_file" \
  --dry-run=client -o yaml | kubectl apply -f -

If the Helm chart creates the Secret, set:

secret:
  values:
    initialAdminBootstrapCode: "REPLACE_BOOTSTRAP_CODE"

If you use an existing Secret, make sure secret.keys.initialAdminBootstrapCode names the key that contains the setup code. Do not put the code in a ConfigMap.

Docker Compose And Other Containers

For environment-variable injection, set the setup code:

DEN_SINGLE_ORG_OWNER_EMAILS=admin@example.com
DEN_SINGLE_ORG_ALLOW_PUBLIC_SIGNUP=false
DEN_INITIAL_ADMIN_BOOTSTRAP_CODE=REPLACE_BOOTSTRAP_CODE

For file-based secret stores, mount a file containing the setup code and set:

DEN_INITIAL_ADMIN_BOOTSTRAP_CODE_FILE=/run/secrets/initial-admin-bootstrap-code

The same pattern works with container-platform secret stores, systemd environment files, VM secret agents, and Kubernetes projected Secrets.

Setup URL

Open:

https://openwork.example.com/setup

The setup page asks for the eligible administrator email and the raw one-time setup code. It does not display configured privileged emails and it does not require email delivery.

Verify Availability

The status endpoint reports only general state:

curl -fsS https://api.openwork.example.com/v1/auth/bootstrap/status

Possible statuses are available, complete, and unavailable. The response never includes configured emails or setup-code material.

Rotation And Recovery

Before the first user is created, rotate by generating a new code and replacing DEN_INITIAL_ADMIN_BOOTSTRAP_CODE or the code file. Restart or roll the Den API pods so they read the new secret.

After the first user is created, rotating the setup code cannot re-enable bootstrap. Use normal administrator account recovery, database backups, or an explicitly reviewed operational recovery procedure.

If the setup code is missing, bootstrap fails closed and /setup reports that setup is unavailable. Fix the secret and restart the API. Do not delete users or organizations to recover a malformed bootstrap configuration.

Bootstrap availability is checked with an existence query against the Better Auth user table (SELECT id ... LIMIT 1) instead of a full user count. Once any user exists, setup is permanently unavailable unless an operator deliberately changes the database outside OpenWork.

Security Warnings

Never put the real setup code in source control, committed Helm values, ConfigMaps, logs, screenshots, issue descriptions, PR bodies, or chat transcripts. Use placeholders such as REPLACE_BOOTSTRAP_CODE in examples.

SMTP and email verification are not required for initial-admin bootstrap. If email verification is enabled for normal auth, Better Auth still owns the signup mechanics and protections.