InstaTunnel
Basculer le menu de navigation
Tutorial
19 min read
69 views

Votre carte Agent A2A nécessite une URL publique : tester les notifications push A2A sur localhost

Votre carte Agent A2A nécessite une URL publique. Découvrez comment tester les notifications push sur localhost avec un tunnel stable et une inscription webhook résistante à SSRF.

IT
InstaTunnel Team
Published by the InstaTunnel team | Editorial policy
Votre carte Agent A2A nécessite une URL publique : tester les notifications push A2A sur localhost

Quick answer

Test des notifications push A2A sur localhost (URL de la carte Agent): quick comparison answer

Choose the tunnel tool based on the network model: public HTTPS URLs for webhooks and demos, private mesh access for internal apps, and managed infrastructure when policy controls matter most.

Which tunnel tool is best for public webhook testing?

Use a public HTTPS localhost tunnel with stable URLs. InstaTunnel focuses on webhook testing, demos, OAuth callbacks, and MCP endpoint workflows.

When should I choose a private network tool instead?

Choose a private mesh or Zero Trust tool when every user and service should stay inside a controlled private network.

Le protocole Agent2Agent (A2A) a rapidement grandi. Google l’a annoncé en avril 2025, la Linux Foundation l’a pris en charge en juin 2025, et la spécification stable v1.0 est sortie le 12 mars 2026. En août 2026, il est devenu un projet hébergé par l’Agentic AI Foundation (AAIF). Deux de ses blocs de construction sont importants pour le développement local. Notifications push sont de simples webhooks : le serveur agent envoie un HTTP POST à une URL enregistrée par le client. La carte Agent est un document JSON servi depuis un chemin bien connu.

Les deux rencontrent le même obstacle sur un ordinateur portable. Des pairs distants ne peuvent pas atteindre localhost, et un serveur agent bien conçu peut refuser d’envoyer un POST vers celui-ci. Ce guide explique pourquoi, comment tester les notifications push A2A depuis votre machine via un tunnel public, et comment enregistrer des webhooks sans ouvrir une faille SSRF.

Il s’agit des callbacks agent-à-agent et d’un enregistrement webhook sûr. Il omet délibérément les flux de découverte OAuth et d’autorisation-serveur.

Où en est A2A en novembre 2026

  • v1.0 a été livré le 12 mars 2026. Le blog du projet et le guide Turing Post l’attribuent à cette date, et Turing Post mentionne un correctif v1.0.1 en mai. La version 1.0 était la première spécification stable et prête pour la production. Sa définition protobuf, a2a.proto, est la source normative, et les formes JSON, gRPC et REST en sont générées.
  • La gouvernance a évolué en deux étapes. Google a donné A2A à la Linux Foundation en juin 2025. Le 17 août 2026, il a été annoncé comme un projet hébergé par l’AAIF, l’organisme de la Linux Foundation lancé en décembre 2025 autour de MCP, goose et AGENTS.md. L’annonce du projet A2A est datée du 27 août 2026 et décrit A2A comme un projet Growth Stage de l’AAIF. La couverture presse de ce déménagement s’est étendue du 17 au 20 août. Aucun contrôle n’a changé de mains. Google avait déjà donné la spec, et chaque projet AAIF conserve ses propres mainteneurs et son calendrier de versions.
  • L’écosystème est large. La Linux Foundation a enregistré plus de 150 organisations de soutien au cap d’un an du projet en avril 2026. Des SDK officiels existent pour Python, Go, JavaScript, Java, .NET et Rust. Le SDK JavaScript (@a2a-js/sdk) est passé en disponibilité générale 1.0.0 le 22 juillet 2026, avec une compatibilité opt-in v0.3 pour des migrations par étapes.
  • v1.0 définit trois liaisons standard du protocole : JSON-RPC 2.0 sur HTTP(S), gRPC et HTTP+JSON/REST.

L’issue pratique est que la spec est suffisamment stable pour investir dans des outils et des travaux de sécurité. Mais de nombreux agents déployés servent encore des formes de carte pré-1.0, il faut donc vérifier la version de chaque pair avant de tester contre lui.

Deux URLs publiques, pas une

Le titre dit « votre carte Agent a besoin d’une URL publique ». C’est vrai, mais seule la moitié d’un test A2A local en a besoin, et mélanger les deux moitiés provoque la plupart des confusions.

