Cloudflare

Add KYA token enforcement to a website or API you already serve through Cloudflare, using a Cloudflare Worker and optional WAF rules.

This guide is for teams already running on Cloudflare who want to add KYA token-based access control to their existing delivery stack. It uses a Cloudflare Worker function, a small serverless function that runs at Cloudflare's edge before a request reaches your origin. The Worker reads the kyapay-token request header, validates the incoming kya token, and then either returns an error or lets the request through to your website or API.

For what a kya token is and why validation works this way, see How it works in Enforce KYA-Based Access Control.

Before you start: you'll need a Cloudflare account with Workers enabled, and your website or API already served through Cloudflare. A reference implementation is available in the skyfire-solutions-cloudflare-news-crawler-demo repo.

Components

Your setup is made of up to three parts:

  • The Worker validates the kya token. It runs on every request that matches its route.
  • A route tells Cloudflare which requests the Worker runs on. For a website, that's a hostname pattern such as dev.example.com/*. For API Gateway, it's an endpoint route pointing at the Worker.
  • A WAF rule (Bots only setups) decides which requests must carry a token at all. It blocks likely bots that arrive without a kyapay-token header before the Worker runs, so human visitors never need a token.

Identify your setup

Two questions determine which setup below applies to you.

Which product serves your traffic?

Cloudflare CDN, if you're serving a website through Cloudflare's proxy. Cloudflare API Gateway, found under Endpoint Management in the dashboard, if you manage API endpoints there.

Which traffic should require a token?

Bots only, letting human visitors through while enforcing tokens on bots. Bots and humans (all), requiring a valid token from every caller, including people in a browser.

What happens to a request depends on which setup you choose:

RequestBots only (Worker + WAF rule)Bots + humans (Worker only)
Human in a browser, no tokenPasses through to your website or APIBlocked by the Worker
Bot, no tokenBlocked by the WAF ruleBlocked by the Worker
Bot or human with an invalid tokenBlocked by the WorkerBlocked by the Worker
Bot or human with a valid tokenPasses through to your website or APIPasses through to your website or API

Bots + humans means ordinary visitors in a browser don't send a kyapay-token header, so with this setup they'll see a JSON error instead of your pages. Choose it only for content that should be reachable by token holders alone, such as an agent-only API. If you want your website to keep working for people, choose Bots only.

Follow the matching setup

Select the tab below that matches your product, then the sub-tab that matches which traffic should require a token.

Use this if your website is served through Cloudflare's CDN, meaning its DNS record in Cloudflare is proxied (orange cloud).

1. Create and configure your Worker

  1. (Extracted from Cloudflare's Create a new Worker project) Create a Worker project on your machine with C3 (create-cloudflare), Cloudflare's command-line tool for setting up new Workers projects. You'll need a Cloudflare account and a recent version of Node.js (see Wrangler's system requirements). In a terminal, run:

    npm create cloudflare@latest -- kya-worker

    kya-worker is the name of the project folder and Worker; use any name you like. C3 then asks a few questions. Answer them like this:

    C3 asksChooseWhy
    What would you like to start with?Hello World exampleGives you a minimal Worker that you'll replace with the example code.
    Which template would you like to use?Worker onlyYou only need a Worker, without static assets or a framework.
    Which language do you want to use?TypeScriptThe example code is written in TypeScript.
    Do you want to use git for version control?Your choiceNot needed for this guide.
    Do you want to add an AGENTS.md file...?Your choiceHelps AI coding tools; not needed for this guide.
    Do you want to deploy your application?NoYou'll replace the code and add configuration first, then deploy in the next step.

    When C3 finishes, move into the new folder; run every later command from here:

    cd kya-worker

    The folder contains these files you'll work with:

    • src/index.ts: the Worker's code, currently a "Hello World!" example. You'll replace it with the example code in the next step.
    • wrangler.jsonc: the Wrangler configuration file, which holds the Worker's name, which file is its code and its environment variables. You'll edit it in step 3. Older projects, or projects created another way, may have wrangler.toml instead; step 3 covers both.
    • package.json and node_modules: the project's npm dependencies, including Wrangler, the CLI you'll use to deploy.

    C3 also installs Wrangler and may open your browser to log in to Cloudflare.

  2. From inside the project folder, install the packages the example Worker code imports:

    npm install validator jose @cloudflare/workers-types

    jose verifies the token's signature, validator checks the claims inside it, and @cloudflare/workers-types provides TypeScript types for the Workers runtime.

  3. Add these environment variables to your Wrangler configuration file. They tell the Worker where to fetch Skyfire's public signing keys and which issuer and algorithm a valid token must have. Use the same values in every environment.

    If your project has wrangler.jsonc, add a vars object at the top level. If your project is older and has wrangler.toml, add a [vars] section instead:

    "vars": {
      "BACKEND_API_URL": "https://api.skyfire.xyz",
      "OFFICIAL_SKYFIRE_JWT_ALGORITHM": "ES256",
      "OFFICIAL_SKYFIRE_JWT_ISSUER": "https://app.skyfire.xyz"
    }
    [vars]
    BACKEND_API_URL = "https://api.skyfire.xyz"
    OFFICIAL_SKYFIRE_JWT_ALGORITHM = "ES256"
    OFFICIAL_SKYFIRE_JWT_ISSUER = "https://app.skyfire.xyz"

2. Choose which traffic requires a token, and deploy

This path adds a Cloudflare WAF rule, a request-filtering rule that runs at Cloudflare's edge before your Worker. The rule blocks requests that Cloudflare scores as likely bots and that don't carry a token header. Human visitors aren't affected by the rule and don't need a token.

Deploy the Worker

  1. Copy the example Worker code into your project's entry file (src/index.ts).

    What this code does: if a request has a kyapay-token (or the deprecated skyfire-pay-id) header, it verifies the token and rejects it if invalid. If there's no token header, it passes the request through to your site, because the WAF rule has already decided that the request didn't need one.

    Adapt it to your needs if necessary.

  2. Deploy from your project folder:

    npx wrangler login   # first time only
    npx wrangler deploy

    Wrangler bundles the TypeScript and its dependencies for you, so there's no separate build step. See Deploy your project for details.

Add the WAF rule

  1. In the Cloudflare Dashboard, select your domain and go to Security → Security rules.

  2. Create a custom rule. It should match requests that are on the hostname you're protecting, likely bots according to Cloudflare's Bot Score, and missing both the kyapay-token header (and the deprecated skyfire-pay-id header).

  3. Set the rule's action to Block.

    Expression you can paste into the Edit expression view, with your own hostname:

    (http.host eq "dev.example.com"
      and cf.bot_management.score lt 30
      and not cf.bot_management.verified_bot
      and not any(lower(http.request.headers.names[*])[*] eq "kyapay-token")
      and not any(lower(http.request.headers.names[*])[*] eq "skyfire-pay-id"))

    How each line works:

    • cf.bot_management.score lt 30: Cloudflare scores every request from 1 (almost certainly automated) to 99 (almost certainly human). Below 30 is Cloudflare's "likely automated" range. Raise or lower the threshold to make the rule stricter or looser.
    • not cf.bot_management.verified_bot: exempts verified bots such as search engine crawlers, so they can keep indexing your site. Remove this line if you want those bots to need a token too.
    • The two header checks let any request that carries a token header past the rule, so the Worker can validate it.
      Example rule:

Why both parts are needed: the WAF rule only checks whether a token header is present, not whether the token is valid. The Worker does the validation. Without the Worker, a bot could send any value in the header and get through. Without the WAF rule, the Bots only Worker would let every request without a token through, bots included.

3. Connect your Worker to your website

A deployed Worker doesn't do anything to your site until you give it a route, a URL pattern that tells Cloudflare to run the Worker on matching requests.

  1. In the Cloudflare Dashboard, open your Worker and go to Settings → Domains & Routes.
  2. Select Add → Route, choose your zone (domain), and enter a pattern that covers the pages you want protected. For example, dev.example.com/* covers every path on dev.example.com.

Once the route is saved, the Worker runs on every matching request. When it lets a request through, fetch(request) at the end of the Worker forwards it to your origin as normal.

If you don't have Bot Management

The Bot Score (cf.bot_management.score) used in the Bots only WAF rule requires a Cloudflare Enterprise plan with Bot Management. A rule with only the header checks blocks every request without a token, humans included.

Alternatives:

  • Super Bot Fight Mode (Business, or Enterprise without Bot Management): turn it on under Security → Bots to block automated traffic, add a WAF custom rule that skips Super Bot Fight Mode for requests carrying a kyapay-token header, and deploy the Bots only Worker. Without the skip rule, agents are blocked even with a valid token. Note that it applies to your whole domain and may occasionally challenge real visitors.
  • Agent-only hostname or path: use the Bots + humans setup on something like api.example.com or example.com/agents/*, and leave human-facing pages without a route. This works on any plan.

See Cloudflare's bot plans for what your plan includes.

Error responses

Return the status codes and messages recommended in Handling Missing or Invalid Tokens: 401 for a missing token and 403 for an invalid one.

  • Worker: your Worker builds the response itself, so set the status and body in its code.
  • WAF rule: in the Bots only setup, the WAF rule blocks bots without a token before your Worker runs. To return the recommended status and message instead of Cloudflare's default block page, set a custom response on the rule's Block action.

Demo

References


Did this page help you?