Fix revocation docs: use POST /v1/validate, not a phantom license-status endpoint
GET /v1/licenses/{id}/status does not exist. Revocation is checked via
POST /v1/validate, which returns ok:false / reason:"revoked".
This commit is contained in:
+22
-14
@@ -198,32 +198,40 @@ result = verifier.<span class="f">verify</span>(license_key_from_user)
|
|||||||
<h2 id="renewals">Renewals & revocation</h2>
|
<h2 id="renewals">Renewals & revocation</h2>
|
||||||
<p>Keysat licenses are signed at issue time and do not phone home. If a license is revoked in the admin UI, the existing key continues to verify in your app. That’s the trade-off for offline.</p>
|
<p>Keysat licenses are signed at issue time and do not phone home. If a license is revoked in the admin UI, the existing key continues to verify in your app. That’s the trade-off for offline.</p>
|
||||||
|
|
||||||
<p>If you need revocation, ship a thin <em>online</em> check that runs on a cadence (e.g. once a week) against your Keysat’s revocation feed:</p>
|
<p>If you need revocation, ship a thin <em>online</em> check that re-validates the key on a cadence (e.g. once a week) against your Keysat’s <code>POST /v1/validate</code>. A revoked license returns <code>ok: false</code> with <code>reason: "revoked"</code>:</p>
|
||||||
|
|
||||||
<pre class="code lang-pane" data-lang="ts"><span class="c">// Optional. Run on a cadence, ignore network errors.</span>
|
<pre class="code lang-pane" data-lang="ts"><span class="c">// Optional. Run on a cadence, ignore network errors.</span>
|
||||||
<span class="k">async function</span> <span class="f">checkRevocation</span>(licenseId: string) {
|
<span class="k">async function</span> <span class="f">checkRevocation</span>(licenseKey: string) {
|
||||||
<span class="k">const</span> r = <span class="k">await</span> fetch(<span class="s">`https://your-keysat.example/v1/licenses/${licenseId}/status`</span>);
|
<span class="k">const</span> r = <span class="k">await</span> fetch(<span class="s">'https://your-keysat.example/v1/validate'</span>, {
|
||||||
|
method: <span class="s">'POST'</span>,
|
||||||
|
headers: { <span class="s">'Content-Type'</span>: <span class="s">'application/json'</span> },
|
||||||
|
body: JSON.<span class="f">stringify</span>({ key: licenseKey }),
|
||||||
|
});
|
||||||
<span class="k">if</span> (r.ok) {
|
<span class="k">if</span> (r.ok) {
|
||||||
<span class="k">const</span> j = <span class="k">await</span> r.json();
|
<span class="k">const</span> j = <span class="k">await</span> r.json();
|
||||||
<span class="k">if</span> (j.status === <span class="s">'revoked'</span>) <span class="f">disableApp</span>();
|
<span class="k">if</span> (!j.ok && j.reason === <span class="s">'revoked'</span>) <span class="f">disableApp</span>();
|
||||||
}
|
}
|
||||||
}</pre>
|
}</pre>
|
||||||
<pre class="code lang-pane" data-lang="rs" style="display:none"><span class="c">// Optional. Run on a cadence, ignore network errors.</span>
|
<pre class="code lang-pane" data-lang="rs" style="display:none"><span class="c">// Optional. Run on a cadence, ignore network errors.</span>
|
||||||
<span class="k">async fn</span> check_revocation(license_id: &<span class="k">str</span>) {
|
<span class="k">async fn</span> check_revocation(license_key: &<span class="k">str</span>) {
|
||||||
<span class="k">if let</span> <span class="k">Ok</span>(r) = reqwest::get(format!(
|
<span class="k">let</span> body = serde_json::json!({ <span class="s">"key"</span>: license_key });
|
||||||
<span class="s">"https://your-keysat.example/v1/licenses/{}/status"</span>,
|
<span class="k">if let</span> <span class="k">Ok</span>(r) = reqwest::<span class="f">Client</span>::new()
|
||||||
license_id
|
.post(<span class="s">"https://your-keysat.example/v1/validate"</span>)
|
||||||
)).<span class="k">await</span> {
|
.json(&body)
|
||||||
<span class="k">if let</span> <span class="k">Ok</span>(j) = r.json::<Status>().<span class="k">await</span> {
|
.send()
|
||||||
<span class="k">if</span> j.status == <span class="s">"revoked"</span> { disable_app(); }
|
.<span class="k">await</span>
|
||||||
|
{
|
||||||
|
<span class="k">if let</span> <span class="k">Ok</span>(j) = r.json::<ValidateResp>().<span class="k">await</span> {
|
||||||
|
<span class="k">if</span> !j.ok && j.reason.as_deref() == <span class="k">Some</span>(<span class="s">"revoked"</span>) { disable_app(); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}</pre>
|
}</pre>
|
||||||
<pre class="code lang-pane" data-lang="py" style="display:none"><span class="c"># Optional. Run on a cadence, ignore network errors.</span>
|
<pre class="code lang-pane" data-lang="py" style="display:none"><span class="c"># Optional. Run on a cadence, ignore network errors.</span>
|
||||||
<span class="k">def</span> <span class="f">check_revocation</span>(license_id):
|
<span class="k">def</span> <span class="f">check_revocation</span>(license_key):
|
||||||
<span class="k">try</span>:
|
<span class="k">try</span>:
|
||||||
r = requests.get(<span class="s">f"https://your-keysat.example/v1/licenses/{license_id}/status"</span>, timeout=<span class="n">5</span>)
|
r = requests.post(<span class="s">"https://your-keysat.example/v1/validate"</span>, json={<span class="s">"key"</span>: license_key}, timeout=<span class="n">5</span>)
|
||||||
<span class="k">if</span> r.json()[<span class="s">"status"</span>] == <span class="s">"revoked"</span>:
|
j = r.json()
|
||||||
|
<span class="k">if</span> <span class="k">not</span> j[<span class="s">"ok"</span>] <span class="k">and</span> j.get(<span class="s">"reason"</span>) == <span class="s">"revoked"</span>:
|
||||||
disable_app()
|
disable_app()
|
||||||
<span class="k">except</span> Exception:
|
<span class="k">except</span> Exception:
|
||||||
<span class="k">pass</span></pre>
|
<span class="k">pass</span></pre>
|
||||||
|
|||||||
Reference in New Issue
Block a user