Aller au contenu principal
Version: Cible · roadmap

Demander l'authentification

Une skill peut être réservée à une personne authentifiée. Ce n'est pas au modèle de le deviner, ni de demander un code à l'oral : Core le sait par la config, l'annonce, et le demande lui-même, au bon moment, avec le bon parcours pour la surface.

Rien de nouveau ne s'écrit pour cela. Une demande d'authentification se déduit de ce que la station déclare déjà : les grants et les permissions, les profils, les fournisseurs et le fournisseur que chaque portail propose.

Quand Core demande​

Core demande l'authentification quand deux conditions sont vraies :

  1. l'identité actuelle ne passe pas une règle : un grant absent, une permission, un require ;
  2. une preuve que ce portail sait faire pourrait l'ouvrir. Par exemple, la règle lit 'email' in identity.verified, et le portail propose un fournisseur qui verifies: email.

Si aucune preuve possible sur ce portail ne peut ouvrir la règle, Core ne demande rien : c'est un refus, ou un item caché. On ne fait pas prouver un e-mail pour rien.

Si la preuve est faite mais ne suffit pas (la personne est vérifiée, mais pas premium), la règle refuse comme d'habitude, et la demande n'est pas répétée.

Le moment dépend de la phase​

la règle porte surCore demandece que voit la personne avant
invoke (ou le grant de l'opération lue)avant l'appel : la skill n'est pas lancéerien de la skill
present (un kind réservé)avant l'appel, comme pour invokerien de la skill ; elle peut continuer sans, et voit alors ce qui n'est pas réservé
select (choisir un kind)quand elle choisit l'itemles items, dont celui qu'elle veut choisir
submit (le grant de l'écriture, submitted_by: owner)quand elle soumettoute sa sélection

Pour present, la demande se décide sur la config, pas sur le résultat : elle dit que la skill a une partie réservée, jamais que cette recherche a trouvé quelque chose de caché. Les items réservés restent retirés avant le modèle, et les comptes sont faits après le filtre (Permissions).

L'appel reprend tout seul​

Quand la preuve est faite, Core relance l'appel en attente, avec les mêmes arguments : la recherche, le choix, ou le submit. La personne n'a rien à redemander.

  • Une room a une seule demande en attente ; une nouvelle remplace l'ancienne.
  • Elle expire avec la demande : un appel abandonné n'est pas relancé une heure plus tard.
  • La relance repasse par toutes les règles : la preuve ouvre l'accès, elle ne le force pas.

L'étiquette, écrite par Core​

Une skill réservée est annoncée comme telle, au modèle et à l'écran, sur les deux portes. Core écrit l'étiquette à partir des règles ; le tenant ne l'écrit pas, et elle ne peut donc pas mentir.

phaseétiquette
invoke« Réservé : prouvez votre e-mail pour l'utiliser. »
present« Une partie est réservée aux clients qui ont prouvé leur e-mail. »
select« Prouvez votre e-mail pour choisir cette option. »
submit« Prouvez votre e-mail pour soumettre. »

Le nom de la donnée vient du fournisseur du portail (verifies:) ; le texte vient du catalogue de textes de Core, dans la langue du tenant.

Le parcours : un playbook d'authentification​

Une demande se présente comme un playbook : des étapes à l'écran, l'une après l'autre, puis la suite. Ce n'est pas un playbook de la config — le tenant ne l'écrit pas, et il ne compte pas dans ses playbooks —, mais il se lit et s'affiche de la même façon. Ses étapes dépendent du mécanisme du fournisseur.

otp — trois étapes.

  1. La donnée. « Votre e-mail ». Pré-remplie si la room la tient déjà (déclarée par un formulaire) ; la personne la confirme ou la corrige. Elle est écrite dans sa forme unique (e-mail en minuscules, téléphone au format international) avant l'envoi.
  2. Le code. « Entrez le code reçu à a***@mail.com. » Avec « Renvoyer », et la phrase du tenant quand il refuse (trop de codes demandés, code expiré). Convoy pose ses propres limites, par donnée et sur les deux portes à la fois : 5 codes faux bloquent les essais pendant 15 minutes, et 5 codes envoyés par heure au plus. Un nouveau code remet les essais à zéro, pas les envois.
  3. Fait. « Votre e-mail est vérifié. » Puis l'appel en attente reprend.

oidc — une étape. Un bouton « Se connecter avec … » ouvre la page du fournisseur. Au retour, c'est fait, et l'appel reprend.

assertion — une étape, ou aucune. Si la personne est connectée sur le site du tenant, elle est déjà vérifiée : rien ne s'affiche. Sinon, un lien vers la page de connexion que le tenant déclare ; Convoy n'invente jamais d'adresse sur son domaine.

Selon la surface​

Les étapes sont les mêmes partout ; où elles s'affichent dépend de la surface. Sur le widget et la PWA, dans le cadre. Sur Claude et ChatGPT, dans la fenêtre de connexion de l'hôte, qui mène à la page Convoy du tenant ; l'hôte relance lui-même l'appel. Sur WhatsApp, dans la conversation, menée par Core. Voir Le parcours d'authentification.

Le modèle ne lance jamais une preuve là où la surface sait afficher les étapes, et il ne voit ni la donnée ni le code. Il reçoit seulement « la personne se connecte ; attendez », puis le résultat de l'appel relancé. Là où la surface n'a ni cadre ni fenêtre de connexion (WhatsApp), c'est Core qui mène les étapes, pas le modèle.

L'authentification appartient à qui parle sur cette surface (son compte Claude, son navigateur, son numéro), pas à la room : le code d'une room ne donne aucun droit.

Ce que le chargement vérifie​

Le graphe des permissions vérifie aussi les demandes :

  • une règle qu'aucun fournisseur de la station ne peut satisfaire ('phone' in identity.verified sans fournisseur qui verifies: phone) est refusée : la demande serait impossible partout ;
  • une skill exposée sur un portail dont le fournisseur ne peut pas ouvrir sa règle donne un avertissement : sur ce portail, la skill est simplement indisponible, sans demande ;
  • un fournisseur assertion utilisé par une demande doit déclarer sa page de connexion.

Exemple​

Les visiteurs anonymes voient l'épicerie. Prouver son e-mail donne l'historique des commandes, et les produits réservés aux clients.

station:
identity:
providers:
email: {mechanism: otp, verifies: email, via: tenant,
send: sendVerificationCode, check: checkVerificationCode}

profiles:
anonyme:
when: "identity.authenticated == false"
grants: [boutique.searchProducts, boutique.createOrder]
client:
when: "'email' in identity.verified"
grants: [boutique.searchProducts, boutique.createOrder, boutique.listOrders]

skills:
- name: commandes # listOrders : seul `client` l'a reçu → demande à l'invoke
invoke: {method: listOrders}
- name: produits
invoke: {method: searchProducts}
kinds:
reserve: # demande avant l'appel ; « continuer sans » montre le reste
when: "$fields.tier == 'client'"
present: {guards: [{permission: {profiles: [client]}}]}
present:
fields:
name: {from: name, type: text, role: title}
tier: {from: tier, type: text}

agent:
portals:
web:
widget: {identity: {auth: email}}

Un visiteur anonyme demande ses commandes. Le modèle appelle commandes ; Core ne la lance pas et affiche le parcours : l'e-mail, le code, « vérifié ». Puis commandes reprend et montre l'historique. Le modèle n'a vu ni l'adresse ni le code.

Si reserve exigeait un abonnement ('abonne' in identity.plans), un code par e-mail ne pourrait pas l'ouvrir : Core ne demanderait rien, et les produits réservés resteraient cachés.