feat: ASRX hybrid pipeline, identity history, worker fixes, checkpoint system

This commit is contained in:
Accusys
2026-06-02 07:13:23 +08:00
parent e3066c3f49
commit e1572907ae
198 changed files with 43705 additions and 8910 deletions
+280
View File
@@ -0,0 +1,280 @@
<!-- module: auth -->
<!-- description: Authentication — login, logout, JWT, session cookie, API key -->
<!-- depends: -->
## Base URL
| Environment | URL | Purpose |
|-------------|-----|---------|
| Production | `http://localhost:3002` | Production deployment |
| External (M5) | `https://m5api.momentry.ddns.net` | Remote access |
## Variables
All examples in this documentation use these environment variables:
```bash
API="http://localhost:3002"
KEY="your-api-key-here"
```
## Authentication
All endpoints under `/api/v1/*` require authentication.
The following endpoints are public (no auth needed):
- `GET /health`
- `POST /api/v1/auth/login`
- `POST /api/v1/auth/logout`
### Three Authentication Modes
The system supports three authentication methods, checked in **priority order** by the middleware:
```
Middleware priority:
1. Session Cookie (Portal/browser)
2. JWT Bearer (API clients, CLI)
3. API Key Header (legacy compatibility)
4. API Key Query Param (?api_key=)
```
| Mode | Transport | Expiry | Scope | Best for |
|------|-----------|--------|-------|----------|
| **Session Cookie** | `Cookie: session_id=<session_id>` | 24h | per-browser session | Portal (browser) |
| **JWT** | `Authorization: Bearer <token>` | 1h | per-login token | API clients, CLI, scripts |
| **API Key** | `X-API-Key: <key>` | 90d | fixed key for automation | Legacy scripts, WordPress |
---
### Login
**Default accounts & API keys:**
| Username | Password | API Key | Role |
|----------|----------|---------|------|
| `admin` | `admin` | — | admin |
| `demo` | `demo` | `muser_demo_key_32chars_abcdef1234567890` | user |
The demo API key is set via `MOMENTRY_DEMO_API_KEY` env var and can be used in place of JWT for marcom integrations:
```bash
# Using API key instead of JWT
curl -s "$API/api/v1/files/scan" -H "X-API-Key: muser_demo_key_32chars_abcdef1234567890"
```
```bash
# Login as admin
curl -s -X POST "$API/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "admin"}'
# Login as demo user
curl -s -X POST "$API/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username": "demo", "password": "demo"}'
```
#### Success Response
```json
{
"success": true,
"jwt": "eyJhbGciOiJIUzI1NiIs...",
"api_key": "muser_...",
"user": {
"username": "admin",
"role": "admin"
},
"expires_at": "2026-05-18T13:00:00Z"
}
```
| Field | Type | Description |
|-------|------|-------------|
| `jwt` | string | JWT access token. Use as `Authorization: Bearer <jwt>`. Expires in 1 hour. |
| `api_key` | string | Legacy API key. Use as `X-API-Key: <key>`. Good for 90 days. |
| `user.username` | string | Username |
| `user.role` | string | Role: `admin`, `user`, or `readonly` |
| `expires_at` | string | ISO8601 timestamp of JWT expiration |
The login endpoint also sets a `Set-Cookie` header for browser-based clients:
```
Set-Cookie: session_id=<session_id>; Path=/; HttpOnly; SameSite=Strict; Max-Age=86400
```
#### Error Response (401)
```json
{
"success": false,
"message": "Invalid username or password"
}
```
---
### Using JWT
JWT is preferred for API clients (CLI scripts, WordPress). It is validated by the middleware without a database lookup (stateless).
```bash
# Login and capture JWT
JWT=$(curl -s -X POST "$API/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' | python3 -c "import json,sys;print(json.load(sys.stdin)['jwt'])")
# Use JWT for all subsequent requests
curl -H "Authorization: Bearer $JWT" "$API/api/v1/files/scan"
curl -H "Authorization: Bearer $JWT" "$API/api/v1/resource/tmdb"
```
JWT is short-lived (1 hour). When it expires, request a new one via login.
---
### Using Session Cookie (Browser)
Browser-based clients (Portal) get a session cookie automatically after login. The browser sends the cookie with every request—no manual header needed.
```bash
# Login captures the session cookie from Set-Cookie header
curl -v -X POST "$API/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' 2>&1 | grep "Set-Cookie"
# Browser automatically sends: Cookie: session_id=<session_id>
# No manual header needed for subsequent requests
```
The session cookie is HttpOnly (not accessible from JavaScript) and SameSite=Strict (protected against CSRF).
---
### Using Legacy API Key
```bash
curl -H "X-API-Key: $KEY" "$API/api/v1/files/scan"
# Also accepted via Bearer header (non-JWT format) or query parameter:
curl -H "Authorization: Bearer $KEY" "$API/api/v1/files/scan"
curl "$API/api/v1/files/scan?api_key=$KEY"
```
API keys are validated via SHA256 hash lookup in the database. They are long-lived (90 days) and intended for automation.
### Obtaining an API Key (CLI)
```bash
momentry api-key create "My API Key" --key-type user
```
---
### Logout
```bash
# Logout using the session cookie (browser)
curl -X POST "$API/api/v1/auth/logout" \
-H "Cookie: session_id=<uuid>"
```
#### What logout does
| Auth mode | Effect |
|-----------|--------|
| **Session Cookie** | Session deleted from database. Same cookie returns 401 on subsequent requests. |
| **JWT** | JWT remains valid until expiry. (JWT is stateless — logout adds JWT to a blacklist only if API key mode is used.) |
| **API Key** | API key remains valid. (Legacy keys are shared across sessions — revoking would break other clients.) |
#### Example: full session lifecycle
```bash
# 1. Login
SESSION_ID=$(curl -s -D - -X POST "$API/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' | grep "Set-Cookie" | sed 's/.*session_id=\([^;]*\).*/\1/')
# 2. Use session (works)
curl -s -o /dev/null -w "HTTP %{http_code}\n" "$API/api/v1/resource/tmdb" \
-H "Cookie: session_id=$SESSION_ID"
# → HTTP 200
# 3. Logout
curl -s -X POST "$API/api/v1/auth/logout" \
-H "Cookie: session_id=$SESSION_ID"
# → {"success": true}
# 4. Use session again (rejected)
curl -s -o /dev/null -w "HTTP %{http_code}\n" "$API/api/v1/resource/tmdb" \
-H "Cookie: session_id=$SESSION_ID"
# → HTTP 401
```
---
### Authentication Flow Summary
```
Login Request
┌──────────────────┐
│ 1. Check users │ ← users table (argon2 password verify)
│ table │
└──────┬───────────┘
┌───┴───┐
│ match │
└───┬───┘
┌──────────────────┐
│ 2. Create JWT │ ← 1h expiry, signed with JWT_SECRET
├──────────────────┤
│ 3. Create │ ← 24h expiry, stored in sessions table
│ session │
├──────────────────┤
│ 4. Set-Cookie │ ← HttpOnly, SameSite=Strict, Path=/
├──────────────────┤
│ 5. Return │ ← JWT + api_key + user info to client
└──────────────────┘
```
```
Protected Request
┌──────────────────────┐
│ Middleware checks: │
│ │
│ 1. Cookie session? │ → DB lookup session → get api_key → verify
│ │
│ 2. JWT Bearer? │ → verify JWT signature → decode claims
│ │
│ 3. X-API-Key? │ → SHA256 hash → DB lookup → verify
│ │
│ 4. ?api_key=? │ → same as #3
│ │
│ 5. None → 401 │
└──────────────────────┘
```
---
### Error Responses
| HTTP | When |
|------|------|
| `401` | Missing or invalid authentication |
| `401` | Session expired or logged out |
| `401` | JWT expired |
| `401` | API key revoked or inactive |
---
### Related
- `POST /api/v1/resource/tmdb/check` — test authentication + TMDb API connectivity
- `GET /health/detailed` — view auth status (integrations section)