Zum Inhalt springen

Authentifizierung und API-Schlüssel

Die DUST API authentifiziert jede Anfrage an /api/v1/* mit einem von AuthD, dem DUST-Kontodienst, ausgestellten Bearer-JWT. API-Integrationen agieren als Dienstkonto — eine Ihrer Organisation gehörende Maschinenidentität — und niemals als Person. Der Ablauf ist:

  1. Ein Organisationsadministrator erstellt ein Dienstkonto und stellt einmalig Anmeldedaten dafür aus.
  2. Ihre Integration tauscht die Anmeldedaten gegen ein kurzlebiges Bearer-Token aus.
  3. Senden Sie bei API-Aufrufen Authorization: Bearer <token> und führen Sie einen erneuten Austausch durch, wenn das Token abläuft.

Ein Dienstkonto ist eine eigenständige Maschinenidentität: Es gehört genau einer Organisation, kann wie ein Mitglied Zugriff auf Teams erhalten und jede von ihm ausgeführte Aktion wird im Audit-Protokoll dem Dienstkonto zugeordnet — nicht dem Mitarbeiter, der es eingerichtet hat. Seine Anmeldedaten können jederzeit rotiert oder widerrufen werden, ohne dass persönliche Konten davon betroffen sind.

Es stehen zwei Arten von Anmeldedaten zur Verfügung, und ein Dienstkonto kann beide besitzen:

  • API-Schlüssel — die einfachste Integration: Tauschen Sie den Schlüssel mit einem einzigen HTTP-Aufruf gegen ein Token aus.
  • OAuth2-Client (client_credentials) — für Enterprise-Middleware (SAP Integration Suite, MuleSoft, Boomi, …) mit integrierter OAuth2-Unterstützung.

Dienstkonten und ihre Anmeldedaten werden von Organisationsadministratoren im AuthD-Portal unter authd.dustid.io verwaltet.

  1. Melden Sie sich unter authd.dustid.io als Organisationsadministrator an.
  2. Öffnen Sie die Seite Ihrer Organisation und wählen Sie die Registerkarte Dienstkonten aus.
  3. Erstellen Sie ein Dienstkonto (beispielsweise „SAP Connector“ oder „Scannerstation der Linie 3“).
  4. Öffnen Sie für das Dienstkonto Verwalten und erstellen Sie einen API-Schlüssel.
  5. Speichern Sie den Schlüssel in einem Secrets Manager — behandeln Sie ihn wie ein Passwort. Er wird nur einmal angezeigt.

Lesen Sie dies vor dem ersten Beispiel: Der Speicherort der Anmeldedaten ist die eine Entscheidung, von der die Sicherheit einer DUST-Integration abhängt.

  • Anmeldedaten befinden sich ausschließlich auf Ihren Servern — in Umgebungsvariablen oder einem Secrets Manager, niemals in Client-Bundles und niemals in der Versionsverwaltung.
  • Bearer-Token sind ebenfalls Anmeldedaten. Sie sind zwar kurzlebig, doch ein aus Ihren Anmeldedaten ausgestelltes Token verfügt über den vollständigen Zugriff des Dienstkontos — auf jede Organisation, jedes Team und jeden Vorgang, die für dieses Konto erreichbar sind. Eine kurze Lebensdauer begrenzt das Zeitfenster, nicht das Ausmaß eines möglichen Schadens.
  • Wenn Ihre Web- oder mobile App DUST-Daten benötigt, lautet das unterstützte Muster: Browser → Ihr Backend → DUST API. Ihr Backend verwahrt die Anmeldedaten, stellt das Bearer-Token aus, entscheidet, welcher Kontext und welcher Vorgang für den Aufrufer zulässig sind, und ruft die DUST API selbst auf. Der Browser erhält keinerlei DUST-Anmeldedaten. Scanner- und mobile Integrationen folgen genau diesem Muster: Die Aufnahme wird an Ihr Backend gesendet, das die Endpunkte für Kennungen mit serverseitig verwahrten Anmeldedaten aufruft.
  • Ein Dienstkonto pro Anwendung und Umgebung ermöglicht eine gezielte Rotation, einen gezielten Widerruf und eine gezielte Prüfung.

GET /api/auth/token nimmt den API-Schlüssel im Header x-api-key entgegen und gibt ein JWT zurück. (APID leitet dies an AuthD weiter, sodass eine einzige Basis-URL für alles ausreicht.)

Dieser Aufruf und jeder auf seinem Ergebnis aufbauende Aufruf werden auf einem Server ausgeführt.

Terminal-Fenster
curl -fsS "https://apid.dustid.io/api/auth/token" \
-H "x-api-key: $DUST_API_KEY"

Antwort:

{ "token": "eyJhbGciOi...", "expiresIn": 900, "expiresAt": "2026-07-14T22:40:00.000Z" }

expiresIn ist die verbleibende Lebensdauer des Tokens in Sekunden; expiresAt gibt denselben Zeitpunkt als ISO-8601-Zeitstempel an. Beide Werte werden aus dem Ablauf-Claim des Tokens abgeleitet. Ein ohne solchen Claim ausgestelltes Token wird daher lediglich als { "token": "…" } zurückgegeben — lesen Sie diese Werte defensiv aus und verwenden Sie ersatzweise Ihren eigenen konservativen Sicherheitsspielraum. Verwenden Sie einen der beiden Werte, um den nächsten Austausch zu planen; codieren Sie keine feste Lebensdauer ein.

Erstellen Sie für Plattformen mit nativer OAuth2-Unterstützung einen OAuth-Client für das Dienstkonto anstelle eines API-Schlüssels oder zusätzlich dazu. Client-ID und Client-Secret werden bei der Erstellung einmalig angezeigt.

Fordern Sie mit dem standardmäßigen Grant client_credentials ein Token vom Token-Endpunkt des Dienstkontos an — sowohl client_secret_post (Formularfelder) als auch client_secret_basic (HTTP Basic) werden akzeptiert:

Terminal-Fenster
curl -fsS "https://authd.dustid.io/api/auth/dust/service-accounts/token" \
-d grant_type=client_credentials \
-d client_id="$DUST_CLIENT_ID" \
-d client_secret="$DUST_CLIENT_SECRET"

Antwort (standardmäßige OAuth2-Token-Antwort):

{ "access_token": "eyJhbGciOi...", "token_type": "Bearer", "expires_in": 900 }

Das resultierende Token hat dieselbe Struktur und dieselben Rechte wie ein Token aus dem API-Schlüsselaustausch — verwenden Sie es auf dieselbe Weise. Wenn Ihre Middleware nach einer „Token-URL“ fragt, verwenden Sie den oben angegebenen Endpunkt.

Senden Sie das Token bei jedem Aufruf der Kern-API:

Authorization: Bearer <token>

So können Sie schnell überprüfen, ob das Token funktioniert:

Terminal-Fenster
curl -fsS "https://apid.dustid.io/api/v1/me" \
-H "Authorization: Bearer $DUST_TOKEN"

Anfragen ohne gültiges Token erhalten 401 mit dem Antwortkörper { "code": "UNAUTHORIZED", "message": "...", "status": 401 } — den Fehlervertrag finden Sie unter Anfragekonventionen, die vollständige Codeliste unter Fehler und Scanergebnisse.

Bearer-Token von Dienstkonten sind kurzlebig — derzeit 15 Minuten. Lesen Sie die Lebensdauer jedoch immer aus der Antwort (expiresIn/expiresAt beim Schlüsselaustausch, expires_in beim OAuth-Grant), anstatt sie fest einzucodieren. Es gibt kein Refresh-Token: Wenn ein Token abläuft, tauschen Sie die Anmeldedaten erneut aus.

Ein robuster Client kombiniert beide Muster — Erneuerung im Voraus mit einem Sicherheitsspielraum sowie die Behandlung eines einzelnen 401 als Signal, das Token zu erneuern und den Aufruf zu wiederholen. Dadurch werden auch Zeitabweichungen und ein Widerruf während der Laufzeit abgedeckt:

let cached: { token: string; refreshAfter: number } | null = null;
async function getToken(): Promise<string> {
if (cached && Date.now() < cached.refreshAfter) return cached.token;
const res = await fetch("https://apid.dustid.io/api/auth/token", {
headers: { "x-api-key": process.env.DUST_API_KEY! },
});
if (!res.ok) throw new Error(`token exchange failed: ${res.status}`);
const { token, expiresIn } = await res.json();
// refresh 60s before expiry, never cache a token for less than 5s
cached = { token, refreshAfter: Date.now() + Math.max(expiresIn - 60, 5) * 1000 };
return token;
}
async function apiFetch(url: string, init: RequestInit = {}): Promise<Response> {
const call = async () => {
// new Headers() handles every HeadersInit shape (plain object, Headers,
// tuple array) — an object spread would silently drop the latter two.
const headers = new Headers(init.headers);
headers.set("Authorization", `Bearer ${await getToken()}`);
return fetch(url, { ...init, headers });
};
let res = await call();
if (res.status === 401) {
cached = null; // token revoked or expired early — refresh once and retry
res = await call();
}
return res;
}

Der Austausch ist kostengünstig; bauen Sie darum keine langlebigen Caches auf. Die kurze Lebensdauer unterstützt Sie auch bei der Reaktion auf Sicherheitsvorfälle: Durch den Widerruf von Anmeldedaten wird die Ausstellung neuer Tokens sofort unterbunden, und bereits ausgestellte Tokens verlieren innerhalb weniger Minuten ihre Gültigkeit.

Ein Dienstkonto authentifiziert das System; es kann DUST nicht mitteilen, welche Person die Schaltfläche in Ihrem ERP-System oder in Ihrer Produktionsstätte betätigt hat. Wenn Sie diese Rückverfolgbarkeit wünschen, deklarieren Sie die Person pro Anfrage mit dem Header Dust-Ctx-Declared-Actor — einem kleinen JSON-Objekt:

Dust-Ctx-Declared-Actor: {"id": "JDOE", "system": "SAP", "displayName": "Jane Doe"}
  • id ist erforderlich; system, displayName und role sind optional. Der Wert darf URI-codiert sein (dies ist erforderlich, wenn er Nicht-ASCII-Zeichen enthält) und muss kleiner als 1 KB bleiben.
  • Der deklarierte Akteur wird bei jedem von der Anfrage geschriebenen Ereignis unverändert erfasst und im Aktivitätsverlauf als deklarierte Zuordnung angezeigt — die Angabe stammt von Ihrer Integration, wird nicht von DUST verifiziert und gewährt oder beschränkt niemals Berechtigungen.
  • Ein Organisationsadministrator kann die Zuordnungsrichtlinie eines Dienstkontos auf erforderlich setzen. In diesem Fall werden Schreibanfragen ohne deklarierten Akteur mit 403 ATTRIBUTION_REQUIRED abgelehnt.

Die API verifiziert die Signatur jedes Bearer-Tokens anhand des JSON Web Key Set von AuthD und prüft den Aussteller (https://authd.dustid.io/api/auth in der Produktionsumgebung) sowie die Audience-Claims. Normalerweise benötigen Sie diese Details nie — wenn Ihr eigenes Backend jedoch von DUST ausgestellte JWTs verifizieren soll, beispielsweise um einem von einem anderen internen Dienst weitergeleiteten Token zu vertrauen, ist das JWKS öffentlich zugänglich:

GET https://apid.dustid.io/api/auth/jwks

Es gibt ein standardmäßiges Dokument im Format { "keys": [ ... ] } zurück, das mit jeder JOSE-Bibliothek verwendet werden kann.

Das nachfolgende Muster zeigt, wie jede Browser- oder mobile Scanintegration aufgebaut sein sollte. Zwei Dateien, zwei Ausführungsorte, ein Satz Anmeldedaten — und diese verlassen niemals die zweite Datei.

scanner.tsx — runs in the BROWSER
// No DUST credential appears in this file, and none should.
async function identify(capture: Blob) {
const form = new FormData();
form.set("capture", capture);
// Your own endpoint, authenticated with your own session.
const response = await fetch("/api/identify", { method: "POST", body: form, credentials: "same-origin" });
return await response.json();
}
server/identify.ts — runs on YOUR SERVER
// Holds the DUST credential, mints the bearer token, chooses the context,
// and applies your own authorization before calling DUST.
export async function handleIdentify(request: Request, session: YourSession) {
if (!session.mayScan) return new Response("Forbidden", { status: 403 });
const capture = (await request.formData()).get("capture") as Blob;
const form = new FormData();
form.set("tagType", "DUST");
form.set("data", capture);
form.set("searchTeamIds", JSON.stringify(session.allowedTeamIds));
return await fetch("https://apid.dustid.io/api/v1/tags/identify", {
method: "POST",
headers: {
Authorization: `Bearer ${await getToken()}`, // server-held credential
"Dust-Ctx-Org-Id": session.organizationId, // your choice, not the caller's
},
body: form,
});
}

Ihr Proxy ist zugleich der natürliche Ort für benutzerspezifische Regeln, von denen die DUST API nichts wissen kann: welche Teams dieser Mitarbeiter durchsuchen darf, ob er Objekte sowohl verknüpfen als auch identifizieren darf und welche Daten Sie protokollieren.

Für ein Dienstkonto können mehrere Anmeldedaten gleichzeitig aktiv sein, sodass eine Rotation ohne Ausfallzeit möglich ist:

  1. Erstellen Sie einen Ersatzschlüssel oder OAuth-Client für dasselbe Dienstkonto.
  2. Stellen Sie ihn in Ihrer Anwendung bereit (während der Überschneidung funktionieren beide Anmeldedaten).
  3. Vergewissern Sie sich, dass der Produktionsdatenverkehr die neuen Anmeldedaten verwendet — der Zeitpunkt der letzten Verwendung jedes Schlüssels ist im Portal sichtbar.
  4. Widerrufen Sie die alten Anmeldedaten.