Erste Schritte
Erste Schritte
Der durchgängige Anbieterpfad für Keyright Cloud und Self-Hosting — Issuing-Service bereitstellen, Produkt und Signaturschlüssel anlegen, SDK in die App einbauen, Lizenz ausstellen, in der App prüfen und live gehen.
Dies ist der durchgängige Pfad für einen Anbieter, der Lizenzierung zu einer App hinzufügt: Issuing-Service bereitstellen, Produkt und Signaturschlüssel anlegen, SDK in Ihr Produkt einbetten, Lizenz ausstellen, sie in der App prüfen und live gehen. Er läuft unabhängig von der Sprache, in der Sie ausliefern, gleich ab — Schritt 3 verlinkt auf das SDK für Ihre Sprache (oder auf den Pfad über reines HTTP).
Keyright gibt es in zwei Bereitstellungsmodi, und jeder Schritt unten zeigt beide. Durchgängig steht $BASE für die URL Ihres Issuing-Service und $TOKEN für Ihr Admin-Zugangsdatum, gesendet im Header X-Admin-Token.
Wählen Sie Ihren Pfad
Keyright Cloud — wir hosten den Issuing-Service; Sie registrieren sich und beginnen, Schlüssel auszustellen. Selbst gehostet — Sie stellen den Service in Ihrer eigenen Infrastruktur bereit. Der Teil, den Sie bauen, ist in beiden Fällen derselbe: Der SDK-Code, das signierte Lizenzformat und der öffentliche Schlüssel, den Sie ausliefern, sind identisch. Nur die Service-URL, auf die Ihre App zeigt, und das Admin-Zugangsdatum, mit dem Sie verwalten, unterscheiden sich.
1. Issuing-Service bereitstellen
Cloud: Legen Sie unter keyright.delta1labs.com einen Arbeitsbereich an und melden Sie sich an. Ihr Arbeitsbereich wird automatisch mit einem Signaturschlüssel ausgestattet, Sie können also direkt zu Schritt 2 übergehen. Setzen Sie $BASE=https://keyright.delta1labs.com; Ihr $TOKEN ist ein Team-Sitzungstoken — es wird bei der Anmeldung ausgestellt, und Sie können unter Settings → Team Teammitglieder einladen (mit eigenen Tokens).
Selbst gehostet: Ziehen Sie das öffentliche Container-Image, zeigen Sie auf eine leere PostgreSQL-Datenbank, geben Sie ihm die benötigten Geheimnisse (ein Admin-Token, ein Schlüsselverschlüsselungs-Secret) sowie Ihren Keyright-Lizenzschlüssel und starten Sie es — beim ersten Start legt es sein eigenes Schema an und antwortet unter /health, sobald es bereit ist. Setzen Sie $BASE auf die URL Ihrer Instanz (lokal ist das http://localhost:8080) und $TOKEN auf das von Ihnen erzeugte KEYRIGHT_ADMIN_TOKEN. Der vollständige Rundgang ist der Bereitstellungsleitfaden, und Ihre Instanz benötigt einen gültigen Schlüssel, um zu laufen — siehe Lizenzierung & Editionen.
Alles ab hier ist für beide Modi gleich; nur $BASE und $TOKEN ändern sich.
Nach der Anmeldung landen Sie auf der Dashboard-Startseite Home, die Ihren Fortschritt durch genau die folgenden Schritte verfolgt:
2. Produkt (und eine Edition) anlegen, dann Signaturschlüssel holen
Legen Sie zuerst das Produkt an — Sie können weder einen Signaturschlüssel erzeugen noch eine Lizenz für ein Produkt ausstellen, das noch nicht existiert. Über das Dashboard (Products → New product, dann Editions → Add edition — das Dashboard nennt Tiers Editionen; die API sagt weiterhin tiers) oder über die API:
# das Produkt anlegen
curl -X POST $BASE/admin/products -H "X-Admin-Token: $TOKEN" -H "content-type: application/json" \
-d '{"name":"Acme App","slug":"acme-app"}'
# ein Tier / eine Edition hinzufügen (Platzanzahl + eine Entitlement-Vorlage, die Ihre App zur Laufzeit liest)
curl -X POST $BASE/admin/products/acme-app/tiers -H "X-Admin-Token: $TOKEN" -H "content-type: application/json" \
-d '{"name":"pro","seats":3,"entitlements":{"export":"true","max-projects":"10"}}'
Entitlement-Werte sind auf dem Draht Strings ("true"/"false" für Flags, eine Ganzzahl oder "unlimited" für Limits). Kontingente (aktive Lizenzen, Produktanzahl) folgen in der Cloud dem Plan des Mandanten; selbst gehostete bezahlte Editionen sind unbegrenzt. Wenn Sie Updates verkaufen (ein Jahr Updates, eine Hauptversion, ein Abonnement …), geben Sie der Edition vor dem Ausstellen eine Abdeckungsrichtlinie — siehe Release-Abdeckung.
Der Tab Overview des Produkts fasst all das zusammen — die Editionen mit ihren Platzanzahlen und Entitlements, die Testversion und den Signaturschlüssel, den Sie als Nächstes einbetten:
Signaturschlüssel holen. Lizenzen und Leases werden mit einem RSA-Schlüssel signiert, dessen private Hälfte serverseitig bleibt; Ihre App bettet nur den öffentlichen Schlüssel ein. Ein Schlüssel ist entweder produktspezifisch oder mandantenweit (von all Ihren Produkten geteilt).
- Produktspezifisch (empfohlen):
curl -X POST $BASE/admin/products/acme-app/signing-key -H "X-Admin-Token: $TOKEN"— die Antwort enthält densigningPublicKeydes Produkts. Im Dashboard finden Sie ihn auf dem Tab Signing key des Produkts. - Mandantenweit: Lesen Sie ihn unter Developers → Keys ab oder über
GET $BASE/admin/public-key(auchGET $BASE/admin/account→integration.signingPublicKey).
GET /admin/public-keyundGET /admin/accountliefern den Mandanten-Schlüssel, dernullist, bis ein Mandantenschlüssel existiert. Erzeugen Sie auf einer frischen selbst gehosteten Instanz ohne gesetzten Mandantenschlüssel einen produktspezifischen Schlüssel (siehe oben), statt einen Null-Wert einzubetten. Ein Cloud-Arbeitsbereich hat bereits einen Mandantenschlüssel.
Kopieren Sie den base64-kodierten öffentlichen Schlüssel desjenigen Schlüssels, der die Lizenzen dieses Produkts signiert — Sie fügen ihn in Schritt 3 in das SDK ein. Das Dashboard öffnet sich in einer ruhigen Ansicht Basis, die genau diese Schritte abdeckt; wechseln Sie zur Ansicht Mittel oder Erweitert, wenn Sie alles Weitere benötigen.
3. SDK in Ihr Produkt einbauen
Das ist das Herzstück der Integration: SDK einbetten, mit Ihrem Produkt-Slug und öffentlichen Schlüssel initialisieren und eine Funktion absichern. Der Code ist in der Cloud und beim Self-Hosting identisch — das Einzige, was sich zwischen den Modi ändert, ist ServiceUrl (Ihr $BASE) und, serverseitig, welches Admin-Token den Schlüssel ausgestellt hat. Das Lizenzformat und der eingebettete öffentliche Schlüssel ändern sich nicht.
Das Dashboard schreibt die erste Version dieses Codes für Sie: Developers → Quickstart wählt Ihr Produkt und Ihre Sprache und füllt das Snippet mit dem Produkt-Slug, seinem öffentlichen Schlüssel und der URL dieser Instanz vor — kopieren Sie es direkt hinein.
Hier ist diese minimale Integration — installieren, mit Produkt-Slug + öffentlichem Schlüssel + Service-URL initialisieren, online aktivieren, dann eine Funktion absichern — in jeder unterstützten Sprache. Setzen Sie die Service-URL auf Ihr $BASE (in der Cloud die gehostete URL, beim Self-Hosting die URL Ihrer Instanz); alles andere — die SDK-Aufrufe, das signierte Lizenz-/Lease-Format, der eingebettete öffentliche Schlüssel — ist in der Cloud und beim Self-Hosting identisch.
.NET — Keyright.NET auf NuGet (Multi-Targeting für netstandard2.0 und net8.0, läuft also auf .NET Framework 4.8 und .NET 6–10):
dotnet add package Keyright.NET
using Keyright.Client;
static readonly KeyrightClient License = KeyrightClient.Initialize(new KeyrightOptions
{
Product = "acme-app", // der Produkt-Slug aus Schritt 2
PublicKeyBase64 = "MIIBIjANBgkq...", // der öffentliche Schlüssel aus Schritt 2 — kein Geheimnis; er prüft nur
ServiceUrl = "https://keyright.delta1labs.com", // Cloud: die gehostete URL. Self-Hosting: URL Ihrer Instanz. Weglassen für nur offline.
});
// Wenn der Kunde einen Schlüssel eingibt, online aktivieren: bindet diese Maschine, belegt einen Platz, speichert einen signierten Lease zwischen.
LicenseInfo info = await License.ActivateAsync(customerEnteredKey, ct);
// Jeder spätere Start prüft offline gegen den zwischengespeicherten Lease — kein Netzwerk-Roundtrip.
LicenseInfo offline = License.Validate();
// Eine bezahlte Funktion über ein Entitlement (nicht über die Edition) absichern, damit Tier-Änderungen keinen neuen Code brauchen.
if (info.IsPaid && License.IsEnabled("export"))
ShowExportCommand();
Node.js — keyright auf npm (CommonJS, keine Abhängigkeiten):
npm install keyright
const { KeyrightClient } = require('keyright');
const license = KeyrightClient.initialize({
product: 'acme-app', // der Produkt-Slug aus Schritt 2
publicKeyBase64: 'MIIBIjANBgkq...', // der öffentliche Schlüssel aus Schritt 2 — kein Geheimnis
serviceUrl: 'https://keyright.delta1labs.com', // Cloud: die gehostete URL. Self-Hosting: URL Ihrer Instanz.
});
// Wenn der Kunde einen Schlüssel eingibt, online aktivieren (bindet die Maschine, belegt einen Platz, speichert einen signierten Lease zwischen).
const info = await license.activate(customerEnteredKey);
// Spätere Starts prüfen offline gegen den zwischengespeicherten Lease — synchron, wirft nie.
const { info: offline } = license.validate();
// Eine bezahlte Funktion über ein Entitlement absichern.
if (info.isPaid && info.entitlements.isEnabled('export')) {
showExportCommand();
}
Python — keyright auf PyPI (Python 3.8+):
pip install "keyright>=1.1.4"
from keyright import KeyrightClient, KeyrightOptions
license = KeyrightClient.initialize(KeyrightOptions(
product="acme-app", # der Produkt-Slug aus Schritt 2
public_key_base64="MIIBIjANBgkq...", # der öffentliche Schlüssel aus Schritt 2 — kein Geheimnis
service_url="https://keyright.delta1labs.com", # Cloud: die gehostete URL. Self-Hosting: URL Ihrer Instanz.
))
# Wenn der Kunde einen Schlüssel eingibt, online aktivieren (synchron).
info = license.activate(customer_entered_key)
# Spätere Starts prüfen offline gegen den zwischengespeicherten Lease; validate() liefert (info, source).
offline, source = license.validate()
# Eine bezahlte Funktion über ein Entitlement absichern.
if info.is_paid and info.entitlements.is_enabled("export"):
show_export_command()
Java — com.delta1labs:keyright auf Maven Central (Java 17+, keine Laufzeitabhängigkeiten):
<dependency>
<groupId>com.delta1labs</groupId>
<artifactId>keyright</artifactId>
<version>1.1.4</version>
</dependency>
import com.delta1labs.keyright.KeyrightClient;
import com.delta1labs.keyright.KeyrightOptions;
import com.delta1labs.keyright.LicenseInfo;
KeyrightClient client = KeyrightClient.initialize(
new KeyrightOptions()
.product("acme-app") // der Produkt-Slug aus Schritt 2
.publicKeyBase64("MIIBIjANBgkq...") // der öffentliche Schlüssel aus Schritt 2 — kein Geheimnis
.serviceUrl("https://keyright.delta1labs.com")); // Cloud: die gehostete URL. Self-Hosting: URL Ihrer Instanz.
// Wenn der Kunde einen Schlüssel eingibt, online aktivieren (synchron).
LicenseInfo info = client.activate(customerEnteredKey);
// Spätere Starts prüfen offline gegen den zwischengespeicherten Lease.
LicenseInfo offline = client.validateInfo();
// Eine bezahlte Funktion über ein Entitlement absichern.
if (info.isPaid() && info.entitlements.isEnabled("export")) {
showExportCommand();
}
Jede Sprache (reines HTTP, kein SDK) — die Runtime-API ist schlichtes JSON über HTTP, sodass Go, Rust, C++, PHP, Ruby … direkt mit ihr sprechen. Aktivieren Sie eine Maschine und prüfen Sie den signierten Lease dann selbst:
curl -s -X POST "$BASE/v1/activate" -H "content-type: application/json" \
-d '{"key":"LIC-9F3A...","machineId":"<your stable per-machine id>","product":"acme-app"}'
# -> { "status":"ok", "seats":3, "used":1, "lease":"{...signed lease JSON...}" }
Speichern Sie den lease-String unverändert und prüfen Sie seine RSA-Signatur gegen Ihren eingebetteten öffentlichen Schlüssel — bauen Sie die kanonische krlease1|…-Nutzlast nach und prüfen Sie sie mit PKCS#1 v1.5 / SHA-256 —, bevor Sie ihm vertrauen. Sobald die Prüfung gelingt, lesen Sie tier für die Edition und entitlements für die Gates pro Funktion und validieren Sie regelmäßig erneut (POST /v1/validate), um Widerrufe mitzubekommen. Verhalten Sie sich bei jedem Status ungleich ok oder einem Lease, der sich nicht verifizieren lässt, fail-closed. Das vollständige Rezept auf Byte-Ebene (mit einem portierbaren Go-Beispiel) ist Die HTTP-API direkt nutzen.
Jedes SDK prüft die Signatur gegen Ihren eingebetteten öffentlichen Schlüssel, kontrolliert Maschinenbindung und Ablauf, speichert den Lease lokal zwischen und reaktiviert automatisch, bevor er abläuft. Alle verhalten sich fail-closed und fallen in den kostenlosen/unlizenzierten Zustand zurück, wenn die Prüfung fehlschlägt oder der Schlüssel widerrufen ist — und weil die fünf Clients dasselbe signierte Format prüfen, teilt sich eine mehrsprachige Produktlinie einen Mandanten und einen öffentlichen Schlüssel.
Für den vollständigen Rundgang pro Sprache — Deaktivierung, Offline-/Air-Gapped-Leases, Testversionen, Node-Locking, Schlüsselrotation und Release-Abdeckung — folgen Sie dem vollständigen Leitfaden für Ihre Sprache:
| Sprache | Paket | Leitfaden |
|---|---|---|
| .NET | Keyright.NET (NuGet) | .NET-SDK-Integration |
| Node.js | keyright (npm) | Node.js-SDK-Integration |
| Python | keyright (PyPI) | Python-SDK-Integration |
| Java | com.delta1labs:keyright (Maven) | Java-SDK-Integration |
| Alles andere (Go, Rust, C++, PHP …) | — | Die HTTP-API direkt nutzen |
Was unterscheidet Cloud und Self-Hosting? Nur die Basis-URL und das Admin-Token. Setzen Sie ServiceUrl in der Cloud auf die gehostete URL oder beim Self-Hosting auf die URL Ihrer Instanz; alles andere — die SDK-Aufrufe, das Lizenz- und Lease-Format, das Einbetten des öffentlichen Schlüssels — ist gleich. Siehe Feature-Gating für Entitlements und Limits im Detail.
4. Lizenz ausstellen und in der App prüfen
Stellen Sie eine bezahlte Lizenz über Licenses → Issue license im Dashboard oder über die API aus (id weglassen, um den Schlüssel automatisch zu erzeugen; angeben, um einen vorhandenen zu importieren):
curl -X POST $BASE/admin/licenses -H "X-Admin-Token: $TOKEN" -H "content-type: application/json" \
-d '{"licensee":"Acme Inc.","product":"acme-app","tier":"pro","seats":3,"email":"owner@acme.com"}'
# -> HTTP 201
# { "id":"LIC-XXXX...", "licensee":"Acme Inc.", "product":"acme-app", "tier":"pro",
# "seats":3, "used":0, "expiryUtc":null, "revoked":false, "trial":false, "createdAt":"..." }
# Die "id" ist der Schlüssel, den Sie dem Kunden geben.
Der Kunde fügt diesen Schlüssel in Ihre App ein, die ActivateAsync (online) aufruft — das bindet die Maschine, belegt einen Platz und speichert einen signierten Lease zwischen, sodass spätere Validate()-Aufrufe offline gelingen. Die Maschinenbindung erfolgt automatisch: Activate nimmt nur den Schlüssel entgegen; das SDK leitet eine stabile Maschinen-ID vom Host ab, sodass ein Einzelplatzschlüssel nicht auf zwei Maschinen laufen kann (der rohe Body von POST /v1/activate trägt { key, machineId, product } — das SDK füllt machineId für Sie aus). Was Sie aus LicenseInfo zurücklesen:
IsPaid/IsTrial— ob es eine bezahlte Lizenz oder eine Testlizenz ist (beide werden über denselben Pfad aktiviert).IsEnabled("flag")/GetLimit("name", fallback)— Entitlement-Prüfungen, die sich fail-closed verhalten.DaysRemaining/ExpiryUtc— für ein Badge „noch 27 Tage“;StatusBadgefür eine Beschriftung wie „Pro Trial“.
Sobald eine Maschine aktiviert, erscheint sie auf dem Tab Devices dieser Lizenz und belegt einen Platz — Sie sehen, welche Geräte gebunden sind, können einen Platz freigeben und die Entitlements ablesen, die die Lizenz trägt:
Die vollständigen Aktivierungs- und Offline-Pfade stehen in Aktivierung & Plätze und Offline & Air-Gapped.
Einen Testschlüssel erhalten. Wenn Sie für das Produkt eine Self-Service-Testversion aktiviert haben (Products → Trials), holt sich Ihre App einen Testschlüssel durch einen direkten Aufruf des öffentlichen Trial-Endpunkts — für das Ausstellen einer Testversion gibt es keinen SDK-Wrapper:
curl -X POST $BASE/v1/trial -H "content-type: application/json" \
-d '{"product":"acme-app","email":"user@customer.com","company":"Customer Ltd"}'
# -> { "ok":true, "product":"acme-app", "trial":true, "emailed":true, "expiresUtc":"...", "days":14, "created":true }
Der Endpunkt sendet den Testschlüssel per E-Mail an die Adresse (die Antwort enthält keinen Schlüssel — auf der Instanz muss SMTP konfiguriert sein); der Kunde gibt diesen Schlüssel dann ein und übergibt ihn wie jeden anderen Schlüssel an ActivateAsync(). Er wird genau wie ein bezahlter Schlüssel aktiviert und validiert; info.IsTrial ist true und DaysRemaining zählt herunter. Vollständiger Ablauf: Self-Service-Testversionen.
5. Live gehen
Beide Modi
- Der im ausgelieferten Build eingebettete öffentliche Schlüssel stimmt mit dem Schlüssel überein, der die Lizenzen dieses Produkts signiert.
- Der
Product-Slug im SDK stimmt mit dem Produkt überein, für das Sie Lizenzen ausstellen (der Server begrenzt die Aktivierung auf das Produkt). - Entscheiden Sie zwischen offline und online (oder beidem): eine Offline-Datei für netzwerkisolierte (air-gapped) Umgebungen/Enterprise, Online-Aktivierung für Platzdurchsetzung und Widerruf — siehe Offline & Air-Gapped.
- Plätze und Ablauf sind auf Edition/Lizenz korrekt gesetzt; testen Sie das Erreichen des Platzlimits.
- Testen Sie den Widerrufspfad (
POST /admin/licenses/{id}/revoke) — die App sollte bei der nächsten Lease-Aktualisierung auf Free zurückfallen. Siehe Widerruf, Verlängerung & Ablauf. - Wenn Sie Release-Abdeckung durchsetzen, ergänzen Sie jede vor der Abdeckung ausgestellte Lizenz nachträglich (Backfill, Releases & coverage → Enforcement readiness), bevor Sie einen
KeyrightRequireCoverage-Build ausliefern, und setzen SieKeyrightCoverageVersion/KeyrightCoverageEntitlementDateaus Ihrer Release-Pipeline — Release-Abdeckung.
Nur Cloud
- Wenn Sie über einen Shop/Merchant of Record verkaufen, verbinden Sie das Fulfillment mit
POST /webhooks/fulfill/{slug}, damit bezahlte Bestellungen automatisch Schlüssel ausstellen — Shop-Fulfillment. - Vergewissern Sie sich, dass Ihr Plan die erwartete Anzahl aktiver Lizenzen und Produkte abdeckt (Upgrade unter Settings → Plan & billing).
Nur Self-Hosting
- Haben Sie einen Backup-Plan für die Datenbank und Ihr Schlüsselverschlüsselungs-Secret — der Verlust dieses Secrets bedeutet den Verlust jedes Signaturschlüssels. Sichern Sie auch Ihre eigene Instanzlizenz.
- Haben Sie einen Plan für die Rotation des Signaturschlüssels.
- Halten Sie eine gültige Instanzlizenz installiert — eine selbst gehostete Instanz ist fail-closed und stellt Runtime-Aufrufe ein, sobald ihre eigene Lizenz über die Kulanzfrist hinaus abgelaufen ist (Lizenzierung & Editionen).
Die API auf einen Blick
| Bereich | Endpunkt | Auth | Zweck |
|---|---|---|---|
| Runtime | POST /v1/activate | keine | Aktiviert einen Schlüssel auf einer Maschine → signierter Lease. Body: { key, machineId, product } |
| Runtime | POST /v1/validate | keine | Validiert/aktualisiert, ohne einen Platz zu belegen. Body: { key, machineId, product } |
| Admin | GET/POST /admin/products, /admin/products/{slug}/tiers | Admin-Token | Produkte & Tiers verwalten |
| Admin | POST /admin/products/{slug}/signing-key | Admin-Token | Signaturschlüssel eines Produkts erzeugen/rotieren → signingPublicKey |
| Admin | POST /admin/licenses, /admin/licenses/{id}/{revoke,renew,transfer,deactivate,offline-lease} | Admin-Token | Lizenzen ausstellen & verwalten |
| Admin | GET /admin/licenses, /admin/overview, /admin/licenses/{id}/activations | Admin-Token | Berichte |
| Admin | GET /admin/self-license | Admin-Token | Nur Self-Hosting: Lizenzstatus dieser Instanz (Edition, Phase, verbleibende Tage) |
| Admin | GET/POST /admin/team | Owner-Token | Teammitglieder |
| Runtime | POST /v1/coverage | keine (Lizenzschlüssel) | Ist Version X für diese Lizenz abgedeckt? — der Baustein für Ihr eigenes Download-Gate |
| Admin | POST /admin/products/{slug}/releases, /admin/licenses/{id}/coverage/{preset,grants}, /admin/products/{slug}/coverage/{readiness,backfill,export,migrate} | Admin-Token | Release-Abdeckung: Register, Bedingungen, Backfill, Air-Gap-Export |
| Platform | GET/POST /platform/tenants, /platform/plans, /platform/tenants/{id}/signing-key | Plattform-Token | Mandantenfähiger Betreiber |
| Auth | POST /auth/login → /auth/mfa, /auth/session, /auth/sso | — | Dashboard-Anmeldung → Sitzungstoken |
Die Runtime-Bodys verwenden machineId (einen stabilen Fingerabdruck pro Maschine) und product (den Produkt-Slug) neben dem Lizenz-key — unbekannte Feldnamen werden wie ein unbekannter Schlüssel behandelt. Vollständige Request-/Response-Details pro Sprache stehen in den Leitfäden zum SDK und zur HTTP-API; die Abdeckungs-Endpunkte sind unter Release-Abdeckung dokumentiert.
Die vollständige Endpunktübersicht finden Sie in der HTTP-API-Referenz.