Accounts System
Built-in per-namespace user account management for the end-users of your application. Every verb shares the ACCOUNT prefix — ACCOUNT REGISTER, LOGIN, LOGOUT, SESSION, REFRESH, REVOKE, VERIFY, COMPARE, DELETE, UPDATE EMAIL, UPDATE PASSWORD — no external auth service required.
STATUS, used in several examples, is documented on HTTP & Network.identity/password. OcaltQL manages the storage internally; you never write SQL for this.?uid is the permanent identifier for the account — it never changes for the lifetime of that account, and it is what you store wherever you need a durable reference. The session is the browser, handled by START SESSION exactly as it is everywhere else in the language. ACCOUNT LOGIN joins the two: it authenticates, then places the account in the current session. There is no separate token to carry, no cookie to set by hand, and no second session system to keep in step with the first.Verb Reference
| Verb | Description | Returns |
|---|---|---|
ACCOUNT REGISTER "email" WITH "password" SET ?uid | Create a user account | UID (string, permanent) or null if the email is already registered |
ACCOUNT LOGIN "email" WITH "password" SET ?uid | Authenticate and place the account in the current session | UID (string) or null on failure |
ACCOUNT REVOKE "email" SET ?count | Invalidate all sessions for a user | Number of sessions revoked |
ACCOUNT VERIFY "email" SET ?ok | Mark a user account as verified (e.g. after email confirmation) | Boolean |
ACCOUNT COMPARE "a" WITH "b" SET ?valid | Constant-time string comparison — safe for comparing tokens and secrets | Boolean |
ACCOUNT DELETE "email" SET ?ok | Permanently delete a user account and all its sessions | Boolean |
ACCOUNT UPDATE EMAIL "old" TO "new" SET ?ok | Change the email address on an account | Boolean |
ACCOUNT UPDATE PASSWORD "email" WITH "new_password" SET ?ok | Change the password on an account | Boolean |
ACCOUNT REGISTER
ACCOUNT REGISTER "alice@example.com" WITH "pass1234" SET ?uid
AFTER IF ?uid IS NULL
OPEN
STATUS 409
AFTER EMIT "Email already registered"
CLOSE
OR
OPEN
EMIT "User created: " & ?uid
CLOSE
ACCOUNT LOGIN
Authenticates, and on success places the account in the current session. Start the session first — there is nowhere to put the account otherwise.
START SESSION
AFTER ACCOUNT LOGIN "alice@example.com" WITH "pass1234" SET ?uid
AFTER IF ?uid IS NULL
OPEN
STATUS 401
AFTER EMIT "Invalid credentials"
CLOSE
OR
OPEN
REDIRECT "/dashboard" AS "302"
CLOSE
Protecting a Route
Who is signed in is a session value, read like any other: !SESSION('account'). There is no account-specific verb for this, because the session system already answers the question.
START SESSION
AFTER SET !SESSION('account') AS ?uid
AFTER IF ?uid IS NULL
OPEN
REDIRECT "/login" AS "302"
CLOSE
OR
OPEN
EMIT "Welcome back, account " & ?uid
CLOSE
KILL SESSION. It ends the browser's session, which is what signing out means. There is no ACCOUNT LOGOUT — it would have been a second way to do the same thing. To end every session a person has anywhere, on every device, see ACCOUNT REVOKE below.Handling Auth Errors with CATCH ERROR
ACCOUNT LOGIN and ACCOUNT REGISTER throw an error on failure (wrong credentials, duplicate email) in addition to returning null. CATCH ERROR captures the error message into a variable; the chain continues normally afterward regardless of whether an error occurred.
START SESSION
AFTER ACCOUNT LOGIN "alice@example.com" WITH "wrongpass" SET ?uid
OR CATCH ERROR SET ?err
AFTER IF ?err IS NOT NULL
OPEN
STATUS 401
AFTER EMIT ?err
CLOSE
OR
OPEN
EMIT "Welcome"
CLOSE
START SESSION
AFTER ACCOUNT LOGIN "alice@example.com" WITH "pass1234" SET ?uid
AFTER IF ?uid IS NULL
OPEN
STATUS 401
AFTER EMIT "Invalid credentials"
CLOSE
OR
OPEN
EMIT "Signed in"
CLOSE
Signing Out
KILL SESSION
AFTER REDIRECT "/login" AS "302"
ACCOUNT REVOKE — Invalidate All Sessions
ACCOUNT REVOKE "alice@example.com" SET ?count
AFTER EMIT "Revoked " & ?count & " sessions"
ACCOUNT VERIFY — Mark Account as Verified
ACCOUNT VERIFY "alice@example.com" SET ?ok
AFTER EMIT ?ok
ACCOUNT COMPARE — Constant-Time Token Check
Always use ACCOUNT COMPARE instead of IS IDENTICAL TO when comparing secrets. It prevents timing attacks.
ACCOUNT COMPARE ?submitted_token WITH ?expected_token SET ?valid
AFTER IF ?valid IS EQUAL TO true
OPEN
EMIT "accepted"
CLOSE
OR
OPEN
STATUS 401
CLOSE
ACCOUNT DELETE
Permanently deletes the account and every session associated with it. This cannot be undone.
ACCOUNT DELETE "alice@example.com" SET ?ok
AFTER IF ?ok IS EQUAL TO true
OPEN
EMIT "Account deleted"
CLOSE
OR
OPEN
STATUS 404
AFTER EMIT "Account not found"
CLOSE
ACCOUNT UPDATE EMAIL
Changes the email address on an existing account. The account's permanent ?uid does not change — only the email used to log in.
ACCOUNT UPDATE EMAIL "alice@example.com" TO "alice.new@example.com" SET ?ok
AFTER IF ?ok IS EQUAL TO true
OPEN
EMIT "Email updated"
CLOSE
OR
OPEN
STATUS 409
AFTER EMIT "New email already in use"
CLOSE
ACCOUNT UPDATE PASSWORD
ACCOUNT UPDATE PASSWORD "alice@example.com" WITH "new_secure_pass" SET ?ok
AFTER EMIT ?ok
Complete Registration + Login Flow (Site Mode)
PARSE JSON !REQUEST('body') SET ?data
AFTER ACCOUNT REGISTER ?data("email") WITH ?data("password") SET ?uid
AFTER IF ?uid IS NULL
OPEN
STATUS 409
AFTER HEADER "Content-Type" AS "application/json"
AFTER EMIT `{"error":"Email already registered"}`
CLOSE
OR
OPEN
ACCOUNT LOGIN ?data("email") WITH ?data("password") SET ?signed_in
CLOSE
AFTER STATUS 201
AFTER HEADER "Content-Type" AS "application/json"
AFTER EMIT `{"uid":"` & ?uid & `"}`