eb8dbf66a1
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
95 lines
4.7 KiB
Markdown
95 lines
4.7 KiB
Markdown
---
|
|
name: hoppscotch_login
|
|
kind: function
|
|
lang: py
|
|
domain: infra
|
|
version: "1.0.0"
|
|
purity: impure
|
|
signature: "def hoppscotch_login(email: str, *, backend_url: str = \"http://localhost:3170\", mailpit_url: str = \"http://localhost:8025\", timeout_s: float = 15.0) -> dict"
|
|
description: "Login headless contra un Hoppscotch self-hosted via magic link, leyendo el correo de verificacion desde una instancia Mailpit de pruebas. Reproduce el flujo sin navegador: POST /v1/auth/signin (deviceIdentifier) -> lee el correo 'Sign in' del email en Mailpit -> extrae el token (?token=...) del cuerpo -> POST /v1/auth/verify (Set-Cookie access_token + refresh_token). Devuelve los JWT de sesion que las mutations GraphQL protegidas esperan en la cookie access_token."
|
|
tags: [hoppscotch, flow-replay, http, infra, auth]
|
|
uses_functions: []
|
|
uses_types: []
|
|
returns: []
|
|
returns_optional: false
|
|
error_type: "error_go_core"
|
|
imports: [re, requests]
|
|
params:
|
|
- name: email
|
|
desc: "correo del usuario que inicia sesion. Debe poder recibir el correo de verificacion en la instancia Mailpit indicada (en el self-host de pruebas, admin@example.com)."
|
|
- name: backend_url
|
|
desc: "base del backend Hoppscotch sin barra final. Los endpoints REST de auth cuelgan de {backend_url}/v1/auth/signin y /v1/auth/verify. Default http://localhost:3170."
|
|
- name: mailpit_url
|
|
desc: "base de la API de Mailpit donde aterriza el correo de verificacion, sin barra final. Default http://localhost:8025."
|
|
- name: timeout_s
|
|
desc: "timeout por request HTTP en segundos. Default 15.0."
|
|
output: "dict. En exito: {status: 'ok', access_token: str, refresh_token: str, email: str}. En error (signin != 201, no llega correo 'Sign in', token no encontrado en el correo, verify != 200, o fallo de transporte): {status: 'error', error: str}. Nunca lanza por errores de red esperables."
|
|
tested: true
|
|
tests:
|
|
- "test_golden_login_devuelve_tokens"
|
|
- "test_verify_recibe_token_extraido_y_device_identifier"
|
|
- "test_error_signin_no_201"
|
|
- "test_error_correo_no_encontrado"
|
|
- "test_error_token_no_en_correo"
|
|
test_file_path: "python/functions/infra/hoppscotch_login_test.py"
|
|
file_path: "python/functions/infra/hoppscotch_login.py"
|
|
---
|
|
|
|
## Ejemplo
|
|
|
|
```python
|
|
import sys
|
|
sys.path.insert(0, "python/functions")
|
|
from infra.hoppscotch_login import hoppscotch_login
|
|
from infra.hoppscotch_create_request import hoppscotch_create_request
|
|
|
|
# 1) Obtener un JWT de sesion via magic link (headless, lee el correo de Mailpit).
|
|
login = hoppscotch_login("admin@example.com")
|
|
assert login["status"] == "ok", login["error"]
|
|
token = login["access_token"]
|
|
|
|
# 2) Usar el token para crear una request en una team collection.
|
|
# El self-host de referencia exige team_id dentro del input.
|
|
created = hoppscotch_create_request(
|
|
collection_id="cmq8lt8ta000t0xls4ddy6sdz",
|
|
method="GET",
|
|
url="https://api.example.com/ping",
|
|
title="Ping",
|
|
team_id="cmq8kn0v500030xls1nvminjy",
|
|
access_token=token,
|
|
)
|
|
print(created) # {"status": "ok", "id": "...", "title": "Ping"}
|
|
```
|
|
|
|
## Cuando usarla
|
|
|
|
Cuando necesites un JWT de sesion de un Hoppscotch self-hosted para operar su API
|
|
GraphQL protegida (crear/editar/borrar requests, gestionar collections) sin abrir
|
|
el navegador. Es el primer paso de cualquier flujo CRUD del grupo `hoppscotch`:
|
|
llama esto, captura `access_token`, y paselo a `hoppscotch_create_request` /
|
|
`hoppscotch_update_request` / `hoppscotch_delete_request` / `hoppscotch_list_requests`.
|
|
Requiere que el backend mande el correo de verificacion a una instancia Mailpit
|
|
accesible (entorno de pruebas).
|
|
|
|
## Gotchas
|
|
|
|
- **El access_token va como cookie, no como header Authorization.** Las mutations
|
|
GraphQL leen el JWT de la cookie `access_token`. Cada funcion del grupo lo manda
|
|
con `cookies={"access_token": ...}`.
|
|
- **El token expira (~24h).** Cuando una llamada GraphQL devuelva un error de auth,
|
|
re-loguea con `hoppscotch_login` para obtener un access_token fresco.
|
|
- **Depende de Mailpit.** El flujo lee el correo de verificacion de una instancia
|
|
Mailpit de pruebas. No funciona contra un backend que mande el correo a un buzon
|
|
real al que esta funcion no pueda consultar por API.
|
|
- **Secreto — nunca logear el token en crudo.** `access_token`/`refresh_token` son
|
|
credenciales de sesion. No los imprimas ni los persistas en claro; trataelos como
|
|
un secreto (vault/pass) si los guardas entre ejecuciones.
|
|
- **Coincidencia del correo por subject + destinatario.** Se elige el mensaje mas
|
|
reciente cuyo destinatario sea `email` y cuyo subject contenga "Sign in". Si hay
|
|
varios magic links pendientes para el mismo email, se usa el ultimo de la lista.
|
|
|
|
## Capability growth log
|
|
|
|
v1.0.0 — version inicial. Flujo magic link headless validado contra el self-host
|
|
vivo (login + CRUD completo) el 10/06/2026.
|