3.3 KiB
3.3 KiB
type, title, description, resource, tags, timestamp
| type | title | description | resource | tags | timestamp | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| database | Admin Operation Tokens | Single-use confirmation tokens backing the destructive admin System operations (restore-backup, reset-scores, wipe-challenges). | backend/src/database/entities/admin-operation-token.entity.ts |
|
2026-07-23T12:04:50Z |
Schema
| Column | Type | Description |
|---|---|---|
id |
TEXT PK | UUIDv4 generated client-side; the primary key. |
user_id |
TEXT FK | user.id of the administrator who issued the token. FK ON DELETE CASCADE to user. |
operation |
TEXT | One of restore-backup, reset-scores, wipe-challenges (mirrors ADMIN_OPERATION_KINDS). |
token_hash |
TEXT | Hex-encoded SHA-256 of the raw token. The raw token is returned once and never logged or stored. Unique. |
issued_at |
TEXT | ISO-8601 timestamp at issuance. |
expires_at |
TEXT | ISO-8601 timestamp after which the token is invalid (default TTL: SYSTEM_OP_CONFIRM_TOKEN_TTL_MS, 5 min). |
consumed_at |
TEXT null | ISO-8601 timestamp when the token was consumed; null while still valid. |
Indexes
| Index | Purpose |
|---|---|
uq_admin_op_token_hash |
UNIQUE on token_hash — guarantees one-shot use. |
idx_admin_op_token_user_op |
(user_id, operation) — fast per-admin/per-op lookup. |
idx_admin_op_token_expiry |
expires_at — enables the periodic expiry sweep. |
Lifecycle
- Admin re-authenticates with their current password via
POST /api/v1/admin/system/confirmations. The backend verifies the password with Argon2id, thenConfirmationTokenService.issue()generates a 32-byte base64url token, persists only its SHA-256 hash, and returns the raw token plus itsexpiresAt. - The client passes the raw token (and the
stagingIdfor restores) to the matching destructive endpoint (/restore/commit,/scores/reset,/challenges/wipe). ConfirmationTokenService.consume()runs the consumption inside a transaction: it looks the token up by hash, validatesuser_id+operation(+stagingIdfor restores), checksexpires_at > now, and finally performs a conditional updateWHERE consumedAt IS NULLso only the first concurrent caller succeeds. A second attempt returnsSYSTEM_TOKEN_REUSED.purgeExpired()deletes expired rows and consumed rows older than 24h.
Related
- Migration: Admin Operation Tokens Migration
- Service:
backend/src/modules/admin/system/confirmation-token.service.ts - Error codes:
SYSTEM_TOKEN_INVALID,SYSTEM_TOKEN_EXPIRED,SYSTEM_TOKEN_REUSED,SYSTEM_TOKEN_MISMATCH - Admin System API