Operator routes¶
The person who runs a provider can look up, disable, enable, reset, export
and delete standard-door accounts, and set how sites share a sub. These are
the routes for that. They are not for sites: a site never holds the operator
secret.
Only standard-door accounts (email or mobile, username, password or passkey) can be touched here. The provider holds their contact and password hash, so it can reset them. An Omxus identity (name, date of birth, words) lives with the person, and no operator can reset it.
Turning them on¶
The routes are off unless the Worker has the secret ACCOUNTS_OPERATOR_SECRET.
Without it every operator path answers 404 not_found, as if it did not exist.
ACCOUNTS_OPERATOR_IPS (exact addresses, separated by commas or spaces)
narrows them further; empty means any address holding the secret.
Every request¶
POST, withContent-Type: application/jsonandAuthorization: Bearer <secret>.- No
Originheader. Browsers send one, so a browser is refused (403 origin_not_allowed). Usecurlor a server. - Body up to 16 KB.
- A wrong secret counts as a failure against the calling address. After 3 in
15 minutes each answer slows down; after 10 the address is locked for the
rest of the window (
429 too_many_requests).
curl -X POST https://auth.omxus.com/accounts/operator/lookup \
-H "authorization: Bearer $SECRET" -H 'content-type: application/json' \
-d '{"email":"[email protected]"}'
Checked against auth.omxus.com on 30 Oct 2026: no secret answers
401 unauthorized, an Origin header answers 403 origin_not_allowed, a
GET answers 405 method_not_allowed. So the routes are on there.
Accounts¶
Name the account with one of:
| Field | What it matches |
|---|---|
account_id |
the provider's internal id (from lookup) |
email |
a verified email address |
phone |
a verified mobile number |
Only verified contacts match. An address someone typed at sign-up but never
confirmed finds nothing. No match answers 404 no_account.
| Route | Does | Answer |
|---|---|---|
/accounts/operator/lookup |
finds the account | { account_id, state } |
/accounts/operator/disable |
blocks sign-in, signs out every session; optional reason (200 characters) |
{ ok, revoked } |
/accounts/operator/enable |
lifts a disable | { ok } |
/accounts/operator/force-reset |
removes the password, signs out every session | { ok, revoked } |
/accounts/operator/export |
everything held about the account | { export } |
/accounts/operator/delete |
deletes the account and everything keyed to it | { ok } |
state is null for an account never disabled, otherwise
{ disabledAt, disabledReason, updatedAt } in Unix seconds. revoked is the
number of sessions ended.
Disable. Sign-in then answers account_disabled. The reason is stored
with the account; the person does not see it.
Force reset. The person signs in with a six-digit code to their contact and sets a new password. Use it when a password may have leaked.
Export. The account (id, Omxus address if linked, whether it has a
password, created), contacts, any pending contact, usernames, profiles,
passkeys, sessions, the activity log, state (with the disable reason) and
in-person vouch status. No password hashes and no tokens. Unlike the copy a
person takes from their own export, it carries the
internal account id and field names as the store holds them (createdAt, not
created_at).
Delete. Cannot be undone. Take an export first if anyone may ask for it.
Disable, enable and force reset are written to the account's activity log
(disabled_by_operator, enabled_by_operator, password_reset_by_operator),
so the person can see them.
Sites that share a sub¶
Each site sees its own sub for a person
(How identity is derived). A website and its apps
usually want one. Two routes set that.
Set a sector for up to 50 clients at once:
curl -X POST https://auth.omxus.com/accounts/operator/sector \
-H "authorization: Bearer $SECRET" -H 'content-type: application/json' \
-d '{"client_ids":["rpgcreator-web","rpgcreator-ios"],"sector":"rpgcreator.net"}'
Answer { ok, updated, sector }. sector must be a domain name. Every listed
client then sees the same sub for a person. It changes the sub those
clients have already seen, so do it before launch.
Approve a pending sector_identifier_uri. A site that registers with one
(Registering a site) waits as pending_operator_approval and
cannot sign anyone in yet. Nothing is fetched at registration.
curl -X POST https://auth.omxus.com/accounts/operator/sector/approve \
-H "authorization: Bearer $SECRET" -H 'content-type: application/json' \
-d '{"client_id":"my-app"}'
The provider then resolves the host, fetches the file (no redirects, 64 KB,
5 seconds) and resolves it again. It refuses if either answer holds a private
address or the two answers differ, and the file must list every redirect URI
of the client. On success: { ok, client_id, sector }, and the client can sign
people in.
| Error | Meaning |
|---|---|
400 invalid_request |
client_ids not 1 to 50 strings, or sector not a domain |
404 no_pending_sector |
that client has no pending URI |
400 sector_refused |
the check failed; the message says why and the URI stays pending |
Errors on every route¶
| Error | Meaning |
|---|---|
404 not_found |
routes off (no secret set) or unknown route |
405 method_not_allowed |
not a POST |
403 origin_not_allowed |
the request carried an Origin header |
403 forbidden |
address not in ACCOUNTS_OPERATOR_IPS |
401 unauthorized |
secret missing or wrong |
429 too_many_requests |
10 failures from this address in 15 minutes |
415 unsupported_media_type |
body is not JSON |
413 body_too_large |
body over 16 KB |
400 invalid_json |
body does not parse |
400 invalid_email, 400 invalid_phone |
the contact given does not look right |
404 no_account |
no account matches |