Przejdź do głównej zawartości

Uwierzytelnianie i klucze API

DUST API uwierzytelnia każde żądanie /api/v1/* za pomocą tokenu JWT typu Bearer wystawionego przez AuthD, usługę kont DUST. Integracje API działają jako konto usługi — tożsamość maszynowa należąca do twojej organizacji — nigdy jako osoba. Przebieg wygląda następująco:

  1. Administrator organizacji tworzy konto usługi i wystawia dla niego poświadczenie (jednorazowo).
  2. Twoja integracja wymienia poświadczenie na krótkotrwały token Bearer.
  3. Wysyłaj nagłówek Authorization: Bearer <token> w wywołaniach API i ponawiaj wymianę, gdy token wygaśnie.

Konto usługi to pełnoprawna tożsamość maszynowa: należy do dokładnie jednej organizacji, można mu przyznać dostęp do zespołów tak jak członkowi, a każda wykonana przez nie czynność jest zapisywana w dzienniku audytu jako czynność konta usługi — a nie pracownika, który akurat je skonfigurował. Jego poświadczenia można w dowolnej chwili zmienić lub unieważnić bez ingerencji w czyjekolwiek konto osobiste.

Dostępne są dwa typy poświadczeń, a jedno konto usługi może mieć oba:

  • Klucz API — najprostsza integracja: wymiana klucza na token jednym wywołaniem HTTP.
  • Klient OAuth2 (client_credentials) — dla oprogramowania pośredniczącego klasy enterprise (SAP Integration Suite, MuleSoft, Boomi, …) z wbudowaną obsługą OAuth2.

Kontami usług i ich poświadczeniami zarządzają administratorzy organizacji w portalu AuthD pod adresem authd.dustid.io.

  1. Zaloguj się w authd.dustid.io jako administrator organizacji.
  2. Otwórz stronę swojej organizacji i wybierz kartę Konta usług.
  3. Utwórz konto usługi (na przykład „Łącznik SAP” lub „Stanowisko skanowania linii 3”).
  4. Otwórz Zarządzaj przy koncie usługi i utwórz klucz API.
  5. Przechowuj klucz w menedżerze sekretów — traktuj go jak hasło. Jest wyświetlany tylko raz.

Przeczytaj to przed pierwszym przykładem: miejsce przechowywania poświadczenia to jedyna decyzja, która przesądza o bezpieczeństwie integracji z DUST.

  • Poświadczenia przechowuj wyłącznie na swoich serwerach — w zmiennych środowiskowych lub menedżerze sekretów, nigdy w pakietach klienckich ani w systemie kontroli wersji.
  • Tokeny Bearer również są poświadczeniami. Są krótkotrwałe, ale token wygenerowany z twojego poświadczenia działa z pełnym dostępem konta usługi — do każdej organizacji, każdego zespołu i każdej operacji, do których to konto ma dostęp. Krótki czas życia ogranicza okno czasowe, a nie zasięg szkód.
  • Jeśli twoja aplikacja internetowa lub mobilna potrzebuje danych DUST, obsługiwany wzorzec to: przeglądarka → twój backend → DUST API. Twój backend przechowuje poświadczenie, generuje token Bearer, decyduje, który kontekst i którą operację wywołujący może wykorzystać, i sam wywołuje DUST API. Przeglądarka nigdy nie otrzymuje żadnego poświadczenia DUST. Integracje skanerów i aplikacji mobilnych mają dokładnie taki kształt: ujęcie trafia do twojego backendu, który wywołuje punkty końcowe identyfikatorów przy użyciu poświadczeń przechowywanych na serwerze.
  • Jedno konto usługi na aplikację i środowisko sprawia, że rotacja, unieważnianie i audyt są precyzyjne.

GET /api/auth/token przyjmuje klucz API w nagłówku x-api-key i zwraca token JWT. (APID przekazuje to żądanie do AuthD, więc jeden bazowy adres URL obsługuje wszystko).

To wywołanie i każde wywołanie oparte na jego wyniku jest wykonywane na serwerze.

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

Odpowiedź:

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

expiresIn to pozostały czas życia tokenu w sekundach; expiresAt to ten sam moment w postaci znacznika czasu ISO 8601. Oba pola są wyznaczane na podstawie oświadczenia o wygaśnięciu zawartego w samym tokenie, więc token wystawiony bez takiego oświadczenia zostanie zwrócony jako samo { "token": "…" } — odczytuj je ostrożnie i w razie ich braku stosuj własny, zachowawczy margines. Użyj dowolnego z nich do zaplanowania kolejnej wymiany; nie wpisuj czasu życia na stałe w kodzie.

W przypadku platform natywnie obsługujących OAuth2 utwórz na koncie usługi klienta OAuth zamiast klucza API (lub obok niego). Identyfikator i sekret klienta są wyświetlane tylko raz, podczas tworzenia.

Zażądaj tokenu z punktu końcowego tokenów kont usług, używając standardowego typu uprawnienia client_credentials — akceptowane są zarówno client_secret_post (pola formularza), jak i client_secret_basic (HTTP Basic):

Okno terminala
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"

Odpowiedź (standardowa odpowiedź tokenu OAuth2):

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

Otrzymany token ma taką samą strukturę i takie same uprawnienia jak token z wymiany klucza API — używaj go w ten sam sposób. Jeśli twoje oprogramowanie pośredniczące prosi o „token URL”, podaj powyższy punkt końcowy.

Wysyłaj token w każdym wywołaniu podstawowego API:

Authorization: Bearer <token>

Szybki sposób na sprawdzenie, czy token działa:

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

Żądania bez prawidłowego tokenu otrzymują 401 z treścią { "code": "UNAUTHORIZED", "message": "...", "status": 401 } — kontrakt błędów opisano w sekcji Konwencje żądań, a pełną listę kodów w sekcji Błędy i wyniki skanowania.

Tokeny Bearer kont usług są krótkotrwałe — obecnie 15 minut, ale zawsze odczytuj czas życia z odpowiedzi (expiresIn/expiresAt przy wymianie klucza, expires_in przy uprawnieniu OAuth), zamiast wpisywać go na stałe. Nie ma tokenu odświeżania: gdy token wygaśnie, ponownie wymień poświadczenie.

Niezawodny klient łączy oba wzorce — odświeża token z wyprzedzeniem, z marginesem bezpieczeństwa, a pojedynczą odpowiedź 401 traktuje jako sygnał do odświeżenia i ponowienia żądania (obejmuje to również rozbieżność zegarów i unieważnienie w trakcie czasu życia tokenu):

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;
}

Wymiana jest tania; nie buduj wokół niej długotrwałych pamięci podręcznych. Krótki czas życia jest też twoim scenariuszem na wypadek incydentu: unieważnienie poświadczenia natychmiast wstrzymuje wydawanie nowych tokenów, a każdy już wystawiony token wygasa w ciągu kilku minut.

Konto usługi uwierzytelnia system; nie może przekazać DUST, która osoba nacisnęła przycisk w twoim systemie ERP lub na hali produkcyjnej. Jeśli zależy ci na takiej identyfikowalności, deklaruj ją w każdym żądaniu za pomocą nagłówka Dust-Ctx-Declared-Actor — niewielkiego obiektu JSON:

Dust-Ctx-Declared-Actor: {"id": "JDOE", "system": "SAP", "displayName": "Jane Doe"}
  • Pole id jest wymagane; pola system, displayName i role są opcjonalne. Wartość może być zakodowana w formacie URI (jest to wymagane, jeśli zawiera znaki spoza ASCII) i musi mieć mniej niż 1 KB.
  • Zadeklarowany wykonawca jest zapisywany dosłownie przy każdym zdarzeniu zapisywanym przez żądanie i wyświetlany w historii aktywności jako przypisanie zadeklarowane — podaje go twoja integracja, DUST go nie weryfikuje i nigdy nie przyznaje ani nie ogranicza on uprawnień.
  • Administrator organizacji może ustawić zasady przypisania konta usługi na wymagane — wówczas żądania zapisu bez zadeklarowanego wykonawcy są odrzucane z błędem 403 ATTRIBUTION_REQUIRED.

API weryfikuje podpis każdego tokenu Bearer względem zestawu kluczy JSON Web Key Set usługi AuthD oraz sprawdza oświadczenia wystawcy (https://authd.dustid.io/api/auth w środowisku produkcyjnym) i odbiorcy. Zwykle ta wiedza nie jest potrzebna — ale jeśli twój własny backend ma weryfikować tokeny JWT wystawione przez DUST (na przykład aby ufać tokenowi przekazanemu z innej usługi wewnętrznej), zestaw JWKS jest publiczny:

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

Zwraca standardowy dokument { "keys": [ ... ] }, którego można użyć z dowolną biblioteką JOSE.

Integracja skanowania w przeglądarce od początku do końca

Dział zatytułowany „Integracja skanowania w przeglądarce od początku do końca”

Poniższy wzorzec pokazuje, jak powinna wyglądać każda integracja skanowania w przeglądarce lub aplikacji mobilnej. Dwa pliki, dwa miejsca wykonywania, jedno poświadczenie — i nigdy nie opuszcza ono drugiego pliku.

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,
});
}

Twoje proxy to także naturalne miejsce na reguły dla poszczególnych użytkowników, o których DUST API nie może wiedzieć: które zespoły dany pracownik może przeszukiwać, czy oprócz identyfikowania może również wiązać identyfikatory oraz co trafia do twoich logów.

Na jednym koncie usługi może być jednocześnie aktywnych wiele poświadczeń, więc rotacja nigdy nie wymaga przestoju:

  1. Utwórz klucz zastępczy (lub klienta OAuth) na tym samym koncie usługi.
  2. Wdróż go w swojej aplikacji (w okresie przejściowym działają oba poświadczenia).
  3. Upewnij się, że ruch produkcyjny korzysta z nowego poświadczenia — czas ostatniego użycia każdego klucza jest widoczny w portalu.
  4. Unieważnij stare poświadczenie.