Create the first operator and sign in
[⏱️ ~5 min] Create the first user with `mdk user add --admin` while the Kernel runs, then sign in at the dashboard, over HTTP, or with `mdk login`
TL;DR
- Users live in the Kernel's identity store, so the stack runs first:
mdk rbac initonce, thenmdk run - In a second terminal,
mdk user add <name> --admincreates the operator, writes theadminrole if it is missing, and binds the user to it - Sign in at the dashboard, at
POST /auth/loginfor a bearer token, or withmdk login <name>so the CLI acts as you
Overview
mdk rbac init binds only service accounts: the CLI's own account and each app. It creates no user, so a fresh stack boots
with nobody able to sign in. The first person is created with mdk user add <name> --admin, and that one binding is what opens
the dashboard and every app route. This page creates that operator and shows the three ways to sign in as them. Every other
MDK path that needs a signed-in user, the tutorials, the agent guides and the hosted-site profiles, delegates this step here.
Prerequisites
- The
mdkCLI installed - A project with
mdk.yaml, frommdk onboardor a tutorial jq, only for the HTTP sign-in
Start the stack
A fresh stack needs its policy before the Kernel boots, so initialize it once, then run everything together:
mdk rbac init # once per stack; binds the CLI and each app, creates no user
mdk runExpected output ends with:
Stack running. Press Ctrl+C to stop.mdk run kernel starts only the Kernel, which is enough for every mdk user command when nothing else is needed yet.
Create the operator
In a second terminal, from the project directory:
mdk user add ops@example.com --adminThe command prompts Password and Password again; the Kernel accepts twelve characters or more. Expected output starts with:
✔ Created user ops@example.com
mdk.yaml bound ops@example.com to adminA third line names the policy version the Kernel now enforces. --admin binds the user to the admin role, writing the role
first when spec.rbac has none. Confirm with mdk user list, which prints the one user.
Scripts pipe the password instead of answering the prompt: echo "$PW" | mdk user add ops@example.com --admin --password-stdin.
A flag value is never accepted.
Sign in
A. In the dashboard
mdk run dashboardOpen the URL it prints, and sign in with the name and password you set.
B. Over HTTP
TOKEN=$(curl -s -X POST http://localhost:3847/auth/login \
-H 'content-type: application/json' \
-d '{"username":"ops@example.com","password":"<the password you set>"}' | jq -er .accessToken)
curl -s -H "Authorization: Bearer $TOKEN" http://localhost:3847/auth/meExpected output:
{"kind":"user","sub":"ops@example.com"}The port is spec.gateway.port in mdk.yaml. The access token lasts minutes; the refresh token arrives as a cookie, or in
the body when the login request carries "refreshIn": "body", which the Gateway's sign-in routes cover.
C. In the CLI
mdk login ops@example.com
mdk whoami
mdk logoutExpected output, one line per command:
✔ Signed in as ops@example.com (until <expiry>)
ops@example.com until <expiry>
✔ Signed outThe session lives in .mdk/session.json, readable by you alone, and is renewed as it is used. While it lasts, mdk status,
mdk user, mdk sa and mdk rbac act as the user, with what spec.rbac binds the user to. Without a session the CLI acts
as its own service account, which mdk whoami reports as mdk-cli.
Troubleshooting
The command fails because the Kernel is not running
no Kernel key at <dir>/.mdk/kernel.key; start it with mdk run, or Kernel unreachable. Users live in the Kernel's identity store, so start
mdk run in another terminal and run the command again.
The password is refused
The Kernel answers ERR_IDENTITY_PASSWORD_WEAK for fewer than twelve characters. The passwords do not match. means the two
prompts differed; run the command again.
No terminal to prompt for a password
No terminal to prompt for a password: pipe it in with --password-stdin. appears in CI and piped shells. Pass the password on
stdin as the TIP shows.
Every route answers 403 after signing in
The user was created without --admin, so no rule names them. Run mdk user add <name> --admin again: it prints
Updated user and adds the binding.
mdk run refuses to start because the policy binds nobody
Run mdk rbac init first. mdk user add cannot run against a Kernel that is not up, so the policy has to let the stack boot
before the first user exists.
The CLI session has expired
ERR_CLI_SESSION_EXPIRED ends the command. An expired session is an error, never a quiet return to the service account, so
sign in again with mdk login.
Next steps
- Give everyone else a narrow role: groups,
resourceNames, and the policy the first operator now administers - Manage users and service accounts:
mdk user passwd,disable,remove, andmdk safor agents - Understand the Gateway's sign-in routes: cookies, refresh rotation, and what reaches an app
- Build your first app with a UI