Zaroz
Usar la API

Inicio de sesión, sesiones y seguridad de la cuenta

La mayoría de los scripts deberían usar un token de API, no un inicio de sesión. Aun así necesitas una sesión (la que usa la consola) para las pocas cosas que un token no puede hacer: crear tu primer token personal, revocar uno o cambiar la seguridad de la cuenta. Esta página muestra el lado de la sesión. Los ejemplos usan el ayudante de Usar la API de Zaroz; el inicio de sesión en sí no lleva autenticación.

Inicia sesión con correo y contraseña

Una contraseña correcta no abre una sesión por sí sola: consigue un código de un solo uso enviado al correo. Envía el código para abrir la sesión.

curl

TerminalCode
curl -sS -X POST "$ZAROZ_API/auth/login" -H "Content-Type: application/json" \ -d '{"email": "[email protected]", "password": "…"}' # {"challenge_id": "…", "status": "…"} el código ya está en tu bandeja curl -sS -X POST "$ZAROZ_API/auth/login/verify" -H "Content-Type: application/json" \ -d '{"challenge_id": "…", "code": "123456"}' # {"token": "<token de acceso>", "refresh_token": "…", "session_id": "…", "user": {…}}

TypeScript

TypeScriptCode
const API = process.env.ZAROZ_API ?? "https://kernel.zaroz.cloud/api/v2"; const post = async (path: string, body: unknown) => (await fetch(`${API}${path}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), })).json(); const { challenge_id } = await post("/auth/login", { email: "[email protected]", password: process.env.PASSWORD }); const code = await promptForCodeFromEmail(); // lo escribes tú const session = await post("/auth/login/verify", { challenge_id, code }); console.log(session.token, session.refresh_token, session.session_id);

Python

Code
import os, requests API = os.environ.get("ZAROZ_API", "https://kernel.zaroz.cloud/api/v2") r = requests.post(f"{API}/auth/login", json={"email": "[email protected]", "password": os.environ["PASSWORD"]}, timeout=20) challenge_id = r.json()["challenge_id"] code = input("Código de tu correo: ") session = requests.post(f"{API}/auth/login/verify", json={"challenge_id": challenge_id, "code": code}, timeout=20).json() print(session["token"], session["refresh_token"], session["session_id"])

El código caduca pronto y el desafío se quema tras unos pocos intentos fallidos (empieza de nuevo con /auth/login). Usa token como token bearer. Las cuentas que inician sesión con un proveedor (la lista es GET /auth/oauth/providers) usan el flujo del navegador; el registro con contraseña es POST /auth/password/signup y después POST /auth/password/verify, y POST /auth/password/forgot con POST /auth/password/reset recupera una contraseña. Estas responden igual tenga o no cuenta esa dirección, así que no sirven para averiguar quién está registrado.

Mantén la sesión viva

El token de acceso dura poco. Cambia el token de refresco por un par nuevo y usa el nuevo token de refresco la próxima vez: rota.

curl

TerminalCode
curl -sS -X POST "$ZAROZ_API/auth/refresh" -H "Content-Type: application/json" -d '{"refresh_token": "…"}' # {"token": "…", "refresh_token": "<el NUEVO>", "session_id": "…"} curl -sS "$ZAROZ_API/auth/session" -H "$AUTH" # 401 cuando ya no es válida curl -sS -X POST "$ZAROZ_API/auth/logout" -H "$AUTH" -H "Content-Type: application/json" -d '{"refresh_token": "…"}' # 204

TypeScript

TypeScriptCode
const next = await post("/auth/refresh", { refresh_token: session.refresh_token }); session.token = next.token; session.refresh_token = next.refresh_token; // guarda el rotado; el anterior está gastado

Python

Code
nxt = requests.post(f"{API}/auth/refresh", json={"refresh_token": session["refresh_token"]}, timeout=20).json() session["token"], session["refresh_token"] = nxt["token"], nxt["refresh_token"] # el anterior está gastado

Guarda siempre el token de refresco rotado y nunca reutilices uno gastado.

Tus sesiones

TerminalCode
curl -sS "$ZAROZ_API/me/sessions" -H "$AUTH" curl -sS -X DELETE "$ZAROZ_API/me/sessions/$SESSION" -H "$AUTH" # 204; termina todos los pares de tokens de esa sesión
TypeScriptCode
const sessions = await call("GET", "/me/sessions"); await call("DELETE", `/me/sessions/${sessions.body.data[0].id}`);
Code
_, sessions = call("GET", "/me/sessions") call("DELETE", f"/me/sessions/{sessions['data'][0]['id']}")

id es la familia de la sesión, estable en cada rotación (es el session_id devuelto al iniciar sesión). Revocar es inmediato y nunca revela si un id existe: el id de otra persona es una operación sin efecto. Si pierdes un portátil, revoca su sesión y después los tokens de API que pudo crear.

Contraseña y perfil

curl

TerminalCode
curl -sS -X POST "$ZAROZ_API/auth/password/change" -H "$AUTH" -H "Content-Type: application/json" \ -d '{"current_password": "…", "new_password": "…", "current_session_id": "<esta sesión>"}' curl -sS "$ZAROZ_API/me" -H "$AUTH" curl -sS -X PATCH "$ZAROZ_API/me" -H "$AUTH" -H "Content-Type: application/json" -d '{"name": "Sam", "language": "es"}'
TypeScriptCode
await call("POST", "/auth/password/change", { current_password: OLD, new_password: NEW, current_session_id: session.session_id, // omítelo para cerrar sesión en todas partes }); await call("PATCH", "/me", { name: "Sam", language: "es" });
Code
call("POST", "/auth/password/change", {"current_password": OLD, "new_password": NEW, "current_session_id": session["session_id"]}) call("PATCH", "/me", {"name": "Sam", "language": "es"})

Cambiar la contraseña cierra todas las demás sesiones; pasa current_session_id para conservar esta, u omítelo para cerrar sesión en todas partes. Todos los campos de PATCH /me son opcionales (name, language, discord_notifications_enabled, billing_country_code); el país de facturación se rechaza cuando el alta ya está completa y hay un país guardado, porque decide el tratamiento fiscal.

Sesiones elevadas (sudo)

Algunas acciones de la cuenta (las del personal, por ejemplo, y las sensibles que hayas decidido proteger) necesitan una sesión elevada: una ventana nueva en la que demostraste un segundo factor. Pregunta si necesitas una y después eleva con tu PIN.

TerminalCode
curl -sS "$ZAROZ_API/auth/sudo/status" -H "$AUTH" # {"is_elevated": false, "elevated_until": null, "available_methods": [...], "enrolled_methods": [...]} curl -sS -X POST "$ZAROZ_API/auth/sudo/elevate" -H "$AUTH" -H "Content-Type: application/json" -d '{"pin": "…"}' # {"token": "<nuevo token de acceso>", "elevated_until": "…"} curl -sS -X POST "$ZAROZ_API/auth/sudo/exit" -H "$AUTH" # abandónala antes; devuelve un token nuevo sin elevar
TypeScriptCode
const status = await call("GET", "/auth/sudo/status"); if (!status.body.is_elevated) { const el = await call("POST", "/auth/sudo/elevate", { pin: process.env.SUDO_PIN }); // usa el.body.token a partir de ahora }
Code
_, status = call("GET", "/auth/sudo/status") if not status["is_elevated"]: _, el = call("POST", "/auth/sudo/elevate", {"pin": os.environ["SUDO_PIN"]}) # usa el["token"] a partir de ahora

Elevar devuelve un token de acceso nuevo con la ventana; el que presentaste sigue siendo válido pero sin elevar. Un PIN incorrecto y una cuenta sin PIN se responden igual (cinco intentos cada quince minutos). Los métodos se configuran con las rutas /auth/sudo/setup, /auth/sudo/totp/* y /auth/sudo/webauthn/*; añadir un segundo método requiere una sesión ya elevada. Un trabajo automatizado nunca debería tener una sesión elevada: usa un token de API con alcance estrecho.

Last modified on