1. L’URL de la carte agent (l’adresse du serveur). Les serveurs A2A publient leur carte à l’adresse https://{server_domain}/.well-known/agent-card.json. Le chemin well-known suit la RFC 8615. Les anciens serveurs pré-1.0 utilisaient couramment /.well-known/agent.json, et des outils tels que a2aops reviennent à ce chemin historique lorsqu’ils vérifient une carte.

La carte répertorie les points de terminaison que les clients doivent appeler dans supportedInterfaces. Il s’agit d’un tableau ordonné dont la première entrée est l’interface préférée. Chaque entrée porte un url, un protocolBinding (JSONRPC, GRPC ou HTTP+JSON) et une protocolVersion, avec un champ optionnel tenant. La spec indique qu’une URL d’interface doit être une URL HTTPS absolue en production.

Si votre serveur tourne localement et qu’un client distant doit y accéder, comme un orchestrateur hébergé, l’agent d’un collègue ou une démonstration cloud, la carte et ses URL d’interface doivent être résolubles publiquement.

2. L’URL du webhook (l’adresse du client). Les notifications push circulent dans l’autre sens. Le client enregistre un webhook et le serveur y POST. Si vous développez le client localement et que vous testez contre un agent distant, votre webhook doit avoir une adresse publique.

Si vous exécutez deux agents locaux qui communiquent entre eux depuis des réseaux différents, vous avez besoin des deux : deux noms d’hôtes publics stables.

Comment fonctionnent les push notifications A2A

Les notifications push existent pour des tâches très longues (minutes, heures ou jours) et pour les clients qui ne peuvent pas maintenir une connexion de streaming ouverte, comme les applications mobiles ou les fonctions serverless. L’agent indique le support avec capabilities.pushNotifications: true dans sa carte. Si le drapeau est faux ou absent, les opérations de configuration push doivent retourner PushNotificationNotSupportedError.

  1. Enregistrer une configuration. Le client envoie un TaskPushNotificationConfig soit en ligne dans la requête SendMessage (sous configuration, l’ID de tâche laissé vide) soit séparément via l’opération de création sur une tâche existante. La spécification v1.0 définit les opérations Create, Get, List et Delete. En JSON-RPC ce sont CreateTaskPushNotificationConfig, GetTaskPushNotificationConfig, ListTaskPushNotificationConfigs et DeleteTaskPushNotificationConfig. En REST, elles se trouvent sous /tasks/{id}/pushNotificationConfigs.
  2. Ce que porte la configuration. Elle contient une url de webhook, un token optionnel pour la validation côté client, et des détails d’authentication (scheme et credentials) qui indiquent au serveur comment s’authentifier vers votre webhook. Elle porte également un id optionnel et le taskId.
  3. Le serveur POST sur les changements d’état. Le corps est un StreamResponse, la même forme utilisée en streaming. Il contient exactement l’un des éléments task, message, statusUpdate ou artifactUpdate.
  4. Votre récepteur le vérifie. L’exemple du guide montre que le serveur envoie un en-tête Authorization construit à partir de vos réglages authentication, plus X-A2A-Notification-Token portant le token que vous avez fourni.

La spec n’est pas d’accord sur chaque détail, alors concevez le récepteur de manière défensive :

  • Le texte normatif ne nomme pas d’en-tête de token. L’exemple montre X-A2A-Notification-Token. D’autres implémentations diffèrent : la crate Rust a2a-protocol-server envoie à la fois X-A2A-Notification-Token et un A2A-Notification-Token sans préfixe, acceptez donc les deux.
  • Les exemples dans la spec montrent le Content-Type du webhook comme application/a2a+json à un endroit et application/json à un autre. Analysez le corps JSON sans insister sur un seul type de média.

Une inscription ressemble à ceci, de manière approximative. Elle est simplifiée, alors confirmez la disposition exacte des champs avec a2a.proto pour votre version du SDK :

{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "CreateTaskPushNotificationConfig",
  "params": {
    "taskId": "task-123",
    "url": "https://a2a-client-dev.example.com/webhooks/a2a",
    "token": "per-task-secret-value",
    "authentication": { "scheme": "Bearer", "credentials": "webhook-credential" }
  }
}

Envoyez l’en-tête A2A-Version: 1.0 à chaque requête. La spec exige que les clients l’envoient afin qu’un agent qui met à jour plus tard ne change pas silencieusement le comportement.

