Audit Logs

Custom Audit Logs

Zuplo Audit Logs stores your audit trail in Zuplo and gives you a portal viewer and query API out of the box. If your organization uses an external audit logging service instead, you can send events to it directly from the gateway with a custom policy that uses runtime hooks. This approach works on any plan — it's just custom code — and gives you full control over which events are recorded, the event format, and the destination.

Example: WorkOS Audit Logs

WorkOS provides various services that help enable enterprise features on your service such as SSO and Audit Logs. The following custom policy logs API calls to the WorkOS Audit Logs API after each response is sent:

TypeScriptCode
import { ZuploContext, ZuploRequest, environment } from "@zuplo/runtime"; export async function auditLogPlugin( request: ZuploRequest, context: ZuploContext, policyName: string, ) { // Clone the request so the body can be read in the hook // note: remove this if you don't need content from the body const cloned = request.clone(); context.addResponseSendingFinalHook(async (response) => { const incomingBody = await cloned.json(); // This is an example event. Extract any additional data needed from the // request. const body = { organization_id: "org_01EHWNCE74X7JSDV0X3SZ3KJNY", event: { action: "user.signed_in", occurred_at: "2022-09-02T16:35:39.317Z", version: 1, actor: { type: "user", // Use the user sub for authenticated users id: request.user.sub, metadata: { role: "user", }, }, targets: [ { type: "user", id: "user_98432YHF", name: "Jon Smith", }, { type: "team", id: "team_J8YASKA2", metadata: { owner: "user_01GBTCQ2", }, }, ], context: { location: request.headers.get("True-Client-IP"), user_agent: request.headers.get("User-Agent"), }, metadata: { extra: incomingBody.extra, }, }, }; await fetch("https://api.workos.com/audit_logs/events", { method: "POST", body: JSON.stringify(body), headers: { Authorization: `Bearer ${environment.WORKOS_API_KEY}`, "Content-Type": "application/json", // Optional idempotency key. // See: https://workos.com/docs/reference/idempotency // "Idempotency-Key": "YOUR_KEY_HERE" }, }); }); return request; }

The same pattern works for any provider with an HTTP API — swap the event shape and endpoint for your provider's, and store credentials in environment variables.

Last modified on