Prueba LUMA gratis 14 días, sin tarjeta.Empieza ahora

Crea una app OAuth

Crea aplicaciones que se integren con LUMA mediante OAuth 2.0.

Crea aplicaciones que permitan a los usuarios conectar sus cuentas de LUMA. Las apps OAuth pueden acceder a datos financieros en nombre de los usuarios, lo que permite integraciones, automatizaciones y herramientas personalizadas.

#Qué puedes construir

Con OAuth, puedes construir:

  • Extensiones de navegador que muestran datos de LUMA
  • Apps móviles con integración con LUMA
  • Herramientas de automatización que sincronizan datos entre servicios
  • Paneles personalizados para flujos de trabajo específicos
  • Herramientas para desarrolladores, como extensiones de IDE
  • Apps públicas listadas en el directorio de apps de LUMA

#Cómo funciona OAuth

OAuth 2.0 permite que tu app solicite acceso a los datos de LUMA de un usuario sin gestionar su contraseña:

  1. Tu app redirige a los usuarios a la página de autorización de LUMA
  2. Los usuarios inician sesión y aprueban los permisos solicitados
  3. LUMA redirige de vuelta con un código de autorización
  4. Tu app intercambia el código por tokens de acceso
  5. Usa los tokens de acceso para llamar a la API de LUMA

#Primeros pasos

#Paso 1: Crea una aplicación OAuth

  1. Ve a Ajustes → Desarrollador
  2. Haz clic en Crear app OAuth
  3. Rellena los datos de tu aplicación:
    • Nombre: el nombre de tu app (se muestra a los usuarios)
    • Descripción: una breve descripción
    • Sitio web: la página principal de tu app
    • URIs de redirección: URLs a las que redirigir tras la autorización
  4. Selecciona los scopes que necesita tu app
  5. Haz clic en Crear

Recibirás:

  • Client ID: identificador público de tu app
  • Client Secret: mantenlo en secreto (se muestra una sola vez)

#Paso 2: Implementa el flujo de autorización

Redirige a los usuarios para iniciar la autorización:

https://app.midday.ai/oauth/authorize?
  response_type=code&
  client_id=YOUR_CLIENT_ID&
  redirect_uri=YOUR_REDIRECT_URI&
  scope=transactions.read%20invoices.read&
  state=RANDOM_STATE_VALUE

Parámetros:

ParámetroObligatorioDescripción
response_typeDebe ser code
client_idEl client ID de tu aplicación
redirect_uriDebe coincidir con una URI de redirección registrada
scopeLista de scopes separados por espacios
stateRecomendadoCadena aleatoria para prevenir ataques CSRF
code_challengePara clientes públicosCode challenge de PKCE
code_challenge_methodPara clientes públicosDebe ser S256

#Paso 3: Gestiona el callback

Tras autorizar, LUMA redirige a tu redirect_uri:

https://yourapp.com/callback?code=AUTH_CODE&state=YOUR_STATE

Si el usuario deniega el acceso:

https://yourapp.com/callback?error=access_denied&error_description=User%20denied%20access

#Paso 4: Intercambia el código por tokens

Haz una petición POST para intercambiar el código de autorización:

curl -X POST https://api.midday.ai/v1/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "code": "AUTH_CODE",
    "redirect_uri": "YOUR_REDIRECT_URI",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET"
  }'

Respuesta:

{
  "access_token": "mid_at_xxxxx",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "mid_rt_xxxxx",
  "scope": "transactions.read invoices.read"
}

#Paso 5: Realiza peticiones a la API

Instala el SDK de LUMA:

npm install @midday-ai/sdk

Usa el token de acceso con el SDK:

import { Midday } from "@midday-ai/sdk";

const midday = new Midday({
  token: "mid_at_xxxxx", // Token de acceso del flujo de OAuth
});

// Lista las transacciones
const transactions = await midday.transactions.list({
  pageSize: 50,
});

// Obtiene las facturas
const invoices = await midday.invoices.list({
  pageSize: 20,
});

// Obtiene métricas financieras
const revenue = await midday.metrics.revenue({
  from: "2024-01-01",
  to: "2024-12-31",
});

#PKCE para clientes públicos

Para apps móviles, SPAs o cualquier cliente que no pueda almacenar secretos de forma segura, usa PKCE (Proof Key for Code Exchange).

#Genera el code verifier y el code challenge

function base64UrlEncode(buffer: Uint8Array): string {
  return btoa(String.fromCharCode(...buffer))
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "");
}

// Genera un code verifier aleatorio
function generateCodeVerifier(): string {
  const array = new Uint8Array(32);
  crypto.getRandomValues(array);
  return base64UrlEncode(array);
}

// Crea un hash SHA-256 para el code challenge
async function generateCodeChallenge(verifier: string): Promise<string> {
  const encoder = new TextEncoder();
  const data = encoder.encode(verifier);
  const hash = await crypto.subtle.digest("SHA-256", data);
  return base64UrlEncode(new Uint8Array(hash));
}

#Inclúyelo en la petición de autorización

https://app.midday.ai/oauth/authorize?
  response_type=code&
  client_id=YOUR_CLIENT_ID&
  redirect_uri=YOUR_REDIRECT_URI&
  scope=transactions.read&
  code_challenge=CHALLENGE&
  code_challenge_method=S256&
  state=STATE

