Al final de esta guía, tu función rechazará peticiones sin token válido.
Inicio rápido
Activa auth en tu función
import { define , z } from "@jelou/functions" ;
export default define ({
description: "API protegida" ,
input: z . object ({ query: z . string () }) ,
auth: true ,
handler : async ( input , ctx ) => {
return { results: [], authenticated: ctx . auth ?. authenticated };
} ,
}) ;
Configura el secret
jelou secrets set mi-funcion AUTH_SECRET=mi-token-secreto
Cuando usas auth: true, la plataforma busca un secret llamado AUTH_SECRET automáticamente.
Llama con el token
curl -X POST https://mi-funcion.fn.jelou.ai \
-H "Authorization: Bearer mi-token-secreto" \
-H "Content-Type: application/json" \
-d '{"query": "test"}'
Respuesta exitosa: { "results" : [], "authenticated" : true }
Sin token o con token incorrecto: { "error" : "Unauthorized" }
Variantes de auth
Valor Comportamiento trueBusca el secret AUTH_SECRET. Rechaza con 401 si falta o no coincide. falseSin autenticación (valor por defecto). { secret: "API_TOKEN" }Busca un secret con ese nombre específico. { secret: ["API_TOKEN", "API_TOKEN_OLD"] }Acepta cualquiera de los secrets (útil para rotación de llaves). { secret: "API_TOKEN", required: false }Auth opcional — nunca retorna 401.
ctx.auth
Resultado de la verificación de autenticación disponible dentro del handler.
Campo Tipo Descripción ctx.authAuthResult | nullnull cuando auth no está activo o es opcional sin tokenctx.auth.authenticatedbooleantrue si el token fue verificado
Escenario Resultado Token válido Handler se ejecuta, ctx.auth = { authenticated: true } Token inválido o faltante 401 Unauthorized + header WWW-Authenticate: BearerSecret no configurado en env 500 fail-closed (nunca permite acceso si el secret no existe)Trigger cron Auth se omite — los crons tienen firma criptográfica propia Token > 4 KB Rechazado con 401
Fail-closed : si olvidas configurar el secret con jelou secrets set, la plataforma retorna 500 en lugar de permitir acceso. Esto es intencional — nunca se degrada a “sin auth”.
Rotación de llaves
Acepta el token antiguo y el nuevo simultáneamente durante la migración:
export default define ({
description: "API con rotación de llaves" ,
input: z . object ({ id: z . string () }) ,
auth: { secret: [ "API_TOKEN" , "API_TOKEN_OLD" ] } ,
handler : async ( input , ctx ) => {
return { id: input . id };
} ,
}) ;
jelou secrets set mi-funcion API_TOKEN=nuevo-token-v2
jelou secrets set mi-funcion API_TOKEN_OLD=token-anterior-v1
Una vez que todos los clientes usen el nuevo token, elimina API_TOKEN_OLD del array y del secret.
Auth opcional
Endpoints públicos con acceso premium opcional:
export default define ({
description: "Catálogo con precios premium opcionales" ,
input: z . object ({ categoria: z . string () }) ,
auth: { secret: "API_TOKEN" , required: false } ,
handler : async ( input , ctx ) => {
const productos = await buscarProductos ( input . categoria );
if ( ctx . auth ?. authenticated ) {
return { productos , precios: await preciosMayorista ( productos ) };
}
return { productos };
} ,
}) ;
Con required: false:
Token válido → ctx.auth = { authenticated: true }
Sin token → ctx.auth = null, handler se ejecuta normalmente
Token inválido → ctx.auth = null (no retorna 401)
Auth en app()
Auth global
import { app , define , z } from "@jelou/functions" ;
export default app ({
config: { auth: { secret: "API_TOKEN" } } ,
tools: {
buscar: define ({
description: "Buscar registros" ,
input: z . object ({ q: z . string () }),
handler : async ( input ) => ({ results: [] }),
}),
crear: define ({
description: "Crear registro" ,
input: z . object ({ nombre: z . string () }),
handler : async ( input ) => ({ id: "abc-123" }),
}),
} ,
}) ;
Todos los tools heredan el auth global.
export default app ({
config: { auth: { secret: "API_TOKEN" } } ,
tools: {
healthCheck: define ({
description: "Health check público" ,
input: z . object ({}),
auth: false ,
handler : async () => ({ status: "ok" }),
}),
admin: define ({
description: "Operación de admin" ,
input: z . object ({ action: z . string () }),
auth: { secret: "ADMIN_TOKEN" },
handler : async ( input ) => ({ done: true }),
}),
} ,
}) ;
Tool Auth healthCheckSin auth (auth: false sobrescribe el global) adminUsa ADMIN_TOKEN en lugar del global
Cron bypass : los triggers cron nunca pasan por auth. Si tu función usa isCron, verifica la lógica de negocio internamente.
Nunca hardcodees secrets en el código. Usa siempre jelou secrets set.
Fail-closed : un secret faltante causa 500, no acceso abierto.
Testing
import { assertEquals } from "jsr:@std/assert" ;
import {
createMockAuthContext ,
createMockAuthRequest ,
createMockContext ,
createMockRequest ,
} from "@jelou/functions/testing" ;
Deno . test ( "handler recibe auth cuando token es válido" , async () => {
const ctx = createMockAuthContext ();
const req = createMockAuthRequest ( "mi-token-secreto" , { query: "test" });
const result = await fn . handler ({ query: "test" }, ctx , req );
assertEquals ( result . authenticated , true );
});
Deno . test ( "handler sin auth retorna ctx.auth null" , async () => {
const ctx = createMockContext ({ auth: null });
const req = createMockRequest ({ query: "test" });
const result = await fn . handler ({ query: "test" }, ctx , req );
assertEquals ( result . authenticated , undefined );
});
createMockAuthContext() Referencia completa de los mocks de autenticación.