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.


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.

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

You can retrieve a user’s information using their token.

After login on your site, Pelcro sets the JWT token.

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

async function getUserFromPelcro(apiBase, siteId, token) {
  const res = await fetch(`${apiBase}/customer?site_id=${siteId}`, {
    method: "POST",
    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:

{
  "data": {
    "id": 1017,
    "email": "[email protected]",
    "first_name": "Jane",
    "last_name": "Doe",
    "subscriptions": [
      {
        "id": 55501,
        "status": "active",
        "current_period_start": "2026-09-01",
        "current_period_end": "2026-10-01",
        "cancel_at_period_end": 0,
        "plan": {
          "id": 6789,
          "nickname": "Digital Monthly",
          "interval": "month",
          "entitlements": ["premium"],
          "product": {
            "id": 321,
            "name": "Digital Access"
          }
        }
      }
    ],
    "memberships": [
      {
        "id": 901,
        "status": "active",
        "subscription_id": 77002,
        "subscription": {
          "id": 77002,
          "status": "active",
          "plan": {
            "id": 7001,
            "nickname": "Corporate Licence",
            "entitlements": ["newsletter_pro"],
            "product": { "id": 400, "name": "Business Edition", "entitlements": [] }
          }
        }
      }
    ],
    "orders": [
      {
        "id": 3301,
        "status": "paid",
        "items": [
          {
            "id": 1,
            "product_sku_id": 88,
            "product_sku_name": "Election Guide eBook",
            "product_sku_entitlements": ["ebook_election_2026"]
          }
        ]
      }
    ],
    "expired_subscriptions": null
  }
}
```

✅ 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, you can verify whether the user has access to a specific resource (content, tier, or plan).


Step 4 — Combine Authentication and Authorization in the Worker

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

export default {
  async fetch(req, env) {
    const url = new URL(req.url);
    const cookies = parseCookies(req.headers.get("Cookie") || "");
    const raw = cookies["pelcro.user.auth.token"];
    const token = raw ? atob(decodeURIComponent(raw)) : null;

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

    // Step 2: Check entitlement
    const allowed = user ? checkEntitlement(user, env.PELCRO_ENTITLEMENT) : false;

    // Step 3: Enforce paywall
    if (allowed) {
      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:
    npx wrangler secret put PELCRO_API_URL
  3. Deploy your Worker:
    wrangler deploy

Troubleshooting

ProblemCauseSolution
401 UnauthorizedToken expired or missingConfirm Pelcro cookie (pelcro.user.auth.token) is present and valid
Slow responsesEntitlement API not cachedUse Cloudflare KV to store entitlement results for a few minutes

Next Steps

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.


Did this page help you?