Auth error codes (mpbx-auth)
Raised by the auth core (W1-AUTH-01) and the RBAC engine (W1-AUTH-02). Kinds map to HTTP statuses
as for the common codes: unauthenticated is 401, permission_denied 403,
invalid_argument 400, not_found 404, conflict 409, unavailable 503, config and internal
500. Messages never contain a password, a token, a hash, a key or an
e-mail address. Guide: authentication.
| Code | Kind | Meaning | What to do |
|---|---|---|---|
MPBX-AUTH-INVALID-CREDENTIALS | unauthenticated | Login failed. The same code covers an unknown e-mail, a wrong password, an account locked after too many failures, a disabled user and a suspended company, so the answer does not reveal which accounts exist. Also returned by a password change when the current password is wrong. | Check the e-mail and password. After auth.lockout.max_failures failures the network is locked for that account for auth.lockout.lockout_secs (doubling for each lockout in a row; W4-AUTH-01: the lock applies to the client network the failures came from, an IPv4 address or an IPv6 /64, so the owner can still sign in from elsewhere); wait, use another network, or ask an administrator to unlock it (POST /api/v1/users/{id}/unlock, or mpbx user unlock <company> <e-mail> on the server). A recovery code (recovery_code) is accepted instead of the TOTP code, and a wrong or spent one answers MPBX-AUTH-TOTP-INVALID. |
MPBX-AUTH-TOKEN-INVALID | unauthenticated | The access token is missing, malformed, not EdDSA, signed with an unknown or retired key (for example a token from another install, or one older than a key rotation's grace period), has a bad signature, or has the wrong issuer or audience. | Sign in again. Services that verify tokens must load the install's current JWK set. |
MPBX-AUTH-TOKEN-EXPIRED | unauthenticated | The access token has expired (or is not valid yet). | Use the refresh token to get a new access token. If this happens right after login, check the clocks (auth.clock_leeway_secs). |
MPBX-AUTH-TOKEN-REVOKED | unauthenticated | The access token or its session was revoked (logout, password change, refresh token reuse, administrator). | Sign in again. |
MPBX-AUTH-REFRESH-INVALID | unauthenticated | The refresh token is malformed, unknown, expired (unused for auth.refresh_idle_ttl_secs, or the session is older than auth.session_max_age_secs), its session was ended, or the user or company is disabled. | Sign in again. |
MPBX-AUTH-REFRESH-REUSED | unauthenticated | A refresh token that had already been exchanged was presented again, after the grace window (auth.refresh_reuse_grace_secs, 20 s) or older than the immediately previous token. That means two parties hold the same session (a stolen token, or a client that sent one refresh twice), so the whole session was revoked and its access tokens were put on the deny list. Within the grace window the previous token returns the pair already issued instead. | Sign in again. Clients must serialise refresh calls (one in flight per session) and always store the newest refresh token. If it repeats, investigate the device. |
MPBX-AUTH-PASSWORD-POLICY | invalid_argument | A new password breaks the password policy. The message lists the broken rules by key: too_short, too_long, too_few_character_classes, invalid_characters, common, contains_user_info, repetitive. | Choose another password; a passphrase of several words is easiest. |
MPBX-AUTH-KEY-INVALID | config | The JWT key material is missing or wrong: MPBX_JWT_SIGNING_KEY, MPBX_JWT_PUBLIC_KEY or MPBX_JWT_KID unset or malformed, a public key that does not belong to the signing key, a weak key, or a malformed MPBX_JWT_PREVIOUS_KEYS entry. The message names the variable, never the value. | Restore the install secrets from backup, or generate them with mpbx init on a new install. |
MPBX-AUTH-CONFIG-INVALID | config | A value in the [auth] configuration section is out of range (the message names it and the allowed range). | Fix mpbx.toml or the MPBX__AUTH__* environment variable. |
MPBX-AUTH-HASH | internal | Password hashing or the OS random number generator failed. | Check the host (memory for argon2, entropy source) and report it with the log line. |
MPBX-AUTH-REVOCATION-UNAVAILABLE | unavailable | Valkey could not be read to check the token deny list. Requests fail closed instead of accepting a possibly revoked token. Retryable. | Check Valkey health. |
MPBX-AUTH-PRINCIPAL-INACTIVE | unauthenticated | The access token or API key is valid, but its user is disabled or deleted, or the company is suspended. Checked on every request, so disabling a user ends their access at once. | Ask an administrator to re-enable the account or the company. |
MPBX-APIKEY-INVALID | unauthenticated | The API key is unknown in the company it names, has been revoked, has expired, or its secret is wrong. One code for every case, so a probe learns nothing. A key whose company part was edited is also refused here: the key is looked up only inside the company the string names. | Create a new key (Admin, API keys) and replace the old one everywhere. |
MPBX-KIOSK-INVALID | unauthenticated | The wallboard kiosk token (X-Kiosk-Token) is missing, unknown, revoked or expired. One code for every case. Revocation applies to the next request. | Create a new kiosk link (Admin, Queue routing, Wallboard kiosks). |
MPBX-RBAC-FORBIDDEN | permission_denied | The caller does not hold the permission the operation needs (the scope named in the OpenAPI document), or holds it only for other departments than the resource's. The message names the permission. | Ask an administrator for a role that grants it; GET /api/v1/me lists what you hold and where. |
MPBX-RBAC-ESCALATION | permission_denied | Assigning a role, defining a custom role or choosing API key scopes would hand out a permission the caller does not hold for that scope (company or department). Nobody can grant more than they have. | Ask someone who holds the permission there (usually the Owner) to do it. |
MPBX-RBAC-UNKNOWN-PERMISSION | invalid_argument | A permission key is not in the catalogue, or is a system permission used in a company role or an API key. | Use the keys listed in the RBAC guide. |
MPBX-RBAC-BUILTIN-READONLY | conflict | Built-in roles (User, Receptionist, Supervisor, Department Admin, Manager, Owner) cannot be renamed, changed or deleted. | Create a custom role with the permissions you need. |
MPBX-RBAC-LAST-OWNER | conflict | The change would leave the company without a company-wide Owner, or the install without a System Owner. | Give the role to someone else first. |
MPBX-RBAC-NOT-FOUND | not_found | The role, role assignment or department does not exist in this company (another company's ids behave like missing ones). | Check the id; list the company's roles with the roles API. |
MPBX-RBAC-SYSTEM-ROLE-REQUIRED | permission_denied | A system-scope token (or a request to get one) for a user who holds neither System Admin nor System Owner, for example after the role was revoked. | Sign in again with a company token, or ask a System Owner for the role. |
MPBX-ACCOUNT-SYSTEM | permission_denied | A principal that does not outrank an account holding a system role (System Owner or System Admin) tried to change it: its fields, status, deletion, password, 2FA, lockout, role assignments, system roles, extension or API keys. System Owner > System Admin > none; only a System Owner changes another System Owner; a company principal or API key has no system rank (W1-SEC-01-M1, rbac.md). | Ask a System Owner. |
MPBX-AUTH-TOTP-REQUIRED | unauthenticated | The e-mail and password were right, but the account has TOTP two-factor enabled and the login carried no totp_code. | Ask the user for the 6-digit code of their authenticator app and repeat the login with the same e-mail and password plus totp_code. |
MPBX-AUTH-TOTP-INVALID | unauthenticated | The totp_code (or recovery_code) is wrong, from the wrong time window (one 30-second step of drift is tolerated), or was already used once; or the account's second factor is locked after auth.lockout.max_failures wrong codes in the window from any network (PR #109 review: an account-wide budget, the code is then not checked and a recovery code is not spent). Counts as a failed login towards the network lockout, like a wrong password. | Enter the current code; check the phone's clock. After repeated wrong codes wait for auth.lockout.lockout_secs (doubling per lock in a row) or ask an administrator to clear the sign-in locks. |
MPBX-AUTH-TOTP-CODE-MISMATCH | invalid_argument | POST /api/v1/auth/totp/verify: the code does not match the pending secret. TOTP stays off until a code matches. Also the answer of the first code of a sign-in enrolment and of switching TOTP off when the code is wrong or the account's second factor is locked (the same account-wide budget as MPBX-AUTH-TOTP-INVALID). | Re-scan the secret from POST /api/v1/auth/totp/enroll and send the current code. |
MPBX-AUTH-TOTP-ALREADY-ENABLED | conflict | Enrolment was requested while TOTP is already enabled for the account. An active second factor is never replaced silently. | An administrator resets the factor first (user administration), then enrol again. |
MPBX-AUTH-TOTP-NOT-ENROLLED | conflict | POST /api/v1/auth/totp/verify without a pending enrolment (never enrolled, or already confirmed), or enrolment for an account that has no local password. | Call POST /api/v1/auth/totp/enroll first. |
MPBX-AUTH-TOTP-UNAVAILABLE | unavailable | The server has no secrets keyring (MPBX_MASTER_KEY not loaded), so TOTP secrets cannot be sealed or opened. Login of an account that has TOTP enabled fails closed with this code. | Start the server with the install secrets from mpbx init. |
MPBX-AUTH-BUSY | unavailable | Every password-hashing slot stayed busy for 2 seconds, so the password was not checked (HTTP 503 with Retry-After). Argon2 costs about 19 MiB and one CPU per check, so the server runs at most two per CPU at a time; this is the bound on unauthenticated hashing work during a login flood. Nothing about the account was checked or changed, and the failure does not count towards the lockout. Retryable. | Retry after a moment. If it happens without a flood, look at the MPBX-AUTH-BUSY warnings in the log and at the host's CPU. |
MPBX-AUTH-TOTP-ENROLMENT-REQUIRED | unauthenticated | The password was right, but the company's two-factor policy covers the account (/api/v1/two-factor-policy: everyone, or one of its roles) and it has no authenticator yet. No session was opened; nothing is enrolled silently. | Explain the policy to the user, call POST /api/v1/auth/totp/enrolment with the same e-mail and password to get the secret (QR code), then sign in with the first code (totp_code): that confirms the authenticator and returns the recovery codes once. |
MPBX-AUTH-TOTP-ENROLMENT-NOT-REQUIRED | conflict | POST /api/v1/auth/totp/enrolment for an account the policy does not cover (it may still enrol after signing in). | Sign in, then enrol under Account security. |
MPBX-AUTH-TOTP-ENROLMENT-CODE-INVALID | unauthenticated | POST /api/v1/auth/totp/enrolment without the one-time code mailed by POST /api/v1/auth/totp/enrolment/code, or with a code that is wrong, expired (10 minutes), already used, replaced by a newer one, burnt after 5 wrong tries, or sent to an address the account no longer has (FU-AUTH01-L3). A wrong code also counts towards the sign-in lockout. | Ask for a new code (POST /api/v1/auth/totp/enrolment/code) and type the one from the newest mail. |
MPBX-AUTH-TOTP-ENROLMENT-CODE-THROTTLED | conflict (HTTP 429) | POST /api/v1/auth/totp/enrolment/code less than a minute after the last code, or after 5 codes for the account (or its address) or 20 from the client network within an hour. Retry-After is set. | Wait, then use the newest code already in the mailbox. |
MPBX-AUTH-TOTP-ENROLMENT-MAIL-UNAVAILABLE | unavailable | The enrolment code cannot be e-mailed: the company has no e-mail provider (and the install has no [email.smtp]), or the provider refused the mail. The code was voided; nothing is enrolled. | Configure the e-mail provider (Settings, E-mail), or an administrator lifts the two-factor policy for the account until it is set up. |
MPBX-AUTH-TOTP-POLICY | conflict | POST /api/v1/auth/totp/disable for an account the company's two-factor policy covers. | Ask an administrator to change the policy or to reset the factor (POST /api/v1/users/{id}/two-factor-reset). |
MPBX-AUTH-REAUTH-FAILED | permission_denied | A sensitive change of one's own account asks for the current password (TOTP enrolment and removal, new recovery codes, resetting one's own password through the user routes) and it was wrong, or sign-in from this network is locked. Counts towards the lockout like a wrong sign-in. HTTP 403, so a client does not mistake it for an expired session. | Enter the current password. |
MPBX-AUTH-INVITE-INVALID | unauthenticated | The invitation link is unknown, expired, already used, replaced by a newer invitation, or the account was disabled or already has a password. One code for all, so the answer reveals nothing. | Ask the administrator to send a new invitation (POST /api/v1/users/{id}/invitation). |
MPBX-AUTH-INVITE-ONBOARDED | conflict | An invitation was requested for an account that already has a password. | Use the password reset instead. |
MPBX-AUTH-INVITE-HOST | conflict | POST /api/v1/users/{id}/invitation was sent to a web address that is not the company's own (in Multi Company mode, another company's address or the install address for a company that is not the default one). The link in the mail is built from that address, so it would not lead to the company. | Send the invitation from the company's own web address (<company>.<pbx domain>). Behind a proxy or another public name, send it from the public name people open and keep the original Host (see the auth guide, FU-AUTH01-L5). |
First-run setup and step-up (W4-WEB-06)
Raised by the setup routes (/api/v1/setup/*) and POST /api/v1/auth/elevate. Guide:
first-run setup wizard.
| Code | Kind | Meaning | What to do |
|---|---|---|---|
MPBX-SETUP-TOKEN-INVALID | unauthenticated | The setup link's token is wrong or incomplete, or this install has no setup token (MPBX_SETUP_TOKEN_SHA256 unset or malformed). One code for all, so a probe learns nothing. Refused attempts are rate limited per client network and recorded in the install audit log (setup.refused). | Use the newest link the installer printed. Issue a new one with mpbx-ctl setup-url (VM) or by deleting the MPBX_SETUP_TOKEN_* values and running mpbx init again (Compose, Kubernetes); the old link stops working. |
MPBX-SETUP-TOKEN-EXPIRED | unauthenticated | The token is right but past MPBX_SETUP_TOKEN_EXPIRES_AT (24 hours after mpbx init by default). | Issue a new link as above. |
MPBX-SETUP-COMPLETE | conflict | The first System Owner exists: setup was completed with the link (the token is spent), or the database already has a System Owner (a restore, a seeded install). The setup token routes never create another owner, whatever the install secrets still hold. Also the answer of the signed-in setup steps once the wizard is finished. | Sign in as usual. To add administrators, a System Owner grants roles in the console. |
MPBX-SETUP-OWNER-PENDING | conflict | A System Owner was already created with the link and waits for its authenticator code. | Finish it (POST /api/v1/setup/owner/confirm), get a new QR code (POST /api/v1/setup/owner/totp), or start over (POST /api/v1/setup/owner/reset). |
MPBX-SETUP-NO-OWNER-PENDING | conflict | Confirming, restarting or resetting the owner while none waits for confirmation. | Create the owner first (POST /api/v1/setup/owner). |
MPBX-SETUP-CREDENTIALS-INVALID | unauthenticated | The e-mail address or password does not match the System Owner created with the link. A wrong password counts towards the sign-in lockout of that account. | Enter the e-mail and password chosen in the first step, or start over. |
MPBX-AUTH-STEP-UP-UNAVAILABLE | conflict | POST /api/v1/auth/elevate: install-wide access is confirmed with a code of the account's authenticator, and this account has none confirmed. | Set up two-factor sign-in under Account security, then try again. |