Authentication REST API
Manager's public authentication endpoints live under /api/auth/*. Except for the WebView HTML page identified below, responses use the standard envelope:
{
"success": true,
"code": 0,
"message": "",
"data": {}
}Fields use snake_case. Business refusals (such as a wrong password or rejected credential change) normally remain HTTP 200, so clients must inspect success and code. A protected request without a valid login session returns HTTP 401 with the same envelope shape.
Current Endpoints
| Method | Path | Purpose |
|---|---|---|
POST | /api/auth/login | Sign in with username or email; an input containing @ uses only the email lane |
POST | /api/auth/logout | Idempotently end the current browser session |
GET | /api/auth/me | Return the current-user DTO in the standard envelope |
PATCH | /api/auth/credentials | Change credentials for the current account |
POST | /api/auth/register | Register |
POST | /api/auth/verify-email | Complete email verification with a single-use token |
POST | /api/auth/resend-verification | Resend verification with a neutral response (anonymous; every input gets the same success) |
POST | /api/auth/pending-verification/resend | Resend verification for the pending account whose password this session just proved; no body, real outcome |
POST | /api/auth/forgot-password | Request a password-reset email with a neutral response |
POST | /api/auth/reset-password | Set a new password with a single-use token |
POST | /api/auth/confirm-email-change | Confirm an email change for the current account |
POST | /api/auth/confirm-account-deletion | Confirm deletion and start the cooling-off period |
GET | /api/auth/config | Return public registration, username, and challenge settings |
GET | /api/auth/turnstile | Return the manager-origin Turnstile HTML page for native mobile WebViews (not a JSON envelope) |
GET | /api/auth/providers | Return the currently available external sign-in providers |
The data returned by POST /api/auth/login is LoginOutcomeDto. Alongside the existing members, a correct password on an account that has not verified its email answers code = 35 (EMAIL_NOT_VERIFIED) and carries email_masked, the masked destination of the verification mail (for example a***@ex****.com). The standalone signaling server has no such account state and always leaves it null; clients must also tolerate the member being absent entirely. The same response grants that browser session a resend authorization lasting up to 24 hours (stored with the session and renewed on every use; a shorter session idle timeout wins).
POST /api/auth/pending-verification/resend takes no body and is authorized solely by that session grant:
- Queued:
success = truewithdata.retry_after_secset tonull. - Throttled:
code = 32(TOO_MANY_ATTEMPTS) withdata.retry_after_secset to the seconds left on the axis that refused it. An administrator who sets a daily cap to0disables sending outright, leaving no window to wait out, so the member isnulland clients must render wording without a countdown. A refused request consumes no allowance. - No usable grant (never signed in, signed out, account already activated, or pending deletion):
code = 3(PERMISSION_ERROR), with no account information in the response.
The data returned by GET /api/auth/me is CurrentUserDto, including an optional user id, name, avatar, email, access level, and optional target connection for the current session. An unauthenticated client must use HTTP 401 and the standard envelope rather than interpreting a historical template response.
Endpoints that send mail (register, resend verification, forgot password, email change, deletion confirmation, and /api/oauth/registration/{submit,resend,fix-email}) write the body in the language of the request that triggered it: the shared lrdm_locale cookie first (written only when the user explicitly switches the interface language), then Accept-Language, then English. Verification mail is delivered asynchronously, and the language is stored with the queued row, so neither the delivery time nor the delivering instance changes it — and switching the interface language afterwards does not rewrite a mail that is already queued.
Change credentials by posting required current_username and current_password, plus optional new_username and new_password, to PATCH /api/auth/credentials; clients should use only the current paths listed above. Third-party OAuth authorization, callback, and identity linking remain under /api/oauth/*.