Перейти к содержанию

Admin authentication

Overview

Platform admin access is restricted to a single configured operator (Mihaham by default). Authentication uses a one-time password (OTP) delivered via Telegram bot command /admin login. The web admin panel verifies the OTP and issues a short-lived admin JWT.

FR: FR-057, FR-058

Configuration

Env var Default Description
ADMIN_TELEGRAM_ID Numeric Telegram user ID of the sole admin
ADMIN_USERNAME Mihaham Username required on web login (case-insensitive)
ADMIN_OTP_TTL_SECONDS 300 OTP validity (5 minutes)
ADMIN_JWT_TTL_HOURS 8 Admin session duration

Both API and bot services read ADMIN_TELEGRAM_ID from .env.

Flow

sequenceDiagram
    participant Admin as Admin
    participant Bot as telegram_bot
    participant API as API
    participant Redis as Redis
    participant Web as admin_UI

    Admin->>Bot: /admin login
    Bot->>Bot: from_user.id == ADMIN_TELEGRAM_ID?
    Bot->>API: POST /auth/admin/otp/request {telegram_id}
    API->>Redis: SET admin:otp:{id} code TTL
    API-->>Bot: {code, expires_in}
    Bot->>Admin: DM with 6-digit code
    Admin->>Web: /admin/login
    Web->>API: POST /auth/admin/otp/verify {username, code}
    API->>Redis: validate + delete OTP
    API-->>Web: {access_token, token_type: admin}
    Web->>API: GET /admin/games (Authorization: Bearer admin JWT)

OTP request (POST /auth/admin/otp/request)

  • Caller: Telegram bot only (internal service call).
  • Body: { "telegram_id": 123456789 }
  • Validation: telegram_id must equal ADMIN_TELEGRAM_ID.
  • Storage: Redis key admin:otp:{telegram_id} → 6-digit code; TTL = ADMIN_OTP_TTL_SECONDS.
  • Rate limit: Max 3 requests per 15 minutes per telegram ID.
  • Response: { "expires_in": 300 } — code is not returned in HTTP response (bot receives it from a dedicated internal field or the bot generates and stores via API — see implementation).

OTP verify (POST /auth/admin/otp/verify)

  • Caller: Web admin login page.
  • Body: { "username": "Mihaham", "code": "123456" }
  • Validation:
  • Username matches ADMIN_USERNAME (case-insensitive).
  • Code matches Redis value for ADMIN_TELEGRAM_ID.
  • Max 3 failed attempts per OTP; then OTP invalidated.
  • Response: { "access_token": "...", "token_type": "admin", "expires_in": 28800 }
  • Rate limit: Max 10 verify attempts per 15 minutes per IP.

Admin JWT

Claim Value
sub "admin"
type "admin"
username Mihaham
exp now + ADMIN_JWT_TTL_HOURS

Header: Authorization: Bearer <admin_jwt>

Admin tokens are stored separately from player tokens in the web client (tabletime_admin_token).

Bot commands

Command Who Action
/admin Admin only Help text for admin commands
/admin login Admin only Request OTP and send DM with code

Non-admin users receive a generic “unknown command” or no response.

Threat model

Threat Mitigation
OTP brute force 6-digit code + 3 attempts + TTL 5 min + rate limits
OTP interception Short TTL; single use; delivered only to configured Telegram ID
Stolen admin JWT 8 h TTL; HTTPS only in production
Unauthorized audit access GET /games/{id}/audit requires admin JWT
OTP in application logs Never log the code value

Prerequisites

  1. Admin must send /start to the bot at least once (Telegram DM requirement).
  2. ADMIN_TELEGRAM_ID must match the admin's numeric user ID.
  3. BOT_TOKEN must be valid in both API and bot services.