Skip to content

Authentification

Quatre mécanismes coexistent, chacun répondant à une situation d'accès différente — aucun n'est un remplacement générique des autres. Cette page vous aide à choisir le bon, puis détaille chacun.

Choisir le bon mécanisme

flowchart TD
    A{Qui accède à l'API ?} -->|Un système, sans humain derrière chaque appel| B{Une seule entité juridique ?}
    B -->|Oui| C[API Key]
    B -->|Non — plusieurs comptes clients gérés par une même intégration| D[OAuth 2.0 Client Credentials]
    A -->|Une personne, au clavier, qui gère le compte| E[Login humain — portal:session]
    A -->|Un sous-traitant sans compte propre, reçoit un lien| F{A besoin de signer ?}
    F -->|Non, juste consulter/commenter| G[carrierAccessCode seul]
    F -->|Oui| H[carrierAccessCode + escalade de session]
    A -->|Un signataire avec son propre téléphone| I[Lien de contexte + WebAuthn]

Tableau de décision

Mécanisme Point d'entrée Preuve d'identité Portée des permissions Détail
API Key Header X-API-KEY Secret partagé, révocable Toutes les permissions métier du compte Ci-dessous
OAuth 2.0 Client Credentials POST /oauth/token client_id/client_secret Toutes les permissions métier du compte visé Ci-dessous
Login humain POST /v1/accounts/login Email + mot de passe (par personne) Permissions métier du compte + gestion du compte selon le rôle (Administrateur/Opérateur) — voir ci-dessous Ci-dessous
carrierAccessCode Lien envoyé au sous-traitant, sans compte Le code lui-même Plafonnée à VIEW + COMMENT, quel que soit le rôle réel Ci-dessous
carrierAccessCode + escalade Le même code, puis vérification SMS Code + numéro de téléphone (OTP) Permissions complètes du rôle assigné (y compris SIGN) Ci-dessous
Lien de contexte + WebAuthn QR code / lien scanné Biométrie de l'appareil du signataire Permissions du rôle, le temps de la cérémonie de signature Expérience terrain, Signature électronique

Les trois premières lignes émettent toutes un jeton de type porteur (bearer) — le reste de l'API ne fait aucune différence entre un appel authentifié par API Key, par OAuth2, ou par une session de login humain : ownPermissions reflète les mêmes permissions métier dans les trois cas, pour le même compte. Les deux dernières lignes sont d'une nature différente : elles ne représentent jamais le compte organisation lui-même, mais un accès temporaire, borné à un document et (souvent) un rôle précis.

API Key — recommandé par défaut

Adaptée si votre intégration représente une seule entité juridique. Une clé au format sk_live_... (production) ou sk_test_... (environnement de test), à transmettre dans le header X-API-KEY de chaque requête.

La clé n'est affichée qu'une seule fois à sa création — conservez-la immédiatement dans un gestionnaire de secrets. Une clé peut être révoquée immédiatement en cas de compromission, et supporte une rotation sans interruption de service (une période de recouvrement permet à l'ancienne et la nouvelle clé de fonctionner simultanément).

OAuth 2.0 (Client Credentials) — pour les intégrateurs multi-comptes

Si vous gérez, en tant que partenaire technique, plusieurs comptes clients distincts sous une seule intégration (par exemple un TMS qui sert plusieurs sociétés de transport), utilisez le flux Client Credentials :

POST /oauth/token
grant_type=client_credentials

Authentifiez-vous via Basic Auth ou dans le corps de la requête avec votre client_id/client_secret. Vous recevez un token d'accès de courte durée (JWT), à renouveler à chaque expiration — pas de refresh token, redemandez simplement un nouveau token.

Login humain (portal:session)

Pour une personne qui gère le compte au clavier — typiquement via un portail de gestion — plutôt qu'un système qui appelle l'API pour son compte.

POST /v1/accounts/login
{ "email": "...", "password": "..." }

Un compte peut avoir plusieurs personnes qui s'y connectent, chacune avec son propre email et mot de passe (un membre), plutôt qu'un identifiant unique partagé par toute une équipe. Chaque membre a un rôle :

  • Opérateur — accès métier complet, identique à ce qu'une API Key ou un accès OAuth2 permet sur ce compte (créer/consulter des documents, etc.).
  • Administrateur — les mêmes permissions qu'un Opérateur, plus la gestion des membres eux-mêmes (inviter, révoquer, changer de rôle) et des ressources de gestion du compte (clés API, clients OAuth2, sous-comptes).

Le jeton renvoyé porte le scope portal:session dans tous les cas — une seule session couvre à la fois l'accès métier et, pour un Administrateur, les endpoints de gestion du compte, là où le compte devait auparavant choisir entre un jeton de gestion sans accès métier et une clé API sans accès de gestion. Un compte nouvellement créé démarre avec un unique membre Administrateur (le compte utilisé à l'inscription) ; les membres suivants sont ajoutés depuis le portail par un Administrateur existant, qui envoie une invitation par email — le nouveau membre choisit lui-même son mot de passe, il ne lui est jamais communiqué par un tiers.

Ce scope est distinct de l'ancien jeton account:manage (toujours accepté par les endpoints de gestion, mais plus jamais émis par /login) — les deux ne sont pas interchangeables : account:manage reste strictement incapable d'atteindre un endpoint métier. Ce détail ne concerne que les clients qui manipulent des scopes directement (rare — la plupart des intégrations n'ont jamais besoin de le savoir).

Les mécanismes de la ligne du dessus (API Key, OAuth 2.0) ne sont pas concernés par cette notion de membre — ce sont des identifiants machine, communs à tout le compte, indépendants de qui s'est connecté au portail.

La réponse de /login peut demander de choisir un compte

Puisqu'un même email peut légitimement être membre de plusieurs comptes différents (deux entreprises distinctes, sans lien entre elles), la réponse de POST /v1/accounts/login porte désormais un champ selection_required :

  • selection_required: false (le cas normal, un seul compte correspond) — access_token est présent immédiatement, rien ne change par rapport à avant.
  • selection_required: true — le mot de passe fourni s'est vérifié correct pour plusieurs comptes distincts sous cette adresse. Aucun access_token n'est encore émis : la réponse contient à la place un selection_token (de courte durée) et la liste accounts (id, company_name) de chacun. Il faut alors appeler POST /v1/accounts/login/select avec { "selection_token": "...", "account_id": "..." } pour obtenir le véritable access_token — sans jamais renvoyer le mot de passe une seconde fois.

Ce deuxième cas ne peut jamais survenir sans qu'un mot de passe correct ait déjà été fourni pour chacun des comptes listés — un mot de passe incorrect renvoie toujours l'erreur générique habituelle (auth.invalid_credentials), identique que l'email corresponde à zéro, un, ou plusieurs comptes.

carrierAccessCode — sans compte ni mot de passe

Pour donner un accès temporaire à un sous-traitant qui n'a pas de compte e-CMR — le cas nominal étant un chauffeur ou une société de transport ponctuelle qui reçoit simplement un lien.

Un compte titulaire d'un rôle habilité à déléguer (CARRIER, SUBSEQUENTCARRIER, SUBCONTRACTOR) émet un code :

POST /v1/freightdocuments/{id}/roles/{roleId}/access-codes

Le sous-traitant échange ensuite ce code contre un accès :

POST /v1/access-codes/redeem
{ "code": "..." }

Cet accès est délibérément plafonné à VIEW et COMMENT, quelles que soient les permissions réelles du rôle assigné — consulter le document et commenter, rien de plus, tant que l'étape suivante n'a pas eu lieu.

Escalade de session : passer de la consultation à l'action

Pour obtenir les permissions complètes du rôle (par exemple SIGN ou CHANGE_STATUS), la même personne prouve son identité par SMS :

POST /v1/access-codes/session/otp/request
{ "code": "...", "phone_number": "..." }

POST /v1/access-codes/session/otp/verify
{ "code": "...", "phone_number": "...", "otp_code": "..." }

Le jeton renvoyé par la vérification porte alors l'ensemble des permissions du rôle assigné — c'est le même principe de "consultation d'abord, action après preuve d'identité" que le lien de contexte décrit ci-dessous, appliqué ici à un accès sans compte plutôt qu'à un accès par QR code.

Lien de contexte + WebAuthn

Pour un signataire qui utilise son propre téléphone — le mécanisme derrière ecmr-app et le parcours de signature électronique. Un lien ou un QR code encode un accès borné à une demande de signature précise ; l'appareil du signataire vérifie son numéro de téléphone puis établit une clé WebAuthn propre à cet appareil (biométrie native — Face ID, Touch ID, Windows Hello selon la plateforme), sans que cette clé transite jamais par vos serveurs.

Ce mécanisme est décrit en détail dans deux pages dédiées plutôt que dupliqué ici :

  • Expérience terrain — ce que voit concrètement le chauffeur/signataire, et comment ce lien s'articule avec votre intégration.
  • Signature électronique — le détail du parcours de signature lui-même (déclenchement du challenge, signature_level, vérification publique).

Où réside la garantie d'identité ?

Le lien de contexte et la connexion classique ne sont que des mécanismes d'accès — ils ouvrent une session, mais ne prouvent jamais à eux seuls qui agit. La garantie d'identité repose entièrement sur la cérémonie de signature WebAuthn : une clé cryptographique liée à un appareil physique, déverrouillée par biométrie, dont la création n'a été possible qu'après une vérification par SMS au moment de l'enrôlement. Concrètement : quelqu'un qui obtiendrait un lien ou un mot de passe pourrait consulter un document, mais ne pourrait pas signer à la place du titulaire sans posséder aussi son appareil déjà enrôlé. Pour l'expéditeur et le destinataire, une protection supplémentaire existe : chaque partie signe obligatoirement sur son propre appareil (via un QR affiché par le chauffeur), jamais sur celui d'un tiers.