Authentification et clés d’API
L’API DUST authentifie chaque requête /api/v1/* à l’aide d’un JWT Bearer émis par AuthD, le service de comptes DUST. Les intégrations d’API agissent en tant que compte de service — une identité machine détenue par votre organisation — et jamais en tant que personne. Le processus est le suivant :
- Un administrateur de l’organisation crée un compte de service et lui attribue un identifiant d’accès (une seule fois).
- Votre intégration échange cet identifiant contre un jeton Bearer à courte durée de vie.
- Envoyez
Authorization: Bearer <token>lors des appels d’API et effectuez un nouvel échange lorsque le jeton expire.
Comptes de service
Section intitulée « Comptes de service »Un compte de service est une identité machine à part entière : il appartient à une seule organisation, peut recevoir un accès à une équipe comme un membre, et chaque action qu’il effectue est consignée dans le registre d’audit sous l’identité du compte de service — et non sous celle de l’employé qui l’a configuré. Ses identifiants d’accès peuvent être renouvelés ou révoqués à tout moment sans modifier le compte personnel de quiconque.
Deux types d’identifiants d’accès sont disponibles, et un même compte de service peut détenir les deux :
- Clé d’API — l’intégration la plus simple : échangez la clé contre un jeton en un seul appel HTTP.
- Client OAuth2 (
client_credentials) — pour les intergiciels d’entreprise (SAP Integration Suite, MuleSoft, Boomi, etc.) avec prise en charge intégrée d’OAuth2.
Créer une clé d’API
Section intitulée « Créer une clé d’API »Les comptes de service et leurs identifiants d’accès sont gérés par les administrateurs de l’organisation dans le portail AuthD à l’adresse authd.dustid.io.
- Connectez-vous à authd.dustid.io en tant qu’administrateur de l’organisation.
- Ouvrez la page de votre organisation et sélectionnez l’onglet Comptes de service.
- Créez un compte de service (par exemple, « Connecteur SAP » ou « Poste de scan de la ligne 3 »).
- Ouvrez Gérer pour le compte de service et créez une clé d’API.
- Stockez la clé dans un gestionnaire de secrets — traitez-la comme un mot de passe. Elle n’est affichée qu’une seule fois.
Conserver les identifiants d’accès côté serveur
Section intitulée « Conserver les identifiants d’accès côté serveur »Lisez ceci avant le premier exemple : l’emplacement où réside un identifiant d’accès est la décision déterminante pour la sécurité d’une intégration DUST.
- Les identifiants d’accès résident uniquement sur vos serveurs — dans des variables d’environnement ou un gestionnaire de secrets, jamais dans des bundles clients ni dans le contrôle de version.
- Les jetons Bearer sont également des identifiants d’accès. Leur durée de vie est courte, mais un jeton généré à partir de votre identifiant confère les accès complets du compte de service — à chaque organisation, équipe et opération auxquelles ce compte peut accéder. Une courte durée de vie limite la fenêtre d’exploitation, pas l’étendue des conséquences.
- Si votre application web ou mobile a besoin de données DUST, le modèle pris en charge est navigateur → votre backend → API DUST. Votre backend conserve l’identifiant d’accès, génère le jeton Bearer, décide du contexte et de l’opération autorisés pour l’appelant, puis appelle lui-même l’API DUST. Le navigateur ne reçoit jamais aucun identifiant d’accès DUST. Les intégrations de scanner et mobiles suivent exactement ce modèle : la capture est envoyée à votre backend, qui appelle les endpoints Identifier avec des identifiants d’accès conservés sur le serveur.
- Un compte de service par application et par environnement permet de cibler précisément le renouvellement, la révocation et l’audit.
Échanger la clé contre un jeton Bearer
Section intitulée « Échanger la clé contre un jeton Bearer »GET /api/auth/token reçoit la clé d’API dans l’en-tête x-api-key et renvoie un JWT. (APID transmet cette requête à AuthD, de sorte qu’une seule URL de base couvre l’ensemble.)
Cet appel, ainsi que chaque appel reposant sur son résultat, s’exécute sur un serveur.
curl -fsS "https://apid.dustid.io/api/auth/token" \ -H "x-api-key: $DUST_API_KEY"const response = await fetch("https://apid.dustid.io/api/auth/token", { headers: { "x-api-key": process.env.DUST_API_KEY! },});const { token, expiresIn } = await response.json();Réponse :
{ "token": "eyJhbGciOi...", "expiresIn": 900, "expiresAt": "2026-07-14T22:40:00.000Z" }expiresIn correspond à la durée de vie restante du jeton en secondes ; expiresAt représente le même instant sous la forme d’un horodatage ISO 8601. Ces deux valeurs sont dérivées de la revendication d’expiration du jeton lui-même. Par conséquent, un jeton émis sans cette revendication est renvoyé seul sous la forme { "token": "…" } — lisez ces valeurs de manière défensive et, si elles sont absentes, appliquez votre propre marge prudente. Utilisez l’une ou l’autre pour planifier le prochain échange ; ne codez pas la durée de vie en dur.
Client OAuth2 client_credentials
Section intitulée « Client OAuth2 client_credentials »Pour les plateformes qui prennent nativement en charge OAuth2, créez un client OAuth sur le compte de service à la place d’une clé d’API, ou en complément de celle-ci. L’identifiant et le secret du client ne sont affichés qu’une seule fois lors de leur création.
Demandez un jeton à l’endpoint de jeton du compte de service à l’aide du type d’autorisation standard client_credentials — client_secret_post (champs de formulaire) et client_secret_basic (HTTP Basic) sont tous deux acceptés :
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"Réponse (réponse de jeton OAuth2 standard) :
{ "access_token": "eyJhbGciOi...", "token_type": "Bearer", "expires_in": 900 }Le jeton obtenu possède exactement la même structure et les mêmes droits qu’un jeton issu de l’échange d’une clé d’API — utilisez-le de la même manière. Si votre intergiciel demande une « URL de jeton », utilisez l’endpoint ci-dessus.
Utiliser le jeton Bearer
Section intitulée « Utiliser le jeton Bearer »Envoyez le jeton lors de chaque appel à l’API principale :
Authorization: Bearer <token>Voici une méthode rapide pour confirmer que le jeton fonctionne :
curl -fsS "https://apid.dustid.io/api/v1/me" \ -H "Authorization: Bearer $DUST_TOKEN"Les requêtes dépourvues d’un jeton valide reçoivent une réponse 401 avec le corps { "code": "UNAUTHORIZED", "message": "...", "status": 401 } — consultez Conventions relatives aux requêtes pour le contrat d’erreur et Erreurs et résultats de scan pour la liste complète des codes.
Expiration et renouvellement des jetons
Section intitulée « Expiration et renouvellement des jetons »Les jetons Bearer des comptes de service ont une courte durée de vie — actuellement 15 minutes, mais lisez toujours la durée de vie dans la réponse (expiresIn/expiresAt pour l’échange d’une clé, expires_in pour l’autorisation OAuth) plutôt que de la coder en dur. Il n’existe pas de jeton d’actualisation : lorsqu’un jeton expire, échangez de nouveau l’identifiant d’accès.
Un client robuste combine les deux méthodes : il renouvelle le jeton de manière proactive en conservant une marge de sécurité et considère une première réponse 401 comme un signal indiquant qu’il faut renouveler le jeton et réessayer (cela couvre également le décalage des horloges et la révocation avant l’expiration) :
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;}L’échange est peu coûteux ; ne construisez pas de caches de longue durée autour de celui-ci. La courte durée de vie constitue également votre mécanisme de réponse aux incidents : la révocation d’un identifiant d’accès empêche immédiatement la création de nouveaux jetons, et tout jeton déjà émis expire en quelques minutes.
Attribution de l’acteur déclaré
Section intitulée « Attribution de l’acteur déclaré »Un compte de service authentifie le système ; il ne peut pas indiquer à DUST quelle personne a appuyé sur le bouton dans votre ERP ou dans votre atelier. Si vous souhaitez disposer de cette traçabilité, déclarez-la pour chaque requête à l’aide de l’en-tête Dust-Ctx-Declared-Actor — un petit objet JSON :
Dust-Ctx-Declared-Actor: {"id": "JDOE", "system": "SAP", "displayName": "Jane Doe"}idest obligatoire ;system,displayNameetrolesont facultatifs. La valeur peut être encodée sous forme d’URI (obligatoire si elle contient des caractères non ASCII) et doit rester inférieure à 1 Ko.- L’acteur déclaré est consigné textuellement dans chaque événement écrit par la requête et apparaît dans l’historique des activités comme une attribution déclarée — il est fourni par votre intégration, n’est pas vérifié par DUST et n’accorde ni ne restreint jamais aucune autorisation.
- Un administrateur de l’organisation peut définir la politique d’attribution d’un compte de service sur obligatoire, auquel cas les requêtes d’écriture dépourvues d’acteur déclaré sont rejetées avec
403 ATTRIBUTION_REQUIRED.
Méthode de vérification des jetons
Section intitulée « Méthode de vérification des jetons »L’API vérifie la signature de chaque jeton Bearer au moyen du jeu de clés web JSON d’AuthD et contrôle les revendications relatives à l’émetteur (https://authd.dustid.io/api/auth en production) et à l’audience. Vous n’avez normalement jamais besoin de ces détails — mais si votre propre backend doit vérifier des JWT émis par DUST (par exemple, afin de faire confiance à un jeton transmis par un autre service interne), le JWKS est public :
GET https://apid.dustid.io/api/auth/jwksIl renvoie un document standard { "keys": [ ... ] } utilisable avec n’importe quelle bibliothèque JOSE.
Une intégration de scan dans un navigateur, de bout en bout
Section intitulée « Une intégration de scan dans un navigateur, de bout en bout »Le modèle ci-dessous illustre la structure que toute intégration de scan dans un navigateur ou une application mobile doit adopter. Deux fichiers, deux emplacements d’exécution, un seul identifiant d’accès — qui ne quitte jamais le second fichier.
// 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();}// 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, });}Votre mandataire constitue également l’emplacement naturel des règles propres à chaque utilisateur que l’API DUST ne peut pas connaître : les équipes dans lesquelles cet employé peut effectuer une recherche, s’il peut effectuer une liaison en plus de l’identification, et les informations que vous consignez.
Renouveler une clé
Section intitulée « Renouveler une clé »Plusieurs identifiants d’accès peuvent être actifs simultanément sur un même compte de service, de sorte qu’un renouvellement ne nécessite aucune interruption de service :
- Créez une clé de remplacement (ou un client OAuth) sur le même compte de service.
- Déployez-la dans votre application (les deux identifiants d’accès fonctionnent pendant la période de chevauchement).
- Confirmez que le trafic de production utilise le nouvel identifiant d’accès — l’heure de dernière utilisation de chaque clé est visible dans le portail.
- Révoquez l’ancien identifiant d’accès.
Étapes suivantes
Section intitulée « Étapes suivantes »- Démarrage rapide avec l’API — du jeton à la première fiche en cinq minutes.
- Conventions relatives aux requêtes — les en-têtes de contexte requis pour chaque appel limité au périmètre d’une organisation.
- Erreurs et résultats de scan — gestion des réponses
401, renouvellement unique après une réponse 401 et reste du contrat d’échec. - Référence complète de l’API — chaque endpoint et chaque schéma.