← Back to index Logout

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:

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):

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:

# 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 Response

{
  "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)

{
  "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).

# 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.

# 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

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)

momentry api-key create "My API Key" --key-type user

Logout

# 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

# 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