mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-13 12:35:05 +00:00
Deployed 87ccd666 with MkDocs version: 1.6.1
This commit is contained in:
@@ -1653,10 +1653,10 @@
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#the-health-check-is-always-open" class="md-nav__link">
|
||||
<a href="#the-health-check-needs-an-api-key-too" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
The health check is always open
|
||||
The health check needs an API key too
|
||||
|
||||
</span>
|
||||
</a>
|
||||
@@ -2298,10 +2298,10 @@
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#the-health-check-is-always-open" class="md-nav__link">
|
||||
<a href="#the-health-check-needs-an-api-key-too" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
The health check is always open
|
||||
The health check needs an API key too
|
||||
|
||||
</span>
|
||||
</a>
|
||||
@@ -2493,7 +2493,7 @@
|
||||
<ol>
|
||||
<li>Add an <code>api_secret</code> to the <code>serve</code> section of your <code>unshackle.yaml</code>.</li>
|
||||
<li>Start the server with <code>unshackle serve</code>.</li>
|
||||
<li>Send that secret in the <code>X-Secret-Key</code> header on every request except <code>GET /api/health</code>.</li>
|
||||
<li>Send that secret in the <code>X-Secret-Key</code> header on every request, <code>GET /api/health</code> included.</li>
|
||||
</ol>
|
||||
<div class="language-bash highlight"><span class="filename">A minimal authenticated request</span><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a>curl<span class="w"> </span>-H<span class="w"> </span><span class="s2">"X-Secret-Key: your-secret-key-here"</span><span class="w"> </span><span class="se">\</span>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="w"> </span>http://127.0.0.1:8786/api/services
|
||||
@@ -2614,9 +2614,9 @@
|
||||
<p class="admonition-title">The reference client sets it for you</p>
|
||||
<p>unshackle's own <a href="../../../guide/downloading/">remote download</a> client (<code>RemoteService</code>) sends <code>X-Secret-Key</code> automatically, reading the API key from your <code>remote_services</code> config. It also sends a <code>User-Agent</code> of <code>unshackle/<version></code>. You only deal with the header directly when writing your own client.</p>
|
||||
</div>
|
||||
<h3 id="the-health-check-is-always-open">The health check is always open<a class="headerlink" href="#the-health-check-is-always-open" title="Permanent link">¶</a></h3>
|
||||
<p>One endpoint is exempt from authentication: <code>GET /api/health</code>. It never requires an API key, so you can use it for liveness and version probes without embedding a secret in your monitoring:</p>
|
||||
<div class="language-bash highlight"><span class="filename">No key needed</span><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a>curl<span class="w"> </span>http://127.0.0.1:8786/api/health
|
||||
<h3 id="the-health-check-needs-an-api-key-too">The health check needs an API key too<a class="headerlink" href="#the-health-check-needs-an-api-key-too" title="Permanent link">¶</a></h3>
|
||||
<p><code>GET /api/health</code> reports the running version and commit, so it sits behind the same <code>X-Secret-Key</code> check as every other route. A monitor that probes it sends an API key; a request without one gets the usual <code>401</code> body, which still proves the server is up:</p>
|
||||
<div class="language-bash highlight"><span class="filename">Liveness probe</span><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a>curl<span class="w"> </span>-H<span class="w"> </span><span class="s2">"X-Secret-Key: your-secret-key-here"</span><span class="w"> </span>http://127.0.0.1:8786/api/health
|
||||
</span></code></pre></div>
|
||||
<div class="language-json highlight"><span class="filename">Response</span><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="p">{</span>
|
||||
</span><span id="__span-11-2"><a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a><span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ok"</span><span class="p">,</span>
|
||||
@@ -2792,10 +2792,6 @@ that reads <code>error_code</code> to classify a <code>429</code> must cope with
|
||||
<td><code>127.0.0.1:8786</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Exempt endpoint</td>
|
||||
<td><code>GET /api/health</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Failure status</td>
|
||||
<td><code>401 Unauthorized</code>, or <code>429 Too Many Requests</code> for a key over its rate limit</td>
|
||||
</tr>
|
||||
@@ -2834,7 +2830,7 @@ that reads <code>error_code</code> to classify a <code>429</code> must cope with
|
||||
<p>The header and config are identical between modes, but the code that enforces them differs:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>API-only server</strong> (<code>--api-only</code>, or <code>--remote-only</code> which forces API-only). An <code>api_key_authentication</code> middleware runs on every request. It lets <code>GET /api/health</code> through unconditionally, then reads <code>X-Secret-Key</code>. An empty header returns the <em>"Secret Key is Empty."</em> body. A header that is not a configured user returns <em>"Secret Key is Invalid."</em>. In this mode the accepted-keys map holds your <code>api_secret</code> (labelled <code>api_user</code>, with no devices) plus every key under <code>serve.users</code>. A per-user key therefore authenticates here exactly as it does on the integrated server, and that user's <code>services</code> allowlist applies as usual. With <code>--no-key</code>, this middleware is not installed and the users map is empty.</p>
|
||||
<p><strong>API-only server</strong> (<code>--api-only</code>, or <code>--remote-only</code> which forces API-only). An <code>api_key_authentication</code> middleware runs on every request. It reads <code>X-Secret-Key</code> on every request, <code>GET /api/health</code> included. An empty header returns the <em>"Secret Key is Empty."</em> body. A header that is not a configured user returns <em>"Secret Key is Invalid."</em>. In this mode the accepted-keys map holds your <code>api_secret</code> (labelled <code>api_user</code>, with no devices) plus every key under <code>serve.users</code>. A per-user key therefore authenticates here exactly as it does on the integrated server, and that user's <code>services</code> allowlist applies as usual. With <code>--no-key</code>, this middleware is not installed and the users map is empty.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Integrated server</strong> (default). A <code>serve_authentication</code> middleware wraps pywidevine's authentication (and pyplayready's for <code>/playready*</code> paths), and the REST routes live in the same application, guarded by the same check. Here the accepted-keys map is your full <code>serve</code> config: <code>api_secret</code> (auto-added with access to all loaded devices) plus every entry under <code>users</code>, each with its declared <code>devices</code> / <code>playready_devices</code>.</p>
|
||||
|
||||
@@ -2518,7 +2518,7 @@ here, so use <code>id</code> as the identity and <code>label</code> only for dis
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Only a configured API key gets a row of counters. A request on an open route such as <code>/api/health</code> with an unknown key counts as <code>anonymous</code>, so an unauthenticated caller cannot grow the table.</p>
|
||||
<p>Only a configured API key gets a row of counters. A request that answers with an unknown key counts as <code>anonymous</code>, so an unauthenticated caller cannot grow the table.</p>
|
||||
<p>Every API key the server counts has a row here, the dashboard key included, so a
|
||||
<code>requests_by_key</code> bucket other than <code>anonymous</code> always matches one. A "traffic by key" panel
|
||||
reads the rows here, which are unambiguous, and takes <code>anonymous</code> from <code>requests_by_key</code>. Read
|
||||
|
||||
@@ -3082,11 +3082,11 @@
|
||||
</div>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Interactive docs</p>
|
||||
<p>The server mounts a live Swagger UI at <strong><code>/api/docs/</code></strong> whenever it does not operate in <code>--remote-only</code> mode. Its title is "Unshackle REST API" and its version tracks the installed package version. In API-only mode with an API key configured, the Swagger UI itself sits behind <code>X-Secret-Key</code>. Only <code>/api/health</code> is exempt.</p>
|
||||
<p>The server mounts a live Swagger UI at <strong><code>/api/docs/</code></strong> whenever it does not operate in <code>--remote-only</code> mode. Its title is "Unshackle REST API" and its version tracks the installed package version. In API-only mode with an API key configured, the Swagger UI itself sits behind <code>X-Secret-Key</code>, like every other route.</p>
|
||||
</div>
|
||||
<h2 id="conventions">Conventions<a class="headerlink" href="#conventions" title="Permanent link">¶</a></h2>
|
||||
<ul>
|
||||
<li><strong>Authentication.</strong> Every request except <code>GET /api/health</code> requires the <code>X-Secret-Key</code> header when you configure an API key. <code>--no-key</code> disables the check entirely. See <a href="../authentication/">Authentication</a>.</li>
|
||||
<li><strong>Authentication.</strong> Every request, <code>GET /api/health</code> included, requires the <code>X-Secret-Key</code> header when you configure an API key. <code>--no-key</code> disables the check entirely. See <a href="../authentication/">Authentication</a>.</li>
|
||||
<li><strong>Content type.</strong> Request bodies are JSON (<code>Content-Type: application/json</code>). All success responses are JSON unless this page documents a <code>204 No Content</code>.</li>
|
||||
<li><strong>CORS.</strong> Every response carries permissive CORS headers, and the server answers <code>OPTIONS</code> preflight requests automatically.</li>
|
||||
<li><strong>Compression.</strong> JSON responses of 256 bytes or more are gzip-compressed when the client sends <code>Accept-Encoding: gzip</code>. A <a href="#slow-responses">slow response</a> is not compressed.</li>
|
||||
@@ -3101,11 +3101,11 @@
|
||||
<h2 id="general-endpoints">General endpoints<a class="headerlink" href="#general-endpoints" title="Permanent link">¶</a></h2>
|
||||
<p>These endpoints report server state and enumerate what is available. <code>GET /api/health</code>, <code>GET /api/services</code>, and <code>POST /api/search</code> are also exposed in <code>--remote-only</code> mode.</p>
|
||||
<h3 id="get-apihealth"><code>GET /api/health</code><a class="headerlink" href="#get-apihealth" title="Permanent link">¶</a></h3>
|
||||
<p>Health check. <strong>This is the only route exempt from authentication</strong>: you can call it without an <code>X-Secret-Key</code> header. It reports the running version and a best-effort update check.</p>
|
||||
<p>Health check. It reports the running version and commit and a best-effort update check, so it needs the <code>X-Secret-Key</code> header like every other route. A request without an API key gets a <code>401</code>, which still shows the server is up.</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="1:2"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Request</label><label for="__tabbed_1_2">Response <code>200</code></label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
<div class="language-bash highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a>curl<span class="w"> </span>http://127.0.0.1:8786/api/health
|
||||
<div class="language-bash highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a>curl<span class="w"> </span>-H<span class="w"> </span><span class="s2">"X-Secret-Key: </span><span class="nv">$SECRET</span><span class="s2">"</span><span class="w"> </span>http://127.0.0.1:8786/api/health
|
||||
</span></code></pre></div>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
@@ -3143,7 +3143,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="get-apiservices"><code>GET /api/services</code><a class="headerlink" href="#get-apiservices" title="Permanent link">¶</a></h3>
|
||||
<p>Show the streaming services available on this server, filtered by your allowlist. Each entry gives the service's tag, matching rules, capability flags, and its CLI parameters (useful when you make a UI that accepts service-specific options). <code>load_errors</code> lists the services the server skipped because they failed to import, at startup or after a service repository refresh; the server also writes each one to its log. An entry marked <code>pending_update</code> has newer code staged: it keeps its current code until its running or queued jobs and its live remote sessions finish.</p>
|
||||
<p>Show the streaming services available on this server, filtered by your allowlist. Each entry gives the service's tag, matching rules, capability flags, and its CLI parameters (useful when you make a UI that accepts service-specific options). For the admin key, <code>load_errors</code> lists the services the server skipped because they failed to import, at startup or after a service repository refresh; the server also writes each one to its log. Any other key gets an empty list; with <code>--no-key</code> every caller is the admin. An entry marked <code>pending_update</code> has newer code staged: it keeps its current code until its running or queued jobs and its live remote sessions finish.</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="2:2"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">Request</label><label for="__tabbed_2_2">Response <code>200</code></label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
|
||||
@@ -2698,8 +2698,7 @@ body that uses an integer <code>status</code> and no <code>error_code</code> or
|
||||
<p class="admonition-title">Handle both shapes</p>
|
||||
<p>A client must expect two error formats: the standard structured error
|
||||
(string <code>status</code> of <code>"error"</code>, with <code>error_code</code>), and this authentication error
|
||||
(integer <code>status</code>, no <code>error_code</code>). The <code>GET /api/health</code> endpoint is exempt
|
||||
from authentication, so it never returns the key-error shape.</p>
|
||||
(integer <code>status</code>, no <code>error_code</code>).</p>
|
||||
</div>
|
||||
<h2 id="late-failures-with-status-200">Late failures with status <code>200</code><a class="headerlink" href="#late-failures-with-status-200" title="Permanent link">¶</a></h2>
|
||||
<p>The remote session <code>titles</code>, <code>tracks</code> and <code>license</code> routes send status <code>200</code> and the headers
|
||||
|
||||
@@ -2260,10 +2260,10 @@ health check is <code>GET http://127.0.0.1:8786/api/health</code>.</p>
|
||||
available at <a href="http://127.0.0.1:8786/api/docs/"><code>/api/docs/</code></a>. The server generates
|
||||
it from the same route table it serves, so it always matches the version you
|
||||
operate. Note that in <code>--api-only</code> mode the docs page is itself behind the
|
||||
API key. Only <code>/api/health</code> is exempt from authentication.</p>
|
||||
API key, like every other route.</p>
|
||||
</div>
|
||||
<p>A quick smoke test that needs no API key:</p>
|
||||
<div class="language-shell highlight"><span class="filename">Confirm the server is up</span><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a>curl<span class="w"> </span>http://127.0.0.1:8786/api/health
|
||||
<p>A quick smoke test:</p>
|
||||
<div class="language-shell highlight"><span class="filename">Confirm the server is up</span><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a>curl<span class="w"> </span>-H<span class="w"> </span><span class="s2">"X-Secret-Key: your-api-secret"</span><span class="w"> </span>http://127.0.0.1:8786/api/health
|
||||
</span></code></pre></div>
|
||||
<div class="language-json highlight"><span class="filename">Response</span><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="p">{</span>
|
||||
</span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a><span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ok"</span><span class="p">,</span>
|
||||
@@ -2292,7 +2292,7 @@ request and response in full.</p>
|
||||
<tr>
|
||||
<td><code>GET</code></td>
|
||||
<td><code>/api/health</code></td>
|
||||
<td>Liveness and version check. Never requires an API key.</td>
|
||||
<td>Liveness and version check.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GET</code></td>
|
||||
@@ -2522,7 +2522,7 @@ history, config, maintenance) is only available in the full or <code>--api-only<
|
||||
</div>
|
||||
<h2 id="authentication-in-one-line">Authentication in one line<a class="headerlink" href="#authentication-in-one-line" title="Permanent link">¶</a></h2>
|
||||
<p>With the default configuration, send your API secret in the <code>X-Secret-Key</code> header on
|
||||
every request except <code>/api/health</code>:</p>
|
||||
every request:</p>
|
||||
<div class="language-shell highlight"><span class="filename">An authenticated request</span><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a>curl<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span>http://127.0.0.1:8786/api/search<span class="w"> </span><span class="se">\</span>
|
||||
</span><span id="__span-5-2"><a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">"X-Secret-Key: your-api-secret"</span><span class="w"> </span><span class="se">\</span>
|
||||
</span><span id="__span-5-3"><a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a><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>
|
||||
|
||||
@@ -2377,7 +2377,7 @@
|
||||
</span></code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Swagger UI is also behind auth</p>
|
||||
<p>In <code>--api-only</code> mode (without <code>--no-key</code>), the Swagger UI at <code>/api/docs/</code> requires the <code>X-Secret-Key</code> header, the same as every other route. Only <code>/api/health</code> is exempt from authentication.</p>
|
||||
<p>In <code>--api-only</code> mode (without <code>--no-key</code>), the Swagger UI at <code>/api/docs/</code> requires the <code>X-Secret-Key</code> header, the same as every other route.</p>
|
||||
</div>
|
||||
<p>For the rest of this page we will assume the server is reachable at <code>http://127.0.0.1:8786</code> and store the secret in an environment variable:</p>
|
||||
<div class="language-shell highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="nb">export</span><span class="w"> </span><span class="nv">SECRET</span><span class="o">=</span><span class="s2">"choose-a-long-random-secret"</span>
|
||||
@@ -2385,8 +2385,8 @@
|
||||
</span></code></pre></div>
|
||||
<hr />
|
||||
<h2 id="step-3-make-sure-that-the-server-is-alive">Step 3: Make sure that the server is alive<a class="headerlink" href="#step-3-make-sure-that-the-server-is-alive" title="Permanent link">¶</a></h2>
|
||||
<p>The health endpoint is the one route that never requires an API key. Use it to make sure that the server operates, and to read its version:</p>
|
||||
<div class="language-shell highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a>curl<span class="w"> </span><span class="s2">"</span><span class="nv">$BASE</span><span class="s2">/api/health"</span>
|
||||
<p>Use the health endpoint to make sure that the server operates, and to read its version. It needs the API key like every other route:</p>
|
||||
<div class="language-shell highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a>curl<span class="w"> </span>-H<span class="w"> </span><span class="s2">"X-Secret-Key: </span><span class="nv">$SECRET</span><span class="s2">"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$BASE</span><span class="s2">/api/health"</span>
|
||||
</span></code></pre></div>
|
||||
<div class="language-json highlight"><span class="filename">200 OK</span><pre><span></span><code><span id="__span-8-1"><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="p">{</span>
|
||||
</span><span id="__span-8-2"><a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a><span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ok"</span><span class="p">,</span>
|
||||
|
||||
Reference in New Issue
Block a user