Skip to main content
13 jul 2026k6 oauth2 api key concurrencia

Por Performate

OAuth2 y API keys en k6: patrones de refresh de token que sobreviven la concurrencia

OAuth2 y API keys en k6 bajo concurrencia: refresh de token, client credentials, secretos por env—docs de auth HTTP k6 y patrones de carga realistas.

Tokens bearer estáticos en scripts k6 hacen que cada corrida parezca saludable—hasta que OAuth prod produce tormentas de refresh, endpoints token rate-limited y clock skew que generan picos 401 bajo carga. Clientes reales renuevan tokens; tu load test también debería.

OAuth2 y API keys en k6 no es «pegar el JWT de DevTools». Es modelar ciclo de vida token bajo concurrencia: client credentials para service accounts, refresh antes de expiración, y escenarios separados cuando API keys golpean límites RPM. En esta guía verás por qué auth colapsa bajo VUs, cómo estructurar setup y refresh en k6, y qué patrones van en smoke CI vs carga completa—no un secreto hard-coded en git.

Por qué auth falla bajo carga—no a escala single-request

Tests funcionales obtienen un token y lo reutilizan forever. k6 concurrente expone fallos distintos:

  • Rate limits en endpoint token throttle refresh cuando muchos VUs renuevan simultáneamente.
  • Access tokens short-lived expiran mid-escenario—ráfagas 401 si refresh es per-iteration pero sin caché.
  • Tormentas client credentials stampede al IdP cuando cada VU llama /token independientemente.
  • Caps RPM API key devuelven 429 mientras rutas business siguen «bien» a baja tasa.
  • Clock skew entre runners k6 y servidor auth causa errores «expired» prematuros.

Piensa tokens como credenciales de conferencia: una credencial por asistente funciona hasta que todos intentan re-imprimir en el mismo kiosk al cambio de sesión.

Referencia OAuth 2.0 overview y variables de entorno k6 para secretos. Empareja con secretos k6 en entornos prueba y gestionar env vars.

Implementación práctica en k6: refresh compartido con caché por VU

Usa setup() para un fetch client-credentials en smoke, o refresh a nivel módulo con lógica tipo mutex en corridas largas—fetch token una vez por batch de iteración VU, no una vez global forever.

Script de ejemplo (ilustrativo—no listo para producción). URLs IdP ficticias; adapta grant type a tu proveedor.

Qué demuestra este ejemplo:

  • Client credentials en setup: un fetch token antes de escenarios cuando es aceptable para carga service-to-service.
  • Caché token por VU con chequeo TTL: refresh cuando ventana expires_in está cerca—refleja comportamiento SDK.
  • Escenario separado ruta API key: tags auth:api_key vs auth:oauth para triage.
  • Umbrales en fallos auth: http_req_failed{route:token} detecta colapso IdP temprano.
import http from 'k6/http';
import { check, sleep } from 'k6';

const BASE = __ENV.API_BASE || 'https://staging.example.com';
const TOKEN_URL = __ENV.TOKEN_URL || 'https://idp.example.com/oauth/token';

const tokenCache = {};

function getAccessToken(vuId) {
  const now = Date.now();
  const cached = tokenCache[vuId];
  if (cached && cached.expiresAt > now + 5000) {
    return cached.accessToken;
  }

  const res = http.post(
    TOKEN_URL,
    {
      grant_type: 'client_credentials',
      client_id: __ENV.CLIENT_ID,
      client_secret: __ENV.CLIENT_SECRET,
      scope: 'api.read',
    },
    { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, tags: { route: 'token' } },
  );

  check(res, { 'token 200': (r) => r.status === 200 });

  const body = res.json();
  tokenCache[vuId] = {
    accessToken: body.access_token,
    expiresAt: now + (body.expires_in || 3600) * 1000,
  };
  return tokenCache[vuId].accessToken;
}

export const options = {
  scenarios: {
    oauth_api: {
      executor: 'constant-arrival-rate',
      rate: Number(__ENV.API_RPS || 30),
      timeUnit: '1s',
      duration: '5m',
      preAllocatedVUs: 15,
      maxVUs: 60,
      exec: 'callWithOAuth',
      tags: { auth: 'oauth' },
    },
    api_key_route: {
      executor: 'constant-arrival-rate',
      rate: Number(__ENV.KEY_RPS || 10),
      timeUnit: '1s',
      duration: '5m',
      preAllocatedVUs: 5,
      maxVUs: 20,
      exec: 'callWithApiKey',
      tags: { auth: 'api_key' },
    },
  },
  thresholds: {
    'http_req_failed{route:token}': ['rate<0.02'],
    'http_req_failed{auth:oauth}': ['rate<0.01'],
    'http_req_duration{auth:oauth}': ['p(95)<600'],
  },
};

