What Is the gatekeeper-kit Package? OAuth Primitives for Cloudflare OS

The gatekeeper-kit package provides the canonical library of reusable OAuth primitives that abstracts common authentication workflows, credential lifecycles, and observation policies, eliminating hundreds of lines of duplicated boilerplate across Cloudflare's gatekeeper implementations.

The gatekeeper-kit package within the cloudflare/cloudflare-os repository supplies the core building blocks required by every OAuth-style gatekeeper implemented on Cloudflare Workers. By extracting shared logic into a structured two-layer architecture, this library enables developers to build secure, provider-specific gatekeepers—such as those for GitHub, Supabase, or Google—without rewriting common nonce handling, credential storage, or handshake sequencing.

Architecture of the gatekeeper-kit Package

The package is organized into two distinct architectural layers that separate standalone utilities from high-level composition logic.

Layer 1 - Leaf Modules (Standalone Primitives)

Layer 1 consists of tiny, stand-alone primitives that can be imported and used independently without depending on higher-level assembly logic. These leaf modules handle specific concerns such as nonce generation, credential storage, HTTP-error helpers, and simulation utilities.

Key leaf modules include connect-nonce, connect-handshake, credentials, observers, and simulation. Each module is designed to be imported individually, allowing gatekeepers to use only the specific utilities they require.

Layer 2 - The Assembly (Factory and Base Classes)

Layer 2 provides the assembly framework that composes Layer 1 primitives into a cohesive gatekeeper structure. At the heart of this layer is the gatekeeperKit<Env, Grant, Exports, Public>() factory function, defined in src/endpoint.ts, which generates typed specifications and abstract base classes.

The assembly exposes four critical base classes that concrete gatekeepers must extend:

  • KitVendorBase – handles provider-specific vendor logic
  • KitUserAccountBase – manages account-level state and credential coordination
  • KitUserBase – handles user-level authentication flow
  • KitGatekeeperBase – orchestrates the overall gatekeeper lifecycle

Why the gatekeeper-kit Package Exists

Prior to the kit's introduction, every gatekeeper implementation (GitHub, Supabase, Google, etc.) contained approximately 400–500 lines of near-identical plumbing code. This duplication included nonce state machines, Durable Object handling for credential storage, expiry latching mechanisms, and observer bookkeeping logic.

By extracting this plumbing into @gadgets/gatekeeper-kit, new gatekeepers can be authored with significantly fewer lines of code, reducing bug surface area and ensuring that security-critical sequencing changes—such as nonce handling updates or refresh fences—apply uniformly across all gatekeepers.

Core Components and Source Files

Nonce Management (connect-nonce.ts)

The src/connect-nonce.ts module provides cryptographic utilities for OAuth nonce generation and validation. It exports constants such as NONCE_BYTES (defining nonce entropy) and CONNECT_TIMEOUT_MS (defining validity windows), along with functions for generating and verifying nonces.

import {
  generateNonce,
  isLiveNonce,
  NONCE_BYTES,
  CONNECT_TIMEOUT_MS,
} from '@gadgets/gatekeeper-kit/connect-nonce';

// Create a fresh nonce for the initiation step
const nonce = generateNonce();          // → 64‑hex‑character string
const stored = { value: nonce, expiresAt: Date.now() + CONNECT_TIMEOUT_MS };

// Later, when the client returns the nonce:
if (isLiveNonce(stored, returnedNonce, Date.now())) {
  // ✅ Nonce is valid – continue OAuth flow
}

Source: connect-nonce.ts

Handshake Orchestration (connect-handshake.ts)

The src/connect-handshake.ts module implements the two-stage handshake sequence required for OAuth flows. It manages the transition from initiation to OAuth completion using putInitiation, advanceToOAuth, and claimOAuth.

import {
  putInitiation,
  advanceToOAuth,
  claimOAuth,
  StoredNonce,
} from '@gadgets/gatekeeper-kit/connect-handshake';

// Step 1 – store an initiation nonce
putInitiation(kv, initiationNonce, Date.now());

// Step 2 – client completes OAuth, we advance to the OAuth stage
const oauthNonce = advanceToOAuth(kv, initiationNonce, Date.now(), { pkceVerifier: '…' });

// Step 3 – finally claim the OAuth nonce once the provider redirects back
const stored: StoredNonce = claimOAuth(kv, oauthNonce, Date.now());
if (stored) {
  // stored.extra contains any extra fields passed in advanceToOAuth
}

Source: connect-handshake.ts

Credential Coordination (credentials.ts)

The src/credentials.ts module provides the CredentialCoordinator class, which handles secure credential storage, automatic expiration checking, and refresh coalescing—a critical mechanism that prevents thundering-herd problems when multiple requests simultaneously attempt to refresh an expired token.

import {
  CredentialCoordinator,
  CredentialsExpiredError,
} from '@gadgets/gatekeeper-kit/credentials';

// Initialise the coordinator inside a UserAccount Durable Object
const coordinator = new CredentialCoordinator(kv, {
  expiresAt: (c) => c.expiresAt,
  refreshSkewMs: 60_000,
});

// Connect (store new credentials)
coordinator.connect({ accessToken: 'abc', expiresAt: Date.now() + 3_600_000 });

// Refresh the token, automatically coalescing concurrent refreshes
await coordinator.fresh(async (current) => {
  const refreshed = await fetchNewToken(current.refreshToken);
  return { ...refreshed, expiresAt: Date.now() + refreshed.expiresIn * 1000 };
});

Source: credentials.ts

Observer Tracking (observers.ts)

The src/observers.ts module implements privacy-policy enforcement through the ObserverTracker class. This utility manages which external entities can observe credential sets, implementing strategies such as "private-only" access where only the account owner may view credentials.

import { ObserverTracker } from '@gadgets/gatekeeper-kit/observers';

// Create a tracker for a “private‑only” strategy
const tracker = new ObserverTracker({
  kv,
  maxTrackedSets: 500,
  maxObservers: 10,
  vendorId: 'my-gatekeeper',
  // Simple verifier that only allows the account owner
  verifyBaseline: async (verifier) => { /* throw if not owner */ },
  hasSetAccess: async (verifier, setIds) =>
    setIds.map(() => false), // no external set access
});

await tracker.addObserver('observer-id', userVerifier);

Source: observers.ts

The Assembly Factory (endpoint.ts)

The src/endpoint.ts file exports the gatekeeperKit factory that assembles all primitives into a deployable gatekeeper structure. This factory uses a fluent API pattern to define RPC specifications, resource paths, and authentication strategies.

import { gatekeeperKit } from '@gadgets/gatekeeper-kit/endpoint';
import { oauth2 } from '@gadgets/gatekeeper-kit/auth-retry';

// Assemble a gatekeeper that uses the OAuth2 strategy
export const MyGatekeeper = gatekeeperKit<MyEnv, MyGrant, MyExports, MyPublic>()
  .define({
    // RPC spec – exported functions
    getSession: async (env) => { /* … */ },
  })
  .resource({
    // Resource URL grammar (e.g., “/connect”, “/callback”)
    path: '/my-gatekeeper',
  })
  .authStrategy(oauth2({ clientId: env.CLIENT_ID, clientSecret: env.CLIENT_SECRET }))
  .build();

Source: endpoint.ts

Package Configuration and Deployment Model

The gatekeeper-kit package is configured as a private, non-deployable library within the Cloudflare OS monorepo. As defined in packages/gatekeeper-kit/package.json, the package lacks a wrangler.jsonc configuration file, indicating it is intended solely as a shared dependency for other gatekeeper worker packages rather than as a standalone deployed service.

This design ensures that the kit remains an internal implementation detail, allowing the Cloudflare OS team to evolve the OAuth primitives without maintaining backward compatibility for external consumers.

Summary

  • The gatekeeper-kit package eliminates ~400–500 lines of duplicated code per gatekeeper by extracting common OAuth plumbing into reusable modules.
  • It implements a two-layer architecture: Layer 1 provides standalone leaf modules (nonce, credentials, observers), while Layer 2 provides the assembly factory and base classes (KitVendorBase, KitUserAccountBase, KitUserBase, KitGatekeeperBase).
  • Key utilities include generateNonce and isLiveNonce for cryptographic validation, CredentialCoordinator for refresh coalescing, and ObserverTracker for privacy enforcement.
  • The package is strictly internal to the cloudflare/cloudflare-os repository and cannot be deployed as a standalone Worker.

Frequently Asked Questions

What is the primary purpose of the gatekeeper-kit package?

The primary purpose is to serve as the canonical library of reusable gatekeeper primitives that abstracts common OAuth workflows, credential lifecycles, and observation-policy logic. It allows each concrete gatekeeper to focus exclusively on provider-specific pieces (such as token exchange or URL grammar) while reusing shared sequencing logic.

How does gatekeeper-kit reduce code duplication?

Previously, each gatekeeper implementation contained nearly identical boilerplate for nonce machines, Durable Object handling, credential expiry logic, and observer bookkeeping. By extracting these into the kit's Layer 1 and Layer 2 modules, new gatekeepers require significantly less code, and security updates apply uniformly across all implementations.

Can gatekeeper-kit be deployed as a standalone worker?

No. The package is explicitly private and non-deployable, as indicated by the absence of wrangler.jsonc in packages/gatekeeper-kit/package.json. It functions purely as a shared library for other gatekeeper packages within the Cloudflare OS ecosystem.

What are the base classes provided by the assembly layer?

The assembly layer in src/endpoint.ts provides four abstract base classes through the gatekeeperKit() factory: KitVendorBase (provider logic), KitUserAccountBase (account state management), KitUserBase (user authentication flow), and KitGatekeeperBase (lifecycle orchestration). Concrete gatekeeper implementations subclass these bases to inject provider-specific behavior.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →