Authentication

AIUS authentication has two layers: a short-lived session token (an HS256 JWT) you get by logging in, and a durable API token (aius_…) you mint from a session and use as a bearer credential on every request.
All examples target production (https://aius.co/api). For the dev gateway, swap for https://dev.aius.co/api and add -H "Accept-Encoding: identity".

1. Register

POST /v1/register creates a new email/password account. On success the gateway adds a session_token to the response so a non-browser client can immediately mint an API token.
curl -X POST https://aius.co/api/v1/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "dev@example.com",
    "name": "Dev User",
    "password": "SuperSecret123!"
  }'
Response 200:
{
  "user": {
    "id": "usr_abc123",
    "email": "dev@example.com",
    "name": "Dev User",
    "provider": "email",
    "provider_id": "dev@example.com",
    "created_at": 1717123456
  },
  "message": "Registration successful",
  "session_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Registration also auto-creates a default client (organization) for the new user, so you can mint tokens and use the API immediately. Password requirements: at least 8 characters, with at least one letter, one number, and one special character.

2. Log in

POST /v1/login verifies credentials. The response depends on whether the account has 2FA enabled.
curl -X POST https://aius.co/api/v1/login \
  -H "Content-Type: application/json" \
  -d '{"email": "dev@example.com", "password": "SuperSecret123!"}'
Response 200 (no 2FA): same shape as register — { user, message, session_token }. Response 200 (2FA enabled): no user or session is returned; instead a short-lived challenge:
{
  "requires_2fa": true,
  "challenge_token": "eyJ...",
  "email": "dev@example.com",
  "message": "Two-factor authentication required"
}
Invalid credentials return 401 with {"detail": {"code": "INVALID_CREDENTIALS", "message": "Invalid email or password"}}.

3. Complete a 2FA login

When requires_2fa is true, finish the login with POST /v1/2fa/login, passing the challenge_token plus a current TOTP code (or a recovery code). This endpoint is unauthenticated — the challenge token is the credential.
curl -X POST https://aius.co/api/v1/2fa/login \
  -H "Content-Type: application/json" \
  -d '{
    "challenge_token": "eyJ...",
    "code": "123456"
  }'
Response 200: { user, message, session_token } — the gateway attaches a session_token just like login. Invalid challenge → 401 INVALID_CHALLENGE; invalid code → 401 INVALID_CODE.

4. Mint an API token

POST /v1/tokens exchanges a session for a durable aius_… token. The session is supplied via the __Host-aius_session cookie. token_name is required; client_id is optional (defaults to your account).
The token value is returned once and never again. Store it securely.
curl -X POST https://aius.co/api/v1/tokens \
  -H "Content-Type: application/json" \
  --cookie "__Host-aius_session=eyJ..." \
  -d '{
    "token_name": "my-cli",
    "client_id": "client_xyz789"
  }'
Response 200:
{
  "id": 42,
  "client_id": "dev@example.com",
  "token_name": "my-cli",
  "token": "aius_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "created_at": 1717123999
}
Missing token_name400 token_name is required. No / invalid session cookie → 401.

5. Use the bearer token

Send your aius_… token on every API request:
curl https://aius.co/api/v1/models \
  -H "Authorization: Bearer aius_xxxxxxxx..."
On the run-loop WebSocket, the same token is sent inside the first frame: {"type": "auth", "token": "aius_…"} (see Run-loop WebSocket). A missing or malformed Authorization header returns 401 missing bearer token / invalid authorization header; an unknown or revoked token returns 401 invalid token.

Enrolling and managing 2FA

These endpoints operate on the authenticated user (send your session cookie or a bearer token). They use TOTP (RFC 6238) — compatible with any authenticator app.
EndpointMethodPurpose
/v1/2fa/statusGETWhether 2FA is enabled → {"enabled": false}
/v1/2fa/setupPOSTBegin enrolment → {"secret": "...", "otpauth_uri": "otpauth://..."}
/v1/2fa/enablePOSTConfirm a code → {"enabled": true, "recovery_codes": [...]}
/v1/2fa/disablePOSTDisable after verifying a code → {"enabled": false}
Enrolment flow:
1

Begin

POST /v1/2fa/setup returns a secret and an otpauth_uri. Add the secret (or scan the URI as a QR code) into your authenticator app. 2FA is not yet active.
2

Confirm

POST /v1/2fa/enable with {"code": "123456"} (the current code from the app). On success you receive one-time recovery_codes — save them.
# Step 1
curl -X POST https://aius.co/api/v1/2fa/setup \
  -H "Authorization: Bearer aius_xxxxxxxx..."

# Step 2
curl -X POST https://aius.co/api/v1/2fa/enable \
  -H "Authorization: Bearer aius_xxxxxxxx..." \
  -H "Content-Type: application/json" \
  -d '{"code": "123456"}'
To disable, POST /v1/2fa/disable with a current TOTP or a recovery code:
curl -X POST https://aius.co/api/v1/2fa/disable \
  -H "Authorization: Bearer aius_xxxxxxxx..." \
  -H "Content-Type: application/json" \
  -d '{"code": "123456"}'

Password reset

EndpointMethodBodyPurpose
/v1/password/reset/requestPOST{"email": "..."}Send a reset email (always 200, even if the email is unknown)
/v1/password/reset/confirmPOST{"token": "...", "new_password": "..."}Set a new password from a reset token