Volver a la wiki

Zoho OAuth Helper — Service Account · functions/_lib/zoho.ts

Zoho OAuth Helper — Service Account · functions/_lib/zoho.ts

Módulo de utilidades TypeScript (Cloudflare Pages Functions) que implementa el ciclo de vida completo del token OAuth Zoho bajo el modelo Service Account: un único refresh_token almacenado en D1 da acceso a Calendar + Tasks de todo el workspace.


Responsabilidades

Función exportadaDescripción
getStoredToken(env)Lee la fila singleton id=1 de zoho_oauth_tokens. Devuelve null si no hay autorización.
getValidAccessToken(env)Devuelve {token, dc} listo para usar. Si el access_token ha expirado, llama a refreshAccessToken de forma transparente.
zohoFetch(env, url, init?)Wrapper sobre fetch que inyecta Authorization: Zoho-oauthtoken <token> automáticamente.
buildAuthorizeUrl(env, state, redirectUri, dc?)Construye la URL del consent screen de Zoho con los scopes de Fase A.
exchangeCodeForTokens(env, code, redirectUri, dc)Intercambia el code del callback por refresh_token + access_token.
upsertToken(env, ...)Persiste o actualiza el token en D1 (INSERT OR REPLACE sobre id=1).
deleteToken(env)Elimina el token (revocación).

Interfaces principales

interface ZohoEnv {
  DB: D1Database;
  ZOHO_CLIENT_ID: string;
  ZOHO_CLIENT_SECRET: string;
}

interface ZohoTokenRow {
  id: number;
  refresh_token: string;
  access_token: string | null;
  access_token_expires_at: string | null;
  dc: string;          // 'eu' | 'com' | 'in'
  granted_by: string;  // email CF Access del autorizador
  granted_at: string;
  updated_at: string;
}

Scopes configurados (ZOHO_SCOPES)

ZohoCalendar.event.READ
ZohoCalendar.calendar.READ
ZohoMail.tasks.READ
ZohoMail.accounts.READ

Lógica de refresco de token

getValidAccessToken evalúa si access_token_expires_at > now. Si no, llama a refreshAccessToken (función privada) que:

  1. POST a https://accounts.zoho.{dc}/oauth/v2/token con grant_type=refresh_token.
  2. Actualiza access_token y access_token_expires_at en D1 (con margen de 60 s).
  3. Devuelve el token fresco.

El margen de 60 segundos previene race conditions en tokens próximos a expirar.


Soporte multi-región (dc)

Zoho opera en tres regiones: eu (default · Esferic Labs SL), com, in. Las funciones de host derivan la URL base:

accountsHost(dc)   → accounts.zoho.{dc}
calendarApiHost(dc) → calendar.zoho.{dc}
mailApiHost(dc)    → mail.zoho.{dc}

La región se detecta en el callback OAuth mediante el query param accounts-server (ej. accounts.zoho.eu) y se persiste en zoho_oauth_tokens.dc.


Tablas D1 asociadas (migración 0026)

zoho_oauth_tokens (singleton)

ColumnaTipoNotas
idINTEGER PKConstraint CHECK (id = 1) — garantiza singleton
refresh_tokenTEXT NOT NULLToken de larga duración
access_tokenTEXTCacheado, nullable
access_token_expires_atTEXTISO 8601
dcTEXTRegión Zoho (eu default)
granted_byTEXTEmail del autorizador (CF Access)
granted_atTEXTTimestamp de la autorización
updated_atTEXTÚltimo refresh

zoho_oauth_state (anti-CSRF)

ColumnaTipoNotas
stateTEXT PKUUID aleatorio
created_byTEXTEmail del iniciador
created_atTEXTTTL implícito 10 min (limpiado por callback)

Índice: idx_zoho_oauth_state_created sobre created_at para limpieza eficiente.


Variables de entorno requeridas

VariableDónde configurar
ZOHO_CLIENT_IDCF Pages secrets
ZOHO_CLIENT_SECRETCF Pages secrets
DBBinding D1 en wrangler.toml / CF Pages settings

Véase también

Subir