cord login sans copier de clés, et un assistant qui intègre Cord pour vous

Comment nous avons construit le flux d’appareil du CLI de Cord, pourquoi le terminal reçoit une clé restreinte à usage unique et ce que fait l’assistant de npx @flouviahq/cli.

Le premier contact avec une plateforme de paiement est souvent le pire : se connecter au tableau de bord, trouver la section des clés, copier une chaîne de 50 caractères, la coller dans un .env et espérer ne pas l’avoir poussée sur GitHub. Avec Cord, nous voulions que tout tienne en une commande :

npx @flouviahq/cli

Le flux d’appareil

cord login reprend le principe de votre télévision quand elle vous demande de vous connecter depuis votre téléphone (le flux d’appareil de la RFC 8628) :

  1. Le terminal demande un code à POST /api/cli/login. Cord génère deux éléments : un device code de 32 octets aléatoires que seul le terminal connaît, et un user code court, comme WXYZ-2346, qui vous est affiché.
  2. Le terminal ouvre votre navigateur sur /app/cli/autorizar?codigo=WXYZ-2346. Là, avec votre session Cord habituelle, vous confirmez que le code est identique à celui affiché dans votre terminal, puis vous cliquez sur Autoriser.
  3. Pendant ce temps, le terminal interroge POST /api/cli/login/claim toutes les deux secondes avec son device code. Dès que vous autorisez l’accès, il reçoit la clé.

Quelques décisions qui ne sont pas évidentes :

  • Seul le sha256 du device code est stocké en base. Quelqu’un qui lirait la table ne pourrait rien réclamer.
  • Le user code évite les caractères qui se confondent quand on les dicte (0 et O, 1, I et L, 5 et S). Il compte 8 caractères tirés d’un alphabet de 25.
  • La table n’a aucune politique d’accès. La sécurité au niveau des lignes y est forcée, sans aucune politique : aucune requête directe ne la voit. Seules quatre fonctions security definer au périmètre restreint y touchent : créer, rechercher, décider et réclamer.
  • La clé n’est remise qu’une seule fois. Elle est stockée chiffrée jusqu’à ce que le terminal la réclame ; à ce moment-là, l’enregistrement passe à reclamado et le secret est supprimé. Le code expire au bout de 10 minutes.
  • Le terminal n’ouvre dans le navigateur qu’une adresse de même origine que l’API. Ce n’est pas le serveur qui décide vers quel site vous envoyer.

Une clé qui ne peut pas faire de dégâts

Le terminal ne reçoit pas une clé d’administrateur. Il reçoit une clé de test restreinte (rk_test_) avec trois droits : utiliser les simulateurs, lire les événements et proposer des configurations. Elle expire au bout de 90 jours et apparaît dans le panneau des clés API sous le nom CLI · <votre appareil>, où vous pouvez la révoquer.

Les clés restreintes de Cord ont un niveau d’accès par ressource, déduit de la route. Une nouvelle route de l’API leur est interdite dès sa création, jusqu’à ce que quelqu’un décide à quelle ressource elle appartient, et un test échoue si une route reste sans ressource.

Comme les clés de test comptent dans la limite de l’offre, reconnecter le même appareil révoque la clé précédente de cet appareil. Un terminal, une clé.

Une seule autorisation pour tout

Votre projet a aussi besoin d’une clé pour que son serveur communique avec Cord. Quand l’assistant s’apprête à intégrer un projet, l’écran d’autorisation affiche une case de plus : « Créer aussi une clé pour ce projet ». Si vous la laissez cochée, Cord crée une Secret Key de test, la chiffre avec celle du CLI et remet les deux ensemble, une seule fois. L’assistant l’écrit dans votre .env.local.

Si votre offre n’a plus de place pour une autre clé, le CLI se connecte quand même et la page vous le signale ; rien ne reste cassé à mi-chemin.

L’assistant

Lancé sans commande, le CLI ouvre un assistant avec des menus, des indicateurs de progression et un récapitulatif final. Étape par étape :

  1. Il connecte le terminal avec le flux décrit plus haut.
  2. Il vous demande quoi faire : configurer le compte avec l’IA, intégrer le projet et tester les webhooks.
  3. Il configure votre compte : il lit votre site et votre liste de prix, vous montre la proposition et attend que vous la validiez dans le navigateur.
  4. Il intègre le projet : il détecte le framework (Next.js, Astro, Express, Laravel, Django, Flask ou FastAPI), vous montre exactement ce qu’il va faire et, si vous acceptez, installe le SDK avec votre gestionnaire de paquets et crée deux routes : celle qui vérifie la signature de chaque webhook et un proxy pour Cord Elements.
  5. Il écoute les webhooks : il ouvre une session de test, enregistre son secret dans votre .env.local et transfère chaque événement à votre serveur local.

Trois règles que l’assistant n’enfreint jamais :

  • Il n’écrase aucun fichier. Si la route existe déjà, il la laisse en place et vous prévient.
  • Il n’écrit de clés que dans un fichier d’environnement ignoré par git. S’il n’en trouve pas, il n’écrit rien et vous indique quelle variable ajouter.
  • Il ne touche pas aux autres lignes de votre .env. Il met à jour ou ajoute uniquement les variables de Cord.
◆  Esto es lo que voy a hacer
│  +  instalar    @flouviahq/node @flouviahq/elements  · con npm
│  +  crear       app/api/webhooks/cord/route.ts       · verifica la firma de cada webhook
│  +  crear       app/api/cord/[...path]/route.ts      · proxy seguro para Cord Elements
│  ~  escribir    .env.local                           · CORD_SECRET_KEY de prueba

Sans dépendances

L’interface utilise @clack/prompts, mais le paquet publié ne dépend de rien : à la compilation, esbuild l’empaquette avec tout le reste dans un seul fichier. Installer le CLI n’ajoute aucun nouvel arbre de dépendances sur votre machine.

Essayez-le

npx create-next-app@latest my-store --ts --app
cd my-store
npx @flouviahq/cli

Une fois l’assistant terminé, lancez npm run dev dans un terminal et npx @flouviahq/cli trigger quote.approved dans un autre : l’événement arrive sur votre route, signé, et le terminal vous affiche le 200.