export function callWithOAuth() {
  const token = getAccessToken(__VU);
  const res = http.get(`${BASE}/v1/orders`, {
    headers: { Authorization: `Bearer ${token}` },
    tags: { route: 'orders', auth: 'oauth' },
  });
  check(res, { 'orders 2xx': (r) => r.status >= 200 && r.status < 300 });
  sleep(0.2);
}

export function callWithApiKey() {
  const res = http.get(`${BASE}/v1/metrics`, {
    headers: { 'X-API-Key': __ENV.API_KEY },
    tags: { route: 'metrics', auth: 'api_key' },
  });
  check(res, { 'metrics not 429': (r) => r.status !== 429 });
  sleep(0.3);
}

Patrones que funcionan

  • Escalonar refresh token: jitter sleep antes de refresh cuando muchos VUs comparten ventanas expiry.
  • Escenario token dedicado baja tasa para estresar IdP separado de APIs business.
  • Nunca commitear secretosCLIENT_SECRET y API_KEY solo vía CI/env (guía secretos k6).
  • Taggear path auth para dashboards—401 en rutas business vs ruta token difiere (tags observabilidad k6).

Anti-patrones a evitar

  • Un token global para 500 VUs cuando proveedor emite límites per-client.
  • Refresh en cada iteración sin importar TTL—crea carga IdP artificial.
  • Ignorar 429 en rutas API key—producto puede golpear límites antes de saturar servidores.

Pro tip (comando de ejemplo):

k6 run oauth-load.js -e CLIENT_ID=$ID -e CLIENT_SECRET=$SECRET -e API_KEY=$KEY

Qué demuestra este comando: secretos inyectados en runtime—mismo patrón que CI y staging local deben usar.

Marco de decisión: token estático vs refresh vs auth dual

SituaciónAcción recomendada
Smoke CI corto, token staging long-livedFetch setup una vez; rotar token out-of-band
OAuth production-like con TTL < 15mCaché por VU + refresh antes expiry
API key en endpoints partnerEscenario separado; umbrales 429
Rate limit IdP conocidoCap VUs; jitter; escenario token dedicado opcional
Clientes mixtos OAuth + API keyEscenarios paralelos con tags auth:*

Usa token setup estático si smoke es <2m e IdP owner aprueba token servicio compartido.

Usa refresh por VU si access tokens expiran durante duración test realista.

Usa escenarios duales si tráfico prod mezcla contexto OAuth usuario e integraciones API key.

Observabilidad, documentación y próximos pasos

Tests carga auth fallan silenciosamente cuando 401s se tratan como errores genéricos. Antes de escalar:

  • Documenta grant type, scopes, TTL token y rate limits IdP en runbook.
  • Alerta separadamente en fallos route:token vs tasas 401 rutas business.
  • Correlaciona tags k6 auth:* con métricas IdP durante ventanas staging.
  • Automatiza smoke OAuth en CI con secret store rotado—no tokens commiteados (pruebas de carga en CI/CD).
  • Archiva escenario y patrón inyección secretos por entorno (staging vs load lab).

Cómo Performate simplifica load testing OAuth2

Copy-paste bearer tokens desde devtools browser no escala entre escenarios. Abajo un ejemplo de flujo concreto para orders (OAuth) y metrics (API key).

Ejemplo: escenarios auth dual con secretos env

  1. Importa colección Postman con requests OAuth y API-key; guarda nombres env var en colección. Problema resuelto: rutas definidas una vez; secretos externos.
  2. Configura escenario oauth_api a 30 req/s con nota pre-request enlazando token URL. Problema resuelto: mapa visual auth vs tráfico business.
  3. Agrega escenario api_key_route a 10 req/s con header X-API-Key ligado a env. Problema resuelto: testing límite RPM sin fork script.
  4. Aplica tags auth:oauth y auth:api_key para reportes filtrados. Problema resuelto: mismo modelo tags del ejemplo k6.
  5. Corre en staging con secretos desde archivo env escritorio (nunca commiteado). Problema resuelto: ingeniería itera sin editar script en cada rotación token.
  6. Exporta script k6 para CI con inyección secret store matching nombres env var local. Problema resuelto: ejecución federada sin drift auth.

Ese flujo mapea al cta: escenarios ejecutables, umbrales y reportes sin días de glue code.

Cierre

OAuth en k6 es problema de ciclo de vida: refresh, rate limits y API keys necesitan escenarios y tags separados—no JWT estático del martes pasado.

Corre el load test de esta semana con refresh token habilitado—y observa si IdP o tu API golpea 429 primero al escalar VUs.

Try Performate free | Reserva una demo | Variables entorno k6

¿Listo para optimizar el rendimiento de tu API?

Usa Performate para convertir este playbook en escenarios k6 ejecutables, umbrales y reportes compartibles sin perder días en código pegamento.

← Volver a todas las entradas