Authentication
Bearer JWTs, how to register and log in, token lifetime, open registration, and how a platform admin is bootstrapped.
Minctrl authenticates with bearer JWTs. Every endpoint except /auth/* and /health
requires an Authorization: Bearer <token> header. A missing or expired token returns
401.
Getting a token
Two ways to obtain a token; both return { token, user, company } on success.
Register (open)
Registration is open — anyone can sign up — and auto-creates a company with you as its owner:
curl -s -X POST "$API/auth/register" \
-H "Content-Type: application/json" \
-d '{
"email": "jane.doe@acme-health.com",
"password": "<your-password>",
"company_name": "Acme Health"
}'company_name and name are optional. When the closed-beta whitelist gate is off
(open registration), personal-email domains (gmail, outlook, …) are accepted.
Log in
curl -s -X POST "$API/auth/login" \
-H "Content-Type: application/json" \
-d '{ "email": "jane.doe@acme-health.com", "password": "<your-password>" }'Invalid credentials return 401. Login is rate-limited to 5 requests/minute per IP —
see Rate limits.
Passwordless one-time code (OTP)
An email one-time-code flow is also available: POST /auth/otp/request emails a 6-digit
code (10-minute TTL, max 5 attempts), and POST /auth/otp/verify exchanges the code for a
token. otp/request always returns {sent: true} regardless of whether the email exists,
to defend against enumeration.
Using the token
TOKEN="<token from the response>"
curl -s "$API/process-templates/" -H "Authorization: Bearer $TOKEN"Token lifetime
Tokens are HMAC-SHA256 JWTs that expire 24 hours after issue. After that, calls return
401 and you re-authenticate. POST /auth/logout revokes the current token immediately
(server-side blacklist, 24h TTL). Confirm the authenticated identity any time with:
curl -s "$API/auth/me" -H "Authorization: Bearer $TOKEN"/auth/me returns your user, primary company, membership status/role, and platform role.
Roles vs. platform admin
There are two distinct role dimensions:
- Company (membership) role —
owner/admin/manager/member/viewer. Governs what you can do within your company. See Set up your team. - Platform role —
adminoruseron theusersrecord. Gates platform-owner endpoints such asGET /auth/users(list every user) and the whitelist admin endpoints, which return403for non-admins.
Admin bootstrap (whitelist)
A platform admin is bootstrapped via the whitelist: an email marked is_admin=true in
user_whitelist is granted users.role='admin' on its first signup. Under open
registration the whitelist is consulted only for this bootstrap — it never blocks a
signup. When the closed-beta gate is enabled, the whitelist additionally gates who may
register: unlisted emails are waitlisted, rejected emails get 403, and bootstrap admins
skip the personal-email block. Admins manage the waitlist via
GET /auth/whitelist, POST /auth/whitelist/{email}/approve, and
POST /auth/whitelist/{email}/reject.
See the Auth reference for the full request/response schemas.