Servicio connector._register_local_token · Depósito del token en el SaaS
Resumen
Método connector._register_local_token() en terminal/agent/core/connector.py (+42 líneas). Ejecutado en cada conexión WebSocket exitosa con el SaaS, deposita el token local del Agent en el servidor para que el frontend pueda descargarlo e inyectarlo en las llamadas locales.
Best-effort: reintenta en cada reconexión; fallos silenciosos, nunca tumban la conexión principal.
Firmas y datos
async def _register_local_token(self):
"""Deposita el token de auth de la API local en el SaaS (Fase 3).
Best-effort: el SaaS lo custodia cifrado y solo lo entrega a la sesión
del tenant dueño (GET /api/agent/local-token). Si falla, el frontend
sigue sin token y el middleware local lo rechazará — se reintenta en
cada reconexión.
"""
import aiohttp
if getattr(sys, "frozen", False):
from core.local_token import get_or_create_local_token
else:
from .local_token import get_or_create_local_token
try:
url = f"{self.auth.saas_url}/api/agent/register-local-token"
headers = {"Authorization": f"Bearer {self.auth.access_token}"}
async with (
aiohttp.ClientSession() as session,
session.post(
url,
json={"local_token": get_or_create_local_token()},
headers=headers,
timeout=aiohttp.ClientTimeout(total=15),
) as resp,
):
if resp.status == 200:
logger.info("Local token registered with SaaS")
else:
logger.warning(f"Local token registration failed: HTTP {resp.status}")
except Exception as e: # noqa: BLE001 — nunca tumbar la conexión por esto
logger.warning(f"Local token registration error: {e}")
Ubicación en el flujo de conexión
En _connect_websocket() (conexión principal WS con el SaaS):
async def _connect_websocket(self):
# ... login, negociación, etc.
if on_connect:
await on_connect()
await self._send_agent_status()
await self._register_local_token() # ← AQUÍ, después de status
# ... receive_loop
Timing: Tras confirmar que la conexión WS está viva y autenticada.
HTTP POST /api/agent/register-local-token
URL
POST https://<saas_url>/api/agent/register-local-token
Ej: https://crearack.com/api/agent/register-local-token
Headers
Authorization: Bearer <access_token>— Credencial del Agent en el SaaS (igual que WS auth).
Request body (JSON)
{
"local_token": "<TOKEN_OPACO_EJEMPLO_43-44_CHARS>"
}
Campo local_token: token opaco 43-44 caracteres de get_or_create_local_token().
Response esperada (HTTP 200)
{}
o vacío (la semántica es “depositado OK”).
Fallos tolerables
| HTTP | Qué pasa | Acción |
|---|---|---|
| 200 | Token depositado | Log info, continua |
| 401/403 | Credencial del Agent inválida o SaaS offline | Log warning, reintenta en próxima conexión |
| 500 | SaaS error interno | Log warning, reintenta en próxima conexión |
| Timeout (>15s) | SaaS no responde rápido | Log warning, no bloquea WS |
| Exception (red abajo, DNS, etc.) | Error de conectividad | Log warning, caught, nunca propaga |
Nunca levanta excepción: el except Exception final es genérico (noqa: BLE001) porque esta operación NO debe impedir la apertura de la conexión WS principal.
Semántica best-effort
El patrón es fire-and-forget asincrónico con reintentos automáticos:
- Primera conexión WS: intenta depositar token.
- Si SaaS no responde rápido (timeout 15s): continúa sin esperar.
- Reconexión WS: intenta de nuevo.
- Eventualmente converge (el frontend solo obtiene token cuando se deposita).
Ventaja: si el SaaS está lento/offline, el Agent sigue funcionando (compat); el frontend simplemente no recibe token y los 401 del gate local lo guían a re-autenticar.
Integración con Fase 2 (frontend)
El frontend (navegador, Fase 2 ya en PROD) hace:
// En el SaaS (Fase 2)
GET /api/agent/local-token
→ SaaS busca el token depositado por este Agent
→ Comprueba que la sesión es del tenant dueño
→ Retorna {"local_token": "..."}
// En el navegador
postMessage({
type: 'SET_AUTH_TOKEN',
token: local_token // ← Recibido del SaaS
}, '*'); // → a terminal.html (iframe)
De ahí en adelante: terminal.html injeta el token en Bearer en todas las llamadas HTTP al Agent local.
Monitoreo / observabilidad
- Log info (éxito):
"Local token registered with SaaS"— ocurre una sola vez por conexión WS exitosa. - Log warning (fallo temporal):
"Local token registration failed: HTTP <code>"o"Local token registration error: <exc>"— reintentable.
En producción, contar warnings de local_token_registration_failed ayuda a detectar problemas de conectividad SaaS ↔ Agent.
Compatibilidad
| Escenario | Qué pasa |
|---|---|
| SaaS Fase 1 PROD, Agent 2.1.0 | Token depositado OK; SaaS lo custodia. |
| SaaS Fase 1 PROD, Agent 2.0.24 (viejo) | El endpoint aún no existe; POST 404 → log warning, ignored. |
| Agent vinculado a SaaS offline | Timeout/error → log warning, reintenta en próxima conexión. |
| Agent pre-activación | auth.saas_url es None → _register_local_token() nunca se llama (compat). |
Seguridad
- Token no se expone en logs: se deposita en JSON, pero no se loguea (podría aparecer en
resp.status/resp.textsi hubiera debug; se evita). - Credencial del Agent protegida: usa
self.auth.access_token(igual que WS auth), que ya es segura. - Timeout corto: 15s evita bloqueos prolongados en redes lentas.
- No reintentos de explosión: el único reintento es en la próxima conexión WS (no hay loop de reintentos acelerados).
Véase también
- [[feature—agent—fase-3-auth-local]]
- [[entity—agent—service—local-token]]
- [[entity—agent—service—terminal-ws-auth]]
- [[entity—agent—service—websocket-connector]]
- [[concept—saas—agent-registration]]