/ Docs / v0.2

Getting started

Install the gateway, then put it between an agent and Gmail in three steps.

/ DocsGetting started

Install

npm i @waterlock/gateway

Node 24+.

Quickstart

1. Gateway

The trusted side. It holds the Gmail credential:

import { serve } from "@hono/node-server";
import { createGateway, createSessions, staticToken } from "@waterlock/gateway";
import { gmail } from "@waterlock/gateway/providers/gmail";

const sessions = createSessions({ signingKey: process.env.WATERLOCK_SIGNING_KEY! }); // >= 32 bytes

const gateway = createGateway({
  providers: [gmail({ credentials: staticToken({ token: process.env.GMAIL_ACCESS_TOKEN! }) })],
  // Default deny: a call goes through only if an allow row matches and no deny row does.
  policy: [
    {
      when: (r) =>
        r.action === "gmail.users.messages.send" &&
        r.context.recipients.length > 0 &&
        r.context.recipients.every((addr) => addr === r.session.onBehalfOf),
      reason: "You can only send email to yourself.",
    },
  ],
  sessions,
});

serve({ fetch: gateway.fetch, port: 8787 }); // gateway.fetch is (Request) => Response

2. Session token

Minted for the agent, on the trusted side:

const { token } = await sessions.mint({ provider: "gmail", agent: "assistant", onBehalfOf: "alice@acme.com", ttlSeconds: 3600 });

3. Harness

A stock client: the gateway as base URL, the session token as bearer.

import { auth, gmail } from "@googleapis/gmail";

const oauth = new auth.OAuth2();
oauth.setCredentials({ access_token: token });
const api = gmail({ version: "v1", auth: oauth, rootUrl: "http://127.0.0.1:8787/" });

await api.users.messages.send({ userId: "me", requestBody: { raw } });
// denied -> 403 { error: { code: "policy_denied", message: "You can only send email to yourself." } }

Full runnable example: examples/ai-sdk-send-email.

Next: how calls map to rules in Actions, and the rule language in Policies.