Auth API
Authentication endpoints for ryOS. These endpoints handle user registration, login, token management, and password operations.
Overview
ryOS uses token-based sessions with a 1-year TTL (refreshed on each validated request).
Browser clients (primary):register, login, token/verify, token/refresh, and session set an httpOnly ryos_auth cookie. The JSON body does not include the raw token.
Programmatic clients: send both headers together:
Authorization: Bearer {token}
X-Username: {username}
Optional request header for timezone persistence: X-User-Timezone: America/Los_Angeles
Most auth-protected endpoints resolve credentials through the shared request-auth utility (both headers required together for programmatic access). register, login, and token/refresh remain explicit handlers.
Endpoint Summary
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/register | Create user + issue session cookie |
| POST | /api/auth/login | Login with password |
| POST | /api/auth/logout | Logout current session |
| POST | /api/auth/logout-all | Logout all sessions |
| GET | /api/auth/session | Restore session from cookie; refresh cookie Max-Age |
| POST | /api/auth/token/verify | Verify token |
| POST | /api/auth/token/refresh | Refresh session cookie |
| GET | /api/auth/password/check | Check if password set |
| POST | /api/auth/password/set | Set or update password |
| GET | /api/auth/tokens | List active tokens |
| POST | /api/auth/recovery/request | Send a password-reset code to all available Telegram/email channels |
| POST | /api/auth/recovery/reset | Reset password with a code; invalidates sessions |
| GET | /api/auth/email/status | Recovery-email status (masked) |
| POST | /api/auth/email/set | Set/replace recovery email + send verify code |
| POST | /api/auth/email/verify | Verify recovery email with a code |
| POST | /api/auth/email/remove | Remove recovery email |
| POST | /api/auth/account/delete | Permanently delete own account |
Endpoints
Register User
Create a new user account and receive a session cookie.
POST /api/auth/register
Content-Type: application/json
{
"username": "alice",
"password": "testpassword123"
}
Response (201, new account):
{
"user": { "username": "alice" }
}
An httpOnly session cookie is set via Set-Cookie.
{
"user": { "username": "alice" }
}
Login
Authenticate with username and password.
POST /api/auth/login
Content-Type: application/json
{
"username": "alice",
"password": "testpassword123"
}
Optional body field: oldToken — rotates session and invalidates the previous token.
{
"username": "alice",
"timeZone": "America/Los_Angeles"
}
Session cookie is set; no token field in the JSON body.
Session
Restore session from the httpOnly cookie.
GET /api/auth/session
Response (200, anonymous):
{
"authenticated": false
}
Response (200, authenticated):
{
"authenticated": true,
"username": "alice",
"expired": false,
"timeZone": "America/Los_Angeles"
}
Logout
Invalidate the current session token.
POST /api/auth/logout
Authorization: Bearer {token}
X-Username: alice
Response (200):
{
"success": true,
"message": "Logged out successfully"
}
Logout All Sessions
Invalidate all active tokens for the user.
POST /api/auth/logout-all
Authorization: Bearer {token}
X-Username: alice
Response (200):
{
"success": true,
"message": "Logged out from 2 devices",
"deletedCount": 2
}
Verify Token
Check if a token is valid.
POST /api/auth/token/verify
Content-Type: application/json
{
"username": "alice",
"token": "..."
}
Headers (Authorization + X-Username) are an optional fallback.
{
"valid": true,
"username": "alice",
"message": "Token is valid"
}
If the token is in grace-period mode:
{
"valid": true,
"username": "alice",
"expired": true,
"message": "Token is within grace period"
}
Refresh Token
Refresh the session cookie before/after expiry (within grace period).
POST /api/auth/token/refresh
Content-Type: application/json
{
"username": "alice",
"oldToken": "previous-token"
}
Body may omit credentials when the httpOnly cookie is present.
Response (200):{
"refreshed": true
}
Cookie is updated.
Check Password Status
Check if a user has set a password.
GET /api/auth/password/check
Authorization: Bearer {token}
X-Username: alice
Response (200):
{
"hasPassword": true,
"username": "alice"
}
Set Password
Set or update the user's password. Requires currentPassword when a password is already set.
POST /api/auth/password/set
Authorization: Bearer {token}
X-Username: alice
Content-Type: application/json
{
"password": "newSecurePassword123",
"currentPassword": "oldPassword123"
}
Response (200):
{
"success": true
}
List Active Tokens
Get all active session tokens for the user.
GET /api/auth/tokens
Authorization: Bearer {token}
X-Username: alice
Response (200):
{
"tokens": [
{
"maskedToken": "...c0ffee12",
"createdAt": 1704067200000,
"isCurrent": true
}
],
"count": 1
}
Account Recovery
Self-service recovery lets a user who forgot their password set a new one using a single-use code delivered to every recovery channel the account has available: a linked Telegram chat and/or a verified recovery email.
Codes are short numeric strings, stored only as salted SHA-256 hashes in Redis, single-use, with a short TTL (~15 min) and a per-code attempt cap. Requests are rate-limited per IP and per identifier.
Request a Reset Code
POST /api/auth/recovery/request
Content-Type: application/json
{
"identifier": "alice" // username OR verified recovery email
}
Response (200) — always generic (anti-enumeration):
{
"success": true,
"message": "If an account with that information exists, a reset code has been sent."
}
The endpoint never reveals whether the account exists or which channels are configured. Callers do not choose a channel. When a matching account has at least one usable channel, one code is issued and sent to every available channel. If no channel can deliver it, the code is discarded.
Reset Password
POST /api/auth/recovery/reset
Content-Type: application/json
{
"identifier": "alice", // username OR verified recovery email
"code": "123456",
"newPassword": "newSecurePassword123"
}
On success the password is replaced, all existing sessions are invalidated, and a fresh session cookie is issued. Invalid/expired/used codes and unknown accounts return a generic 400 Invalid or expired reset code.
{
"success": true,
"username": "alice"
}
Recovery Email
Email is an optional channel that requires both RESEND_API_KEY and RECOVERY_EMAIL_FROM to be set. If either is missing, email/set returns 503 and email/status reports emailConfigured: false; recovery still works via Telegram.
Email Status
GET /api/auth/email/status
Authorization: Bearer {token}
X-Username: alice
{
"hasEmail": true,
"email": "a***@example.com",
"emailVerified": true,
"emailConfigured": true
}
Set / Verify / Remove
POST /api/auth/email/set { "email": "[email protected]" } # sends a code
POST /api/auth/email/verify { "code": "123456" } # marks verified
POST /api/auth/email/remove # clears email
set and remove require a fresh (non-grace) token. verify writes a reverse
index so the email can be used as a recovery identifier.
Delete Account
Permanently delete the authenticated user's own account and all associated data (profile, password, sessions, recovery-email index, Telegram link, and Sync v2 data). Requires a fresh (non-grace) token.
POST /api/auth/account/delete
Authorization: Bearer {token}
X-Username: alice
Content-Type: application/json
{
"confirm": true,
"confirmUsername": "alice",
"currentPassword": "currentPassword123" // required when a password is set
}
The admin account (ryo) cannot self-delete. The clearing Set-Cookie header is returned on success.
{
"success": true
}
Environment
| Variable | Purpose |
|---|---|
TELEGRAM_BOT_TOKEN | Required to deliver reset codes over Telegram |
RESEND_API_KEY | Required for the recovery-email channel (Resend); must be set together with RECOVERY_EMAIL_FROM |
RECOVERY_EMAIL_FROM | Required for the recovery-email channel — From address for recovery email (e.g. ryOS <[email protected]>); must be set together with RESEND_API_KEY |
Error Responses
| Status | Error | Description |
|---|---|---|
| 400 | Invalid request | Missing/invalid parameters (or partial auth headers) |
| 401 | Invalid credentials | Wrong username or password |
| 401 | Unauthorized - invalid token | Token is invalid for username |
| 403 | Unauthorized / Forbidden - Admin access required | Origin or permissions blocked |
| 404 | User not found | Username doesn't exist |
| 409 | Username already taken | Register collision with different password |
| 429 | Rate limit exceeded | Too many requests |
Related
- Rooms API - Room endpoints
- Messages API - Message endpoints
- API Design Guide - API patterns and conventions