Bootstrap and authenticate
Create the first tapstate administrator, sign in, and use the preview control plane safely
The tapstate control plane requires authentication for connector, artifact, connection, pipeline, and observation operations. Self-hosted servers use local accounts; Cloud uses its managed sign-in flow.
The Quickstart performs these steps automatically. Use this page after a tapstate server is already running, for example in that playground or in an environment managed separately from these docs.
Sign in on the web
For the Playground, follow the Web access step
and sign in as admin with the password saved in tapstate-demo/.env. The setup script creates the account.
For another deployment, use the server URL and account supplied by its operator.
For Cloud, open the cluster from the Cloud application and complete its sign-in flow. The server exchanges the one-time code for a host-only, secure, HTTP-only session cookie. Use HTTPS and the assigned cluster hostname; local bootstrap and username/password login are unavailable in Cloud mode.
The bootstrap and password-login examples below cover self-hosted authentication. A new self-hosted server has one bootstrap window for its first administrator. Web users do not need to repeat bootstrap.
Before you begin
- Start a preview server with its control port bound to loopback or another protected interface.
- Confirm
GET /healthzreturns HTTP200withok; a broken engine returns503. - Install
curlandjqfor the HTTP examples. - Choose a strong first-administrator password and keep it out of shell history.
The preview bootstrap endpoint accepts only a loopback caller. Do not expose an unbootstrapped server port to another host.
Set the server base URL once in the shell before using the HTTP examples. Use the address exposed by your running environment:
export TAPSTATE_URL=http://127.0.0.1:8080
curl --fail --silent --show-error --noproxy '*' "$TAPSTATE_URL/healthz"Create the first administrator
Set credentials in the current shell, then call the loopback endpoint:
export TAPSTATE_URL=http://127.0.0.1:8080
export TAPSTATE_ADMIN_USER=admin
read -s TAPSTATE_ADMIN_PASSWORD
export TAPSTATE_ADMIN_PASSWORD
curl --fail-with-body --silent --show-error \
-X POST "$TAPSTATE_URL/auth/bootstrap" \
-H 'Content-Type: application/json' \
--data "$(jq -n \
--arg username "$TAPSTATE_ADMIN_USER" \
--arg password "$TAPSTATE_ADMIN_PASSWORD" \
'{username: $username, password: $password}')"A successful first bootstrap returns HTTP 204 with no body. Once any user exists, another bootstrap request returns HTTP 409 with code control.bootstrap-closed.
The playground treats both results as an established administrator: 204 means it created the user; 409 means the bootstrap window was already closed.
Sign in with the CLI
Start an interactive session:
tapstate -w workThen connect and sign in:
connect http://127.0.0.1:8080
login adminThe CLI asks for the password with masked input. A successful login keeps the session token in memory for that CLI process. Use logout or exit when finished.
The REPL does not expand $TAPSTATE_URL. Type the actual server URL in its
connect command, including the port exposed by your running environment.
In the current preview, connected verbs can run inside this interactive session or as
one-shot commands seeded with -c and -u. Prefer the session for a sequence
that shares one login.
Sign in over HTTP
TOKEN="$(
curl --fail-with-body --silent --show-error \
-X POST "$TAPSTATE_URL/auth/login" \
-H 'Content-Type: application/json' \
--data "$(jq -n \
--arg username "$TAPSTATE_ADMIN_USER" \
--arg password "$TAPSTATE_ADMIN_PASSWORD" \
'{username: $username, password: $password}')" \
| jq -r '.token'
)"Present the token on /api/** requests:
curl --fail-with-body --silent --show-error \
"$TAPSTATE_URL/api/connectors" \
-H "Authorization: Bearer $TOKEN"The returned access token expires after 15 minutes. When the signing secret is not configured, the single-node server creates a new secret at startup, so existing access tokens stop working after a restart. For longer-lived CLI sessions, see Save a server context and session.
Cloud sessions
Cloud browser sessions and self-hosted access tokens have different lifecycles. Cloud validates and refreshes the managed session on the server; do not apply the self-hosted 15-minute access-token lifetime to its browser cookie.
- Use the application's sign-out flow to invalidate the session and clear its cookie.
- Cookie-authenticated writes must come from the same origin. Keep the proxy's hostname allowlist and HTTPS configuration aligned with the cluster URL.
/auth/invalidate-sessionis a signed provider callback, not a user API that accepts a normal Bearer token.
See Base URLs and authentication for the deployment-specific HTTP contracts.
Authentication results
| Result | Meaning |
|---|---|
HTTP 400 | The JSON body is malformed or a required username/password field is blank. |
HTTP 401 | Login failed, or an API credential is absent, invalid, expired, or revoked. |
HTTP 403 | The authenticated caller lacks the operation's required scope, or bootstrap was not called from loopback. |
HTTP 409 | The first-administrator bootstrap window is already closed. |
API errors use the structured error envelope. Do not distinguish “unknown user” from “wrong password” in automation; both intentionally return the same authentication failure.
Security boundaries
- Keep the preview server on a trusted network path.
- Do not pass passwords as CLI arguments or commit
.envfiles. - Unset the shell variables when finished:
unset TAPSTATE_ADMIN_PASSWORD TOKEN. - If the signing secret is generated at startup, existing tokens stop working after restart.
- In a cluster, configure the same
tapstate.control.auth.jwt-secreton every member. See Configure a cluster. - This preview is not a production identity-management service.