#Incluye el verifier en el intercambio de tokens

curl -X POST https://api.midday.ai/v1/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "code": "AUTH_CODE",
    "redirect_uri": "YOUR_REDIRECT_URI",
    "client_id": "YOUR_CLIENT_ID",
    "code_verifier": "YOUR_CODE_VERIFIER"
  }'

Nota: los clientes públicos no deben enviar client_secret.

#Renovación de tokens

Los tokens de acceso caducan al cabo de 1 hora. Usa el refresh token para obtener tokens nuevos:

curl -X POST https://api.midday.ai/v1/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "refresh_token",
    "refresh_token": "mid_rt_xxxxx",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET"
  }'

Los refresh tokens son válidos durante 30 días y rotan en cada uso.

#Revocación de tokens

Permite que los usuarios desconecten tu app revocando los tokens:

curl -X POST https://api.midday.ai/v1/oauth/revoke \
  -H "Content-Type: application/json" \
  -d '{
    "token": "mid_at_xxxxx",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET"
  }'

#Ejemplo: implementación en TypeScript

import express from "express";
import crypto from "crypto";
import { Midday } from "@midday-ai/sdk";

const app = express();

const CLIENT_ID = process.env.MIDDAY_CLIENT_ID!;
const CLIENT_SECRET = process.env.MIDDAY_CLIENT_SECRET!;
const REDIRECT_URI = "http://localhost:3000/callback";

// En producción, usa un almacén de sesiones adecuado
const sessions = new Map<string, { state: string; accessToken?: string }>();

// Paso 1: Redirige a la autorización
app.get("/connect", (req, res) => {
  const sessionId = crypto.randomUUID();
  const state = crypto.randomUUID();
  
  sessions.set(sessionId, { state });
  res.cookie("session_id", sessionId);
  
  const authUrl = new URL("https://app.midday.ai/oauth/authorize");
  authUrl.searchParams.set("response_type", "code");
  authUrl.searchParams.set("client_id", CLIENT_ID);
  authUrl.searchParams.set("redirect_uri", REDIRECT_URI);
  authUrl.searchParams.set("scope", "transactions.read invoices.read");
  authUrl.searchParams.set("state", state);
  
  res.redirect(authUrl.toString());
});

// Paso 2: Gestiona el callback e intercambia el código por tokens
app.get("/callback", async (req, res) => {
  const { code, state, error } = req.query;
  const sessionId = req.cookies.session_id;
  const session = sessions.get(sessionId);
  
  if (error) {
    return res.send("Authorization denied");
  }
  
  // Verifica que el state coincide
  if (state !== session?.state) {
    return res.status(400).send("Invalid state");
  }
  
  // Intercambia el código por tokens
  const response = await fetch("https://api.midday.ai/v1/oauth/token", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      grant_type: "authorization_code",
      code,
      redirect_uri: REDIRECT_URI,
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
    }),
  });
  
  const tokens = await response.json();
  session.accessToken = tokens.access_token;
  
  res.send("Connected successfully!");
});

// Paso 3: Usa el SDK con el token de acceso
app.get("/transactions", async (req, res) => {
  const sessionId = req.cookies.session_id;
  const session = sessions.get(sessionId);
  
  if (!session?.accessToken) {
    return res.status(401).send("Not connected");
  }
  
  const midday = new Midday({
    token: session.accessToken,
  });
  
  const result = await midday.transactions.list({
    pageSize: 50,
  });
  
  res.json(result);
});

app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});

#Gestiona tu app

#Edita los ajustes de la aplicación

  1. Ve a Ajustes → Desarrollador
  2. Haz clic en tu aplicación OAuth
  3. Actualiza los ajustes que necesites
  4. Haz clic en Guardar

#Regenera el client secret

Si tu client secret se ve comprometido:

  1. Ve a los ajustes de tu aplicación OAuth
  2. Haz clic en Regenerar secreto
  3. Actualiza tu app con el nuevo secreto de inmediato

El secreto anterior deja de funcionar de inmediato.

#Supervisa el uso

Haz seguimiento del uso de tu aplicación:

  • Número de usuarios autorizados
  • Llamadas a la API por día
  • Tasa de errores

#Buenas prácticas de seguridad

#Almacena los secretos de forma segura

  • Nunca subas client_secret al control de versiones
  • Usa variables de entorno o un gestor de secretos
  • Rota los secretos si es posible que se hayan expuesto

#Valida el parámetro state

Comprueba siempre que el parámetro state coincide con el que enviaste:

if (req.query.state !== storedState) {
  throw new Error("Invalid state parameter");
}

#Usa HTTPS en todas partes

  • Todas las URIs de redirección deben usar HTTPS (salvo localhost para desarrollo)
  • Nunca envíes tokens por conexiones sin cifrar

#Solicita los scopes mínimos

Solicita solo los scopes que tu app realmente necesita. Los usuarios tienen más probabilidades de autorizar apps que piden un acceso limitado.

#Gestiona la caducidad de los tokens

  • Detecta las respuestas 401 y renueva los tokens automáticamente
  • Implementa una lógica adecuada de renovación de tokens
  • Gestiona con elegancia la caducidad del refresh token

#Próximos pasos