| Environment | URL | Purpose |
|---|---|---|
| Production | http://localhost:3002 |
Production deployment |
| External (M5) | https://m5api.momentry.ddns.net |
Remote access |
All examples in this documentation use these environment variables:
API="http://localhost:3002"
KEY="your-api-key-here"
All endpoints under /api/v1/* require authentication.
The following endpoints are public (no auth needed):
GET /healthPOST /api/v1/auth/loginPOST /api/v1/auth/logoutThe 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 |
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:
# Using API key instead of JWT
curl -s "$API/api/v1/files/scan" -H "X-API-Key: muser_demo_key_32chars_abcdef1234567890"
# 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": 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
{
"success": false,
"message": "Invalid username or password"
}
JWT is preferred for API clients (CLI scripts, WordPress). It is validated by the middleware without a database lookup (stateless).
# 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.
Browser-based clients (Portal) get a session cookie automatically after login. The browser sends the cookie with every request—no manual header needed.
# 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).
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.
momentry api-key create "My API Key" --key-type user
# Logout using the session cookie (browser)
curl -X POST "$API/api/v1/auth/logout" \
-H "Cookie: session_id=<uuid>"
| 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.) |
# 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
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 │
└──────────────────────┘
| HTTP | When |
|---|---|
401 |
Missing or invalid authentication |
401 |
Session expired or logged out |
401 |
JWT expired |
401 |
API key revoked or inactive |
POST /api/v1/resource/tmdb/check — test authentication + TMDb API connectivityGET /health/detailed — view auth status (integrations section)