# What Is a Gatekeeper Worker in Cloudflare OS? Architecture and Implementation Guide

> Understand Cloudflare OS Gatekeeper Workers. This Durable Object broker secures RPC calls, manages authentication, authorization, caching, and approval workflows for user Gadgets and third-party services.

- Repository: [Cloudflare/cloudflare-os](https://github.com/cloudflare/cloudflare-os)
- Tags: architecture
- Published: 2026-09-05

---

**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`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-shared/src/gatekeeper.ts):

1. **GatekeeperVendor** – The top-level entrypoint (`WorkerEntrypoint`) that acts as the service factory.
2. **UserAccount** – A per-user Durable Object that securely stores OAuth tokens and user-specific configuration.
3. **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`](https://github.com/cloudflare/cloudflare-os/blob/main/.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`](https://github.com/cloudflare/cloudflare-os/blob/main/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`](https://github.com/cloudflare/cloudflare-os/blob/main/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`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/user.ts).

When a Gadget establishes a connection:

1. The backend instantiates the **Vendor** (`GatekeeperVendor`) as the entry point.
2. It creates or retrieves a **UserAccount** Durable Object for the authenticated user.
3. 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`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-context/src/index.ts) demonstrates the minimal structure:

```typescript
// 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:

```typescript
// 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`](https://github.com/cloudflare/cloudflare-os/blob/main/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`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-shared/src/gatekeeper.ts)** – Canonical interface definitions including `GatekeeperVendor`, `GatekeeperUser`, `Gatekeeper`, `GatekeeperUserVerifier`, and `ApprovalQueue` with extensive JSDoc documentation.
- **[`packages/gatekeeper-context/src/index.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-context/src/index.ts)** – Reference implementation demonstrating the minimal exports required for a functional Gatekeeper Worker.
- **[`packages/gatekeeper-email/README.md`](https://github.com/cloudflare/cloudflare-os/blob/main/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`](https://github.com/cloudflare/cloudflare-os/blob/main/.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 the `GATEKEEPER_<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 `ApprovalQueue` with simulation support, while **read operations** use `authorizeObservation` with 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`](https://github.com/cloudflare/cloudflare-os/blob/main/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`](https://github.com/cloudflare/cloudflare-os/blob/main/.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.