Un fragment minimal de carte au style v1.0 montre où se situe l’adresse publique. Une carte complète nécessite également defaultInputModes, defaultOutputModes et skills :

{
  "name": "Flight Booking Agent",
  "description": "Handles flight reservations.",
  "version": "1.0.0",
  "supportedInterfaces": [
    {
      "url": "https://a2a-agent-dev.example.com/a2a",
      "protocolBinding": "JSONRPC",
      "protocolVersion": "1.0"
    }
  ],
  "capabilities": { "streaming": true, "pushNotifications": true }
}

Ce que la spec demande des expéditeurs et des destinataires

  • Les serveurs doivent tenter la livraison au moins une fois et peuvent réessayer avec un backoff exponentiel. Ils devraient utiliser un délai d’attente du webhook d’environ 10 à 30 secondes et peuvent s’arrêter après des échecs répétés.
  • Les destinataires doivent répondre avec un statut 2xx pour accuser réception, doivent traiter les notifications de manière idempotente car des duplications peuvent survenir, et doivent vérifier que le task ID correspond à une tâche attendue.
  • Le guide asynchrone d’A2A indique qu’après avoir vérifié l’authenticité d’une notification, un client appelle généralement GetTask avec l’ID de la notification pour obtenir l’état complet et actuel. Considérez la charge utile comme un déclencheur et réinterrogez la tâche avant d’agir sur quoi que ce soit d’important.

Pourquoi localhost casse les push notifications A2A

Trois échecs distincts se cachent derrière « ça marche sur ma machine ».

La carte publie une adresse que personne d’autre ne peut atteindre. De nombreux cadres construisent la carte à partir de l’adresse de liaison, donc la carte affiche http://localhost:8000/a2a. Un client distant récupère la carte (si elle est atteignable), puis suit supportedInterfaces[0].url vers sa propre interface de loopback. La solution est de définir explicitement l’URL publique de base du serveur afin que la carte reflète le nom d’hôte du tunnel.

Le agent ne peut pas atteindre votre webhook. Si votre webhook est http://localhost:9000/hook, l’agent distant résout cela vers lui-même, et rien n’arrive.

