What Is a Gatekeeper Worker in Cloudflare OS? Architecture and Implementation Guide
A Gatekeeper Worker in Cloudflare OS is a secure, Durable Object-based broker that mediates capability-based RPC calls between user Gadgets and external third-party services, managing authentication, fine-grained authorization, caching, and approval workflows.
In the cloudflare/cloudflare-os repository, the Gatekeeper Worker functions as the essential security boundary between Gadgets (user-written code running in the Workshop) and external APIs like Google, GitHub, or Supabase. Unlike standard HTTP endpoints, this specialized Cloudflare Worker implements a sophisticated hierarchy of Durable Objects and exposes a typed TypeScript API through Cap'n Web, ensuring that Gadgets can only access explicitly granted resources.
Core Architecture and Hierarchy
The Gatekeeper Worker implements a three-tier Durable Object hierarchy that separates concerns between service definition, user identity, and resource instances.
Three-Tier Design Pattern
At the foundation of every Gatekeeper Worker lies a strict hierarchy defined in packages/workshop-shared/src/gatekeeper.ts:
- GatekeeperVendor – The top-level entrypoint (
WorkerEntrypoint) that acts as the service factory. - UserAccount – A per-user Durable Object that securely stores OAuth tokens and user-specific configuration.
- Gatekeeper – A per-resource Durable Object facet that implements the Session API exposed to Gadgets.
This architecture ensures that authentication state is isolated per user in durable storage, while resource-specific logic operates in separate Durable Object instances, enabling fine-grained access control and horizontal scaling.
Key Responsibilities and Implementation
According to the skill guide at .agents/skills/write-gatekeeper/SKILL.md, a Gatekeeper Worker fulfills eight critical responsibilities:
Authentication and Token Management
The Worker handles complete OAuth flows and credential storage. In packages/gatekeeper-context/src/index.ts, the GatekeeperVendor and ContextAccount classes manage token persistence within the UserAccount Durable Object, ensuring that sensitive credentials never leave the secure Worker environment.
Capability-Based API Design
The Worker exposes a thin, typed TypeScript API that mirrors external service resources as capabilities—objects with methods that represent specific actions a Gadget can perform. This design follows the principle that Gadgets receive capability objects rather than raw API tokens, enforcing the principle of least privilege.
Fine-Grained Resource Granting
Users can grant Gadgets access to specific resources (e.g., a single Google Doc or GitHub repository) rather than blanket account access. This granularity is enforced at the Gatekeeper DO facet level, where each instance represents exactly one resource or collection.
Approval Queue and Observability
All side-effect actions route through the ApprovalQueue system, while read-only observations call authorizeObservation. This separation ensures that destructive operations require explicit user approval while maintaining audit trails. The GatekeeperUserVerifier interface in packages/workshop-shared/src/gatekeeper.ts implements observer verification, ensuring that collaborators viewing a Gadget's data possess equivalent access rights to the underlying external resources.
Caching and Performance Optimization
Remote data is cached within the Gatekeeper's Durable Object storage (utilizing KV or SQLite-backed Durable Objects) to minimize external API calls. This caching layer enables richer API shapes that aggregate data across multiple endpoints without performance penalties.
Simulation of Pending Actions
When an action is submitted to the ApprovalQueue but not yet approved, the Gatekeeper enters simulation mode. It pretends the action has taken effect by mutating the local cache or overlaying pending actions, allowing Gadgets to display optimistic UI updates while awaiting final authorization.
Push Notification Hooks
The Worker provides a hook mechanism for external services to push events (such as inbound emails) to Gadgets via persistent RPC stubs. This enables real-time synchronization without polling, implemented through long-lived Cap'n Web WebSocket connections.
Implementation Structure and Discovery
Durable Object Facets and Entry Points
A Gatekeeper Worker is not discovered as a traditional HTTP endpoint but as a service binding. The Workshop backend automatically discovers available Gatekeepers through the GATEKEEPER_ prefix in service bindings, as implemented in packages/workshop-backend/src/user.ts.
When a Gadget establishes a connection:
- The backend instantiates the Vendor (
GatekeeperVendor) as the entry point. - It creates or retrieves a UserAccount Durable Object for the authenticated user.
- It mints a Gatekeeper DO facet that implements the Session API for the specific resource.
Minimal Implementation Skeleton
A functional Gatekeeper Worker requires three main exports. The following pattern from packages/gatekeeper-context/src/index.ts demonstrates the minimal structure:
// packages/gatekeeper-example/src/index.ts
export {
GatekeeperVendor, // top-level entrypoint (WorkerEntrypoint)
ExampleAccount, // per-user durable object
ExampleGatekeeper, // per-resource DO facet
} from "./gatekeeper-impl.js";
export default {
async fetch() {
return new Response("Example gatekeeper is alive", {
headers: { "content-type": "text/plain" },
});
},
};
This structure exports the three-tier hierarchy while providing a fallback HTTP handler for health checks or direct Worker access.
How Gadgets Consume Gatekeeper Capabilities
Gadgets interact with external services exclusively through the typed Session API provided by the Gatekeeper. The following example demonstrates how a Gadget uses the capability object:
// In a Gadget's code (client side)
import { ExampleSession } from "gatekeeper-example";
async function listProjects(session: ExampleSession) {
// `session` is a capability the gatekeeper provides.
const projects = await session.listProjects(); // read-only, authorizes observation
console.log(projects);
}
The ExampleSession type—defined in src/types.d.ts of the gatekeeper package—represents the sole API surface visible to the Gadget. Behind this interface, the Gatekeeper manages caching, approval queues, and external API calls transparently.
Key Source Files and Components
Understanding the Gatekeeper Worker requires familiarity with these critical files in the Cloudflare OS repository:
packages/workshop-shared/src/gatekeeper.ts– Canonical interface definitions includingGatekeeperVendor,GatekeeperUser,Gatekeeper,GatekeeperUserVerifier, andApprovalQueuewith extensive JSDoc documentation.packages/gatekeeper-context/src/index.ts– Reference implementation demonstrating the minimal exports required for a functional Gatekeeper Worker.packages/gatekeeper-email/README.md– Real-world example showing inbound email handling, hook architecture, and Durable Object address mapping..agents/skills/write-gatekeeper/SKILL.md– Authoritative design guide detailing the eight responsibilities, implementation phases, and architectural constraints.packages/gatekeeper-<name>/wrangler.jsonc– Configuration declaring the Worker as deployable and defining theGATEKEEPER_<NAME>service binding used by the Workshop backend.
Summary
- A Gatekeeper Worker acts as a secure RPC broker between Gadgets and external services, implemented as Durable Object-based Cloudflare Workers.
- The architecture follows a three-tier hierarchy: Vendor (entrypoint), UserAccount (per-user OAuth storage), and Gatekeeper (per-resource capability provider).
- Security is enforced through capability-based access control, where Gadgets receive typed Session objects rather than API tokens.
- Side-effect actions route through an
ApprovalQueuewith simulation support, while read operations useauthorizeObservationwith observer verification. - Data is cached in Durable Object storage to optimize performance and enable complex aggregations.
- Workers are discovered via
GATEKEEPER_service bindings in the Workshop backend, not through traditional HTTP endpoint registration.
Frequently Asked Questions
How does a Gatekeeper Worker differ from a standard Cloudflare Worker?
A Gatekeeper Worker is a specialized Durable Object-based Worker that implements the three-tier hierarchy (Vendor, UserAccount, Gatekeeper) and communicates via Cap'n Web RPC rather than standard HTTP requests. While regular Workers process HTTP requests directly, Gatekeepers function as persistent RPC endpoints discovered through service bindings, maintaining stateful connections to external services on behalf of specific users.
How are OAuth tokens stored and secured within the Gatekeeper architecture?
OAuth tokens are stored within UserAccount Durable Objects, instantiated per user and bound to the ContextAccount class as defined in packages/gatekeeper-context/src/index.ts. These tokens never leave the Worker environment; Gadgets receive capability objects that proxy requests through the Gatekeeper, ensuring that raw credentials remain isolated in secure, durable storage while the Gadget operates with minimal necessary privileges.
What is the purpose of the ApprovalQueue in Gatekeeper Workers?
The ApprovalQueue manages all actions that produce side effects (writes, deletions, updates) by intercepting these calls before execution. When a Gadget attempts a mutating operation, the Gatekeeper submits it to the queue, enters simulation mode to show optimistic results, and waits for explicit user authorization. This mechanism, detailed in .agents/skills/write-gatekeeper/SKILL.md, ensures that destructive operations require conscious approval while maintaining responsive UI through local cache manipulation.
How does observer verification maintain security when sharing Gadget data?
The GatekeeperUserVerifier interface ensures that collaborators observing a Gadget's data possess equivalent access rights to the underlying external resources. When a user shares a Gadget view, the Gatekeeper implements getVerifier, addObserver, and removeObserver methods to validate that the observer's capabilities match the data being displayed, preventing information leakage across permission boundaries.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →