396 lines
21 KiB
HTML
396 lines
21 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>01 Auth - Momentry API Docs</title>
|
|
<style>
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; color: #333; padding: 40px; }
|
|
.container { max-width: 960px; margin: 0 auto; background: white; border-radius: 12px; box-shadow: 0 2px 12px rgba(0,0,0,0.08); padding: 40px; }
|
|
h1 { font-size: 24px; margin: 24px 0 12px; }
|
|
h2 { font-size: 20px; margin: 20px 0 10px; color: #222; }
|
|
h3 { font-size: 16px; margin: 16px 0 8px; color: #444; }
|
|
p { line-height: 1.6; margin: 8px 0; }
|
|
table { border-collapse: collapse; width: 100%; margin: 12px 0; font-size: 14px; }
|
|
th, td { border: 1px solid #ddd; padding: 8px 12px; text-align: left; }
|
|
th { background: #f0f0f0; font-weight: 600; }
|
|
code { background: #f0f0f0; padding: 2px 6px; border-radius: 3px; font-size: 13px; }
|
|
pre { background: #f8f8f8; border: 1px solid #ddd; border-radius: 6px; padding: 12px; overflow-x: auto; margin: 12px 0; }
|
|
pre code { background: none; padding: 0; }
|
|
a { color: #0066cc; }
|
|
.back { display: inline-block; margin-bottom: 20px; color: #666; }
|
|
.back:hover { color: #333; }
|
|
.topbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
|
|
.logout-btn { font-size: 13px; color: #999; text-decoration: none; }
|
|
.logout-btn:hover { color: #cc0000; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="topbar">
|
|
<a class="back" href="index.html">← Back to index</a>
|
|
<a class="logout-btn" href="#" onclick="fetch('/api/v1/auth/logout',{method:'POST'}).then(()=>window.location.reload());return false">Logout</a>
|
|
</div>
|
|
<!-- module: auth -->
|
|
<!-- description: Authentication — login, logout, JWT, session cookie, API key -->
|
|
<!-- depends: -->
|
|
|
|
<h2>Base URL</h2>
|
|
<table class="table">
|
|
<thead>
|
|
<tr>
|
|
<th>Environment</th>
|
|
<th>URL</th>
|
|
<th>Purpose</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>Production</td>
|
|
<td><code>http://localhost:3002</code></td>
|
|
<td>Production deployment</td>
|
|
</tr>
|
|
<tr>
|
|
<td>External (M5)</td>
|
|
<td><code>https://m5api.momentry.ddns.net</code></td>
|
|
<td>Remote access</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h2>Variables</h2>
|
|
<p>All examples in this documentation use these environment variables:</p>
|
|
<div class="codehilite"><pre><span></span><code><span class="nv">API</span><span class="o">=</span><span class="s2">"http://localhost:3002"</span>
|
|
<span class="nv">KEY</span><span class="o">=</span><span class="s2">"your-api-key-here"</span>
|
|
</code></pre></div>
|
|
|
|
<h2>Authentication</h2>
|
|
<p>All endpoints under <code>/api/v1/*</code> require authentication.
|
|
The following endpoints are public (no auth needed):</p>
|
|
<ul>
|
|
<li><code>GET /health</code></li>
|
|
<li><code>POST /api/v1/auth/login</code></li>
|
|
<li><code>POST /api/v1/auth/logout</code></li>
|
|
</ul>
|
|
<h3>Three Authentication Modes</h3>
|
|
<p>The system supports three authentication methods, checked in <strong>priority order</strong> by the middleware:</p>
|
|
<div class="codehilite"><pre><span></span><code>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=)
|
|
</code></pre></div>
|
|
|
|
<table class="table">
|
|
<thead>
|
|
<tr>
|
|
<th>Mode</th>
|
|
<th>Transport</th>
|
|
<th>Expiry</th>
|
|
<th>Scope</th>
|
|
<th>Best for</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><strong>Session Cookie</strong></td>
|
|
<td><code>Cookie: session_id=<session_id></code></td>
|
|
<td>24h</td>
|
|
<td>per-browser session</td>
|
|
<td>Portal (browser)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>JWT</strong></td>
|
|
<td><code>Authorization: Bearer <token></code></td>
|
|
<td>1h</td>
|
|
<td>per-login token</td>
|
|
<td>API clients, CLI, scripts</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>API Key</strong></td>
|
|
<td><code>X-API-Key: <key></code></td>
|
|
<td>90d</td>
|
|
<td>fixed key for automation</td>
|
|
<td>Legacy scripts, WordPress</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<hr />
|
|
<h3>Login</h3>
|
|
<p><strong>Default accounts & API keys:</strong></p>
|
|
<table class="table">
|
|
<thead>
|
|
<tr>
|
|
<th>Username</th>
|
|
<th>Password</th>
|
|
<th>API Key</th>
|
|
<th>Role</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>admin</code></td>
|
|
<td><code>admin</code></td>
|
|
<td>—</td>
|
|
<td>admin</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>demo</code></td>
|
|
<td><code>demo</code></td>
|
|
<td><code>muser_demo_key_32chars_abcdef1234567890</code></td>
|
|
<td>user</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>The demo API key is set via <code>MOMENTRY_DEMO_API_KEY</code> env var and can be used in place of JWT for marcom integrations:</p>
|
|
<div class="codehilite"><pre><span></span><code><span class="c1"># Using API key instead of JWT</span>
|
|
curl<span class="w"> </span>-s<span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/files/scan"</span><span class="w"> </span>-H<span class="w"> </span><span class="s2">"X-API-Key: muser_demo_key_32chars_abcdef1234567890"</span>
|
|
</code></pre></div>
|
|
|
|
<div class="codehilite"><pre><span></span><code><span class="c1"># Login as admin</span>
|
|
curl<span class="w"> </span>-s<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/auth/login"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-H<span class="w"> </span><span class="s2">"Content-Type: application/json"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-d<span class="w"> </span><span class="s1">'{"username": "admin", "password": "admin"}'</span>
|
|
|
|
<span class="c1"># Login as demo user</span>
|
|
curl<span class="w"> </span>-s<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/auth/login"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-H<span class="w"> </span><span class="s2">"Content-Type: application/json"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-d<span class="w"> </span><span class="s1">'{"username": "demo", "password": "demo"}'</span>
|
|
</code></pre></div>
|
|
|
|
<h4>Success Response</h4>
|
|
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
|
|
<span class="w"> </span><span class="nt">"success"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"jwt"</span><span class="p">:</span><span class="w"> </span><span class="s2">"eyJhbGciOiJIUzI1NiIs..."</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"api_key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"muser_..."</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"user"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
|
<span class="w"> </span><span class="nt">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"admin"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"role"</span><span class="p">:</span><span class="w"> </span><span class="s2">"admin"</span>
|
|
<span class="w"> </span><span class="p">},</span>
|
|
<span class="w"> </span><span class="nt">"expires_at"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-05-18T13:00:00Z"</span>
|
|
<span class="p">}</span>
|
|
</code></pre></div>
|
|
|
|
<table class="table">
|
|
<thead>
|
|
<tr>
|
|
<th>Field</th>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>jwt</code></td>
|
|
<td>string</td>
|
|
<td>JWT access token. Use as <code>Authorization: Bearer <jwt></code>. Expires in 1 hour.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>api_key</code></td>
|
|
<td>string</td>
|
|
<td>Legacy API key. Use as <code>X-API-Key: <key></code>. Good for 90 days.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>user.username</code></td>
|
|
<td>string</td>
|
|
<td>Username</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>user.role</code></td>
|
|
<td>string</td>
|
|
<td>Role: <code>admin</code>, <code>user</code>, or <code>readonly</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>expires_at</code></td>
|
|
<td>string</td>
|
|
<td>ISO8601 timestamp of JWT expiration</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>The login endpoint also sets a <code>Set-Cookie</code> header for browser-based clients:</p>
|
|
<div class="codehilite"><pre><span></span><code><span class="nt">Set-Cookie</span><span class="o">:</span><span class="w"> </span><span class="nt">session_id</span><span class="o">=<</span><span class="nt">session_id</span><span class="o">>;</span><span class="w"> </span><span class="nt">Path</span><span class="o">=/;</span><span class="w"> </span><span class="nt">HttpOnly</span><span class="o">;</span><span class="w"> </span><span class="nt">SameSite</span><span class="o">=</span><span class="nt">Strict</span><span class="o">;</span><span class="w"> </span><span class="nt">Max-Age</span><span class="o">=</span><span class="nt">86400</span>
|
|
</code></pre></div>
|
|
|
|
<h4>Error Response (401)</h4>
|
|
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
|
|
<span class="w"> </span><span class="nt">"success"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Invalid username or password"</span>
|
|
<span class="p">}</span>
|
|
</code></pre></div>
|
|
|
|
<hr />
|
|
<h3>Using JWT</h3>
|
|
<p>JWT is preferred for API clients (CLI scripts, WordPress). It is validated by the middleware without a database lookup (stateless).</p>
|
|
<div class="codehilite"><pre><span></span><code><span class="c1"># Login and capture JWT</span>
|
|
<span class="nv">JWT</span><span class="o">=</span><span class="k">$(</span>curl<span class="w"> </span>-s<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/auth/login"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-H<span class="w"> </span><span class="s2">"Content-Type: application/json"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-d<span class="w"> </span><span class="s1">'{"username":"admin","password":"admin"}'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>python3<span class="w"> </span>-c<span class="w"> </span><span class="s2">"import json,sys;print(json.load(sys.stdin)['jwt'])"</span><span class="k">)</span>
|
|
|
|
<span class="c1"># Use JWT for all subsequent requests</span>
|
|
curl<span class="w"> </span>-H<span class="w"> </span><span class="s2">"Authorization: Bearer </span><span class="nv">$JWT</span><span class="s2">"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/files/scan"</span>
|
|
curl<span class="w"> </span>-H<span class="w"> </span><span class="s2">"Authorization: Bearer </span><span class="nv">$JWT</span><span class="s2">"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/resource/tmdb"</span>
|
|
</code></pre></div>
|
|
|
|
<p>JWT is short-lived (1 hour). When it expires, request a new one via login.</p>
|
|
<hr />
|
|
<h3>Using Session Cookie (Browser)</h3>
|
|
<p>Browser-based clients (Portal) get a session cookie automatically after login. The browser sends the cookie with every request—no manual header needed.</p>
|
|
<div class="codehilite"><pre><span></span><code><span class="c1"># Login captures the session cookie from Set-Cookie header</span>
|
|
curl<span class="w"> </span>-v<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/auth/login"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-H<span class="w"> </span><span class="s2">"Content-Type: application/json"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-d<span class="w"> </span><span class="s1">'{"username":"admin","password":"admin"}'</span><span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s2">"Set-Cookie"</span>
|
|
|
|
<span class="c1"># Browser automatically sends: Cookie: session_id=<session_id></span>
|
|
<span class="c1"># No manual header needed for subsequent requests</span>
|
|
</code></pre></div>
|
|
|
|
<p>The session cookie is HttpOnly (not accessible from JavaScript) and SameSite=Strict (protected against CSRF).</p>
|
|
<hr />
|
|
<h3>Using Legacy API Key</h3>
|
|
<div class="codehilite"><pre><span></span><code>curl<span class="w"> </span>-H<span class="w"> </span><span class="s2">"X-API-Key: </span><span class="nv">$KEY</span><span class="s2">"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/files/scan"</span>
|
|
|
|
<span class="c1"># Also accepted via Bearer header (non-JWT format) or query parameter:</span>
|
|
curl<span class="w"> </span>-H<span class="w"> </span><span class="s2">"Authorization: Bearer </span><span class="nv">$KEY</span><span class="s2">"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/files/scan"</span>
|
|
curl<span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/files/scan?api_key=</span><span class="nv">$KEY</span><span class="s2">"</span>
|
|
</code></pre></div>
|
|
|
|
<p>API keys are validated via SHA256 hash lookup in the database. They are long-lived (90 days) and intended for automation.</p>
|
|
<h3>Obtaining an API Key (CLI)</h3>
|
|
<div class="codehilite"><pre><span></span><code>momentry<span class="w"> </span>api-key<span class="w"> </span>create<span class="w"> </span><span class="s2">"My API Key"</span><span class="w"> </span>--key-type<span class="w"> </span>user
|
|
</code></pre></div>
|
|
|
|
<hr />
|
|
<h3>Logout</h3>
|
|
<div class="codehilite"><pre><span></span><code><span class="c1"># Logout using the session cookie (browser)</span>
|
|
curl<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/auth/logout"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-H<span class="w"> </span><span class="s2">"Cookie: session_id=<uuid>"</span>
|
|
</code></pre></div>
|
|
|
|
<h4>What logout does</h4>
|
|
<table class="table">
|
|
<thead>
|
|
<tr>
|
|
<th>Auth mode</th>
|
|
<th>Effect</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><strong>Session Cookie</strong></td>
|
|
<td>Session deleted from database. Same cookie returns 401 on subsequent requests.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>JWT</strong></td>
|
|
<td>JWT remains valid until expiry. (JWT is stateless — logout adds JWT to a blacklist only if API key mode is used.)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>API Key</strong></td>
|
|
<td>API key remains valid. (Legacy keys are shared across sessions — revoking would break other clients.)</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h4>Example: full session lifecycle</h4>
|
|
<div class="codehilite"><pre><span></span><code><span class="c1"># 1. Login</span>
|
|
<span class="nv">SESSION_ID</span><span class="o">=</span><span class="k">$(</span>curl<span class="w"> </span>-s<span class="w"> </span>-D<span class="w"> </span>-<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/auth/login"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-H<span class="w"> </span><span class="s2">"Content-Type: application/json"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-d<span class="w"> </span><span class="s1">'{"username":"admin","password":"admin"}'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s2">"Set-Cookie"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span><span class="s1">'s/.*session_id=\([^;]*\).*/\1/'</span><span class="k">)</span>
|
|
|
|
<span class="c1"># 2. Use session (works)</span>
|
|
curl<span class="w"> </span>-s<span class="w"> </span>-o<span class="w"> </span>/dev/null<span class="w"> </span>-w<span class="w"> </span><span class="s2">"HTTP %{http_code}\n"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/resource/tmdb"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-H<span class="w"> </span><span class="s2">"Cookie: session_id=</span><span class="nv">$SESSION_ID</span><span class="s2">"</span>
|
|
<span class="c1"># → HTTP 200</span>
|
|
|
|
<span class="c1"># 3. Logout</span>
|
|
curl<span class="w"> </span>-s<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/auth/logout"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-H<span class="w"> </span><span class="s2">"Cookie: session_id=</span><span class="nv">$SESSION_ID</span><span class="s2">"</span>
|
|
<span class="c1"># → {"success": true}</span>
|
|
|
|
<span class="c1"># 4. Use session again (rejected)</span>
|
|
curl<span class="w"> </span>-s<span class="w"> </span>-o<span class="w"> </span>/dev/null<span class="w"> </span>-w<span class="w"> </span><span class="s2">"HTTP %{http_code}\n"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$API</span><span class="s2">/api/v1/resource/tmdb"</span><span class="w"> </span><span class="se">\</span>
|
|
<span class="w"> </span>-H<span class="w"> </span><span class="s2">"Cookie: session_id=</span><span class="nv">$SESSION_ID</span><span class="s2">"</span>
|
|
<span class="c1"># → HTTP 401</span>
|
|
</code></pre></div>
|
|
|
|
<hr />
|
|
<h3>Authentication Flow Summary</h3>
|
|
<div class="codehilite"><pre><span></span><code>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
|
|
└──────────────────┘
|
|
</code></pre></div>
|
|
|
|
<div class="codehilite"><pre><span></span><code>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 │
|
|
└──────────────────────┘
|
|
</code></pre></div>
|
|
|
|
<hr />
|
|
<h3>Error Responses</h3>
|
|
<table class="table">
|
|
<thead>
|
|
<tr>
|
|
<th>HTTP</th>
|
|
<th>When</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>401</code></td>
|
|
<td>Missing or invalid authentication</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>401</code></td>
|
|
<td>Session expired or logged out</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>401</code></td>
|
|
<td>JWT expired</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>401</code></td>
|
|
<td>API key revoked or inactive</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<hr />
|
|
<h3>Related</h3>
|
|
<ul>
|
|
<li><code>POST /api/v1/resource/tmdb/check</code> — test authentication + TMDb API connectivity</li>
|
|
<li><code>GET /health/detailed</code> — view auth status (integrations section)</li>
|
|
</ul>
|
|
<hr />
|
|
<p><em>Updated: 2026-05-19 12:49:24</em></p>
|
|
</div>
|
|
</body>
|
|
</html> |