Un serveur bien construit peut refuser d’essayer. La spec indique que les serveurs ne doivent pas poster simplement à n’importe quelle URL fournie par le client, car cela ouvre des attaques SSRF et d’amplification DDoS. Les implémentations réelles répondent à cela de différentes manières :

  • La crate Rust a2a-protocol-server (0.15.0) valide les URLs webhook lors de la création de la config et à nouveau lors de la livraison. Elle rejette les cibles loopback, privées et link-local, ainsi que localhost, .local et .internal. Son échappatoire allow_private_urls() est documentée comme destinée aux tests et comme désactivant la protection SSRF.
  • Une pull request visant le SDK Python officiel (#1164) décrit le problème clairement. L’expéditeur a utilisé push_info.url exactement tel quel, sans vérifications. La PR ajoute une validation à l’envoi concernant le schéma, la résolution DNS et les destinations publiques uniquement, avec une option d’exclusion allow_private_push_urls pour les opérateurs dont les webhooks résident sur des réseaux privés. Une PR chevauchante (#1169) couvre le même terrain, et je ne peux pas confirmer si l’une ou l’autre a été fusionnée. Vérifiez la version du SDK que vous utilisez.

Ainsi, savoir si localhost fonctionne comme webhook dépend du SDK et de la version de votre serveur. Là où cela fonctionne, c’est parce que la garde manque. Désactiver la garde pour que 127.0.0.1 passe les tests est une voie de code que vous n’useriez pas en production. Un tunnel public donne à votre webhook une adresse HTTPS publique réelle et globale qui passe la même validation qu’une endpoint de production.

Le contexte de sécurité : SSRF et webhook

Le webhook est une entrée influençable par définition. Quiconque enregistre une configuration push choisit où votre serveur envoie des requêtes HTTP. Le guide de sécurité A2A (juin 2026) appelle l’URL du webhook sa propre surface d’attaque, avec SSRF si les destinations sortants ne sont pas autorisées et usurpation si le destinataire n’authentifie pas les notifications.

La documentation A2A énumère des mitigations pour les serveurs : autorisation des domaines de confiance (allowlisting), vérification de possession telle que challenge-réponse, et contrôles réseau tels que des pare-feu de sortie. Pour les destinataires, elle indique que le point de terminaison doit vérifier que les notifications proviennent réellement du serveur légitime, en utilisant des signatures, des tokens ou le token enregistré. Elle indique également que les notifications doivent comporter un horodatage afin de rejeter les anciennes, et recommande des IDs uniques pour les événements critiques afin d’attraper les replays. La documentation décrit aussi une procédure optionnelle JWT+JWKS pour la vérification asymétrique.

L’avis Apache Camel montre comment un validateur peut mal tourner :

  • CVE-2026-71569 (Apache Camel, publié le 29 octobre 2026). Le composant camel-a2a WebhookUrlValidator classifiait des hôtes en deux endroits qui n’étaient pas d’accord. Un hôte écrit sous forme d’adresse IP littérale était apparié à des préfixes de chaîne qui incluaient l’intervalle unique-local fc00::/7. Un nom d’hôte résolu et vérifié avec des prédicats JDK (isLoopbackAddress, isSiteLocalAddress, etc.) ne couvrait pas fc00::/7. Un nom résolu en fc00::/7 a donc franchi une garde qui refusait l’identique littéral.
    • Le répartiteur envoyait aussi tout en-tête Authorization configuré à cette adresse. L’attaquant fournit le schéma et les informations d’identification, ce qui n’est pas une fuite des secrets de la victime.
    • Cela concerne la version 4.21.0 jusqu’à 4.22.2. Les correctifs arrivent dans 4.22.2 et 4.23.0, et la ligne 4.21.x est en fin de vie sans correctif. Le composant a été introduit en 4.21.0 et est marqué comme Prévisualisation.
    • Le score est Medium (CVSS 3.1 score 4.8). La requête est aveugle, car la réponse n’est pas relayée au caller. L’exploitation nécessite aussi que le nom se résolve en fc00::/7, un service HTTPS écoutant là-bas, et une poignée TLS réussie pour ce nom.
    • La pré-vérification de chaîne était également erronée dans l’autre sens. Elle correspondait au nom d’hôte brut sans vérifier d’abord s’il s’agissait d’une IP littérale, donc des noms légitimes commençant par fc ou fd, tels que fcm.googleapis.com, ont été refusés.
  • Le SDK Python officiel. La PR #1164 indique deux risques résiduels. Le rebinding DNS entre la validation et le POST reste possible, car la résolution et la connexion résolvent le nom séparément. Un relecteur a également noté que les redirections ne sont pas revalidées, donc le client HTTP doit maintenir follow_redirects=False, ce qui est la valeur par défaut de httpx.

Une checklist d’inscription webhook SSRF-safe

Si vous construisez ou exploitez un serveur A2A, validez par couches :

  1. HTTPS uniquement. Rejetez d’autres schémas et URL portant des identifiants intégrés. Certains garde-fous SDK permettent aussi http en clair. Renforcez cela en production.
  2. Restreindre les ports. Autoriser 443 sauf raison documentée.
  3. Résoudre puis classer chaque adresse. Une mauvaise réponse suffit à faire échouer l’URL entière. La résolution capture aussi les écritures décimales, hexadécimales et octales des hôtes comme 2130706433, que la correspondance de chaînes manquerait. Dépliez les adresses IPv4 imbriquées dans IPv6, NAT64 et 6to4 avant de les classer, et assurez-vous que fc00::/7 et 100.64.0.0/10 soient couverts.
  4. Valider à l’enregistrement et à la livraison. Les configurations peuvent arriver par plusieurs chemins (en ligne dans une requête Send ou via l’opération dédiée), et le DNS peut changer entre les deux instants.
  5. Fermer la fenêtre de rebinding. Là où votre client HTTP le permet, connectez-vous à l’adresse que vous avez validée tout en conservant le nom d’hôte d’origine pour TLS et l’en-tête Host. La crate Rust suit une voie différente pour les cibles https://. Elle ne lie pas l’adresse IP et explique qu’un rebinding vers une adresse privée échoue la négociation TLS parce que l’attaquant ne peut pas présenter un certificat valide pour votre nom d’hôte. Choisissez délibérément une approche.
  6. N’en faites jamais suivre des redirections lors de la livraison des push.
  7. Vérifiez la propriété avec un challenge avant d’envoyer de vrais événements.
  8. N’attachez pas d’identifiants à des destinations non validées. Ajoutez un proxy de sortie ou une politique réseau comme défense en profondeur.
  9. Refuser l’injection d’en-têtes. Refusez les caractères CR ou LF dans les valeurs token et authentication avant de les mettre dans les en-têtes.

Un point de départ Python pour les étapes 1 à 3 suit. Je l’ai exécuté sur Python 3.13. Il rejette les cibles loopback, privées, link-local, CGNAT et unique-local, les hôtes codés en entier, localhost, IPv4-mappés et IPv4-compatibles IPv6, NAT64 et adresses 6to4 enveloppant des IPv4 privés, les ports mauvais et les informations d’identification intégrées. Il accepte les hôtes publics. Les règles is_global de Python ont changé entre les versions, donc retestez sur votre propre version :

import ipaddress
import socket
from urllib.parse import urlsplit

ALLOWED_PORTS = {443}
NAT64 = ipaddress.ip_network("64:ff9b::/96")


def unwrap(ip):
    """Return the IPv4 hidden inside an IPv6 address, if there is one."""
    if isinstance(ip, ipaddress.IPv6Address):
        if ip.ipv4_mapped:                      # ::ffff:a.b.c.d
            return ip.ipv4_mapped
        if ip in NAT64:                         # 64:ff9b::/96
            return ipaddress.IPv4Address(int(ip) 0xFFFFFFFF)
        if ip.sixtofour:                        # 2002::/16
            return ip.sixtofour
        if int(ip)  32 == 0 and int(ip)  1:  # deprecated ::a.b.c.d
            return ipaddress.IPv4Address(int(ip) FFFFFFFF)
    return ip


def check_webhook_url(url: str) -> list[str]:
    parts = urlsplit(url)
    if parts.scheme != "https" or not parts.hostname:
        raise ValueError("webhook must be an https URL with a host")
    if parts.username or parts.password:
        raise ValueError("credentials in the URL are not allowed")
    try:
        port = parts.port or 443
    except ValueError:
        raise ValueError("invalid port")
    if port not in ALLOWED_PORTS:
        raise ValueError("port not allowed")

    public_ips = []
    for *_, sockaddr in socket.getaddrinfo(parts.hostname, port, type=socket.SOCK_STREAM):
        ip = ipaddress.ip_address(sockaddr[0].split("%")[0])
        # is_global rejects private, loopback, link-local, unique-local and CGNAT.
        if not unwrap(ip).is_global:
            raise ValueError(f"{ip} is not a public address")
        public_ips.append(str(ip))
    return public_ips  # connect to one of these, not to a fresh DNS lookup

Sur le côté récepteur, comparez le token en temps constant, acceptez les deux orthographes d’en-tête, répondez rapidement et récupérez l’état séparément. J’ai testé ce gestionnaire FastAPI. Il renvoie 401 pour un token manquant ou incorrect et 200 pour l’un des noms d’en-tête :

import hmac
import os

from fastapi import FastAPI, Header, HTTPException, Request

app = FastAPI()
EXPECTED = os.environ["A2A_WEBHOOK_TOKEN"]


@app.post("/webhooks/a2a")
async def a2a_webhook(
    request: Request,
    x_a2a_notification_token: str = Header(default=""),
    a2a_notification_token: str = Header(default=""),
):
    token = x_a2a_notification_token or a2a_notification_token
    if not hmac.compare_digest(token.encode(), EXPECTED.encode()):
        raise HTTPException(status_code=401)
    event = await request.json()  # accepts application/json or application/a2a+json
    # enqueue event; re-fetch the task with GetTask before acting on it
    return {"received": True}

Si votre serveur envoie aussi un en-tête Authorization issu de authentication, vérifiez-le aussi. Le token seul prouve seulement que l’expéditeur connaissait un secret par tâche.

Tester les notifications push A2A sur localhost avec un tunnel

Un tunnel donne à votre port local un nom d’hôte HTTPS public, vous permettant d’exécuter le flux réel. N’importe quel outil de tunnels fonctionne. Les propriétés importantes sont HTTPS, un nom d’hôte stable, et le support des requêtes POST simples et non interactives.

Étape 1 : Réserver un nom d’hôte stable. Des URL aléatoires de session cassent les tests A2A. Les clients mettent en cache les cartes, et la spec indique que les serveurs doivent envoyer les en-têtes Cache-Control et ETag, et que les clients doivent les respecter. Les configurations push enregistrées contiennent l’URL de votre webhook. Lorsque le nom d’hôte change, elles ne pointent sur rien.

Un tunnel jetable est suffisant pour un premier test rapide. cloudflared tunnel --url http://localhost:8000 crée une URL aléatoire trycloudflare.com sans compte. Cloudflare documente plusieurs limites pour ces Quick Tunnels :

  • Il n’y a aucune garantie de disponibilité.
  • Chaque tunnel prend en charge jusqu’à 200 requêtes en vol, et les requêtes supplémentaires renvoient un 429.
  • Le nom d’hôte change à chaque fois.
  • Server-Sent Events ne sont pas pris en charge. Les opérations de streaming A2A (SendStreamingMessage, SubscribeToTask) utilisent SSE, donc un Quick Tunnel peut transporter les webhooks push et les appels plain request/response mais pas les tests de streaming.
  • Quick Tunnels ne fonctionnent pas si un config.yaml existe dans ~/.cloudflared.
  • Quick Tunnels disposent désormais d’un drapeau optionnel --allowed-mail qui restreint l’URL derrière un PIN à usage unique par e-mail. Cloudflare indique qu’il nécessite une session de navigateur interactive et ne prend pas en charge les clients non interactifs. Un serveur agent POSTant vers votre webhook ne peut pas accomplir cela, donc désactivez-le pour les callbacks A2A.

Pour tout test itératif, utilisez un tunnel nommé ou le sous-domaine réservé par un autre fournisseur.

Étape 2 : Faites dire à la carte l’adresse publique. Configurez l’URL publique de base de votre agent à partir d’une variable d’environnement et reconstruisez la carte à partir de celle-ci. Puis vérifiez-la depuis l’extérieur de votre réseau :

curl -s https://a2a-agent-dev.example.com/.well-known/agent-card.json | jq '.supportedInterfaces'

Vous devriez voir le nom d’hôte du tunnel, pas localhost. Si un pair utilise une carte au format pré-1.0, a2aops compat <base-url> imprime une checklist de migration v0.x vers v1.0. C’est un petit outil bêta tiers, traitez donc sa sortie comme une indication.

Étape 3 : Tunneliser le récepteur webhook. Exécutez le récepteur ci-dessus sur son propre port avec son propre nom d’hôte public, ou sur un chemin acheminé.

Étape 4 : Enregistrer et déclencher. Créez la configuration push pour une tâche longue, puis lancez la tâche. Observez l’inspecteur de requêtes du tunnel (la plupart des outils en proposent un) pour les en-têtes exacts et le corps que le serveur envoie.

Étape 5 : Exécuter les tests négatifs. Ils comptent autant que le chemin heureux :

  • Enregistrez https://127.0.0.1/hook et https://localhost/hook. Un serveur durci devrait rejeter les deux.
  • Enregistrez un nom d’hôte que vous contrôlez qui résout une adresse privée, et un hôte boucle décimale tel que https://2130706433/hook. Les deux devraient être rejetés.
  • Envoyez une requête avec un token wrong ou manquant. Votre récepteur devrait renvoyer 401.
  • Répétez une notification capturée ancienne. Votre récepteur devrait la rejeter comme périmée ou en double.
  • Retournez un 5xx depuis le récepteur une fois et confirmez que le serveur réessaie. Puis retournez un 401 et voyez s’il s’arrête. Le comportement de réessai varie, et la crate Rust ne réessaie que les 408, 429 et 5xx.

Pièges courants

  • Dérive de la carte et du tunnel. Vous redémarrez le tunnel, le nom d’hôte change, et la carte (et chaque configuration push enregistrée) affiche toujours l’ancien.
  • Cartes pré-1.0. Un pair peut servir /.well-known/agent.json ou un schéma plus ancien. La v1.0 a introduit des changements importants, y compris une structure Part unifiée, des méthodes renommées et de nouveaux champs d’interface de carte.
  • Tunnel public, agent public. Un tunnel expose votre serveur de développement à Internet. Ne mettez pas de secrets dans la carte, ne mettez pas de données de production derrière un agent de développement, et fermez le tunnel lorsque vous avez fini.
  • Gestionnaires de webhooks lents. Accusez réception rapidement et traitez de façon asynchrone. La crate Rust par défaut donne un délai d’attente de 10 secondes pour les requêtes, et la spec recommande 10 à 30 secondes. Un gestionnaire lent invite les réessais et les livraisons en double.
  • Jetons partagés. Utilisez un jeton unique et à usage unique par configuration push.

FAQ

Une carte Agent A2A doit-elle être à une URL publique ? Oui, pour la découverte par des clients distants. Elle est servie à /.well-known/agent-card.json sur le domaine de l’agent, et les URL d’interface intérieures doivent être atteignables par quiconque vous appellera. Les cartes peuvent également être récupérées à partir d’un registre ou configurées directement.

Pourquoi mon serveur A2A rejette-t-il mon webhook localhost ? C’est presque certainement une protection SSRF. Les serveurs durcis bloquent par défaut les destinations privées, loopback et link-local. Utilisez un tunnel HTTPS public plutôt que de désactiver la garde.

Quel en-tête porte le jeton de notification push A2A ? L’exemple du guide utilise X-A2A-Notification-Token, alimenté par le token que vous avez fourni lors de l’enregistrement. Le texte normatif ne nomme pas d’en-tête, et certaines implémentations envoient aussi A2A-Notification-Token, donc acceptez les deux.

Puis-je tester le streaming A2A via un Cloudflare Quick Tunnel ? Non. Cloudflare indique que les Quick Tunnels ne prennent pas en charge les Server-Sent Events, utilisées par le streaming A2A. Les webhooks push fonctionnent correctement via l’un d’eux.

A2A est-il assez stable pour construire dessus ? v1.0 est la spécification stable actuelle, gouvernée par la Linux Foundation et hébergée par l’AAIF depuis août 2026. Les SDK et les intégrations sont encore en maturation, alors testez le support des versions, les capacités optionnelles et l’authentification de bout en bout avec chaque pair.

Points clés

  • Un test local A2A peut nécessiter deux adresses publiques : l’URL d’interface de la carte pour le serveur, et l’URL du webhook pour le client.
  • Le fait qu’un webhook localhost fonctionne dépend du SDK de votre serveur. Les serveurs durcis refusent intentionnellement les cibles privées, et un tunnel teste le chemin réaliste où désactiver la protection ne fonctionnera pas.
  • L’enregistrement du webhook est une surface SSRF. Résolvez et classez chaque adresse avec un seul classificateur partagé, validez à l’enregistrement et à la livraison, décidez comment vous allez fermer la fenêtre de rebinding et refusez les redirections.
  • Utilisez un nom d’hôte de tunnel stable, authentifiez chaque notification, traitez la charge utile comme un déclencheur pour appeler GetTask, et effectuez les tests négatifs.

Sources

Continue from this article into the most relevant product guides and workflows.

Related Topics

#A2A protocol#agent2agent protocol#A2A push notifications#A2A webhook#A2A agent card#agent card public URL#agent card well-known path#.well-known/agent.json#A2A localhost testing#test A2A locally#A2A v1.0#A2A Linux Foundation#Agentic AI Foundation#agent to agent communication#agent-to-agent callbacks#AI agent interoperability#multi-agent systems#AI agent webhooks#webhook testing localhost#webhook SSRF#SSRF prevention#SSRF-safe webhooks#webhook registration security#A2A security#AI agent security#webhook security best practices#localhost tunneling#expose localhost to internet#localhost public URL#stable public URL for localhost#static tunnel URL#persistent tunnel URL#ngrok alternative#Cloudflare Tunnel#localtunnel#tunneling tools comparison#local development tunnel#webhook tunnel#HTTPS tunnel localhost#reverse tunnel#developer infrastructure#cloud-native development#DevOps tools#agentic AI development#AI agent development#build AI agents#A2A server setup#A2A client example#A2A SDK#A2A task streaming#A2A server-sent events#long-running agent tasks#async agent notifications#webhook callback URL#webhook signature verification#allowlist webhook URLs#private IP blocking#MCP vs A2A#agent discovery#InstaTunnel

Keep building with InstaTunnel

Read the docs for implementation details or compare plans before you ship.

Share this article

More InstaTunnel Insights

Discover more tutorials, tips, and updates to help you build better with localhost tunneling.

Browse All Articles