---
updatedAt: 2025-12-01T19:40:45.000Z
agentTools:
  projectIndex: https://docs.pelcro.com/v2.4/llms.txt
---

# Cloudflare

In this guide, you’ll learn how to build a **server-side paywall** using **Pelcro** and **Cloudflare Workers** to securely enforce content access at the edge.

<br />

**Category:** How-To Guide

## Overview

In this guide, you’ll learn how to build a **server-side paywall** using **Pelcro** and **Cloudflare Workers** to securely enforce content access at the edge.

You’ll use Pelcro’s **Authentication** and **Authorization** APIs to:

* Identify logged-in users from their Pelcro token.
* Retrieve the user resource.
* Verify the user’s **entitlements** before serving premium content.

By the end, you’ll have a working Cloudflare Worker that authenticates a Pelcro user, checks their subscription, and conditionally serves or blocks content.

## Prerequisites

* A **Pelcro tenant** with API access (server-side key).
* A **Cloudflare account** with Workers and KV storage enabled.
* A CMS (e.g., Zephyr or Naviga) that adds `X-Access-Tier` and `X-Content-Id` headers per page.

## Step 1 — Understand the Flow

A server-side paywall runs **before** your content is served.
Cloudflare Workers intercept the request, validate the user’s Pelcro token, and call Pelcro APIs to check entitlements.

```
User → Cloudflare Worker → Pelcro API (auth + entitlements) → CMS (content)
```

If the user is entitled, the Worker lets the request continue to your CMS.
Otherwise, it blocks or shows a preview.

## Step 2 — Authenticate the User via Pelcro

According to Pelcro’s [Authenticate a Customer](https://docs.pelcro.com/update/recipes/authenticate-a-customer-use-the-token-with-the-open-api#/) recipe, you can retrieve a user’s information using their token.

After login on your site, Pelcro sets a cookie like:

```
pelcro_session=<JWT_TOKEN>
```

Inside your Worker, extract the token and call the Pelcro Open API `/user` endpoint:

```js
async function getUserFromPelcro(apiBase, token) {
  const res = await fetch(`${apiBase}/user`, {
    headers: {
      "Authorization": `Bearer ${token}`,
      "Content-Type": "application/json"
    }
  });
  if (!res.ok) return null;
  const data = await res.json();
  return data.data; // returns the Pelcro user resource
}
```

**Response Example:**

```json
{
  "data": {
    "id": 12345,
    "email": "customer@example.com",
    "subscriptions": [ { "plan_id": 6789, "status": "active" } ]
  }
}
```

✅ **Tip:** Store your `PELCRO_API_URL` (e.g., `https://api.pelcro.com/v3`) as an environment variable or Worker Secret.

## Step 3 — Check Entitlements

Following Pelcro’s [Authorization recipe](https://docs.pelcro.com/update/recipes/authorization#/), you can verify whether the user has access to a specific resource (content, tier, or plan).

You’ll call the `/authorization` endpoint to check entitlement state:

```js
async function checkEntitlement(apiBase, token, resourceType, resourceId) {
  const res = await fetch(`${apiBase}/authorization`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${token}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      data: {
        type: "authorization",
        attributes: {
          resource_type: resourceType,
          resource_id: resourceId
        }
      }
    })
  });

  const data = await res.json();
  return data.data.attributes.allowed; // true or false
}
```

**Example Request:**

```json
{
  "data": {
    "type": "authorization",
    "attributes": {
      "resource_type": "content",
      "resource_id": "article-123"
    }
  }
}
```

**Example Response:**

```json
{
  "data": {
    "type": "authorization",
    "id": "12345",
    "attributes": {
      "allowed": true
    }
  }
}
```

## Step 4 — Combine Authentication and Authorization in the Worker

Here’s how the complete Cloudflare Worker ties everything together:

```js
export default {
  async fetch(req, env) {
    const url = new URL(req.url);
    const cookies = parseCookies(req.headers.get("Cookie") || "");
    const token = cookies["pelcro_session"];
    const accessTier = req.headers.get("X-Access-Tier") || "standard";
    const contentId = req.headers.get("X-Content-Id") || url.pathname;

    // Step 1: Authenticate
    const user = await getUserFromPelcro(env.PELCRO_API_URL, token);

    // Step 2: Check entitlement
    const allowed = user
      ? await checkEntitlement(env.PELCRO_API_URL, token, "content", contentId)
      : false;

    // Step 3: Enforce paywall
    if (allowed || accessTier === "free") {
      return fetch(req);
    }

    // Not allowed — redirect to Pelcro offers
    return Response.redirect("https://yourdomain.com/subscribe", 302);
  }
};

function parseCookies(str) {
  return Object.fromEntries(str.split(";").map(v => v.trim().split("=")).filter(p => p[0]));
}
```

✅ **Note:** This Worker enforces the paywall **server-side**, so users cannot bypass access control by disabling JavaScript.

## Step 5 — Deploy

1. Save your Worker code.
2. Store `PELCRO_API_URL` as a secret:
   ```bash
   npx wrangler secret put PELCRO_API_URL
   ```
3. Deploy your Worker:
   ```bash
   npx wrangler publish
   ```

## Troubleshooting

| Problem                    | Cause                                  | Solution                                                         |
| -------------------------- | -------------------------------------- | ---------------------------------------------------------------- |
| `401 Unauthorized`         | Token expired or missing               | Confirm Pelcro cookie (`pelcro_session`) is present and valid    |
| Content cached incorrectly | Missing cache variation by entitlement | Add `Vary: X-Access-State` header in Worker                      |
| Slow responses             | Entitlement API not cached             | Use Cloudflare KV to store entitlement results for a few minutes |

## Next Steps

* [Pelcro API Reference – Authentication](https://docs.pelcro.com/update/recipes/authenticate-a-customer-use-the-token-with-the-open-api#/)
* [Pelcro API Reference – Authorization](https://docs.pelcro.com/update/recipes/authorization#/)
* [Pelcro Paywall Enforcement Overview](https://docs.pelcro.com/docs/paywalls#enforcement)
* [Cloudflare Workers Documentation](https://developers.cloudflare.com/workers/)

## Summary

You’ve successfully implemented a **server-side paywall** using **Cloudflare Workers** and **Pelcro APIs**.
Your Worker now:

* Authenticates users with their Pelcro session token.
* Verifies entitlements for each content request.
* Enforces paywall logic before the CMS responds.

This design keeps premium content secure, improves performance, and provides a scalable integration pattern for publishers using Zephyr or Naviga with Pelcro.

# Sibling pages

* [AMP](https://docs.pelcro.com/v2.4/docs/amp.md)
* [Wordpress](https://docs.pelcro.com/v2.4/docs/wordpress.md)
* [Blox](https://docs.pelcro.com/v2.4/docs/bloxdigital.md)