Skip to content

Edge Content Protection tutorial: four-persona content access

This tutorial walks you through a complete Edge Content Protection (ECP) configuration for a site with two article sections and four distinct reader personas. It covers the JWT design, the rules document, and the PageBuilder resolvers and templates that must be created.

Scenario

In this scenario, you have two article sections with different access rules:

  • News β€” free to all registered (authenticated) users.
  • Sports β€” requires an active subscription entitlement.

Readers fall into one of four personas:

PersonaAuthenticationEntitlementNews accessSports access
AnonymousNo accountNoneMetered (limited)Paywall
RegisteredSigned inNoneFull article, with adsPaywall
Subscriber β€” with adsSigned insubscriber_adsFull article, with adsFull article, with ads
Subscriber β€” no adsSigned insubscriber_no_adsFull article, no adsFull article, no ads

Step 1: Design the JWT

ECP reads two custom claims from the signed JWT cookie you issue: entitlements and prepend.

In this scenario, prepend carries the authentication status signal. Every authenticated user β€” regardless of subscription tier β€” receives prepend: "A". When ECP constructs the variant query parameter, it concatenates prepend with the resolver-query-param from the matching rule. Anonymous users have no JWT cookie, so ECP appends no variant parameter at all.

JWT payloads

Registered user (authenticated, no subscription):

{
"prepend": "A",
"entitlements": "registered",
"exp": 1763035200
}

Subscriber β€” with ads:

{
"prepend": "A",
"entitlements": "subscriber_ads",
"exp": 1763035200
}

Subscriber β€” no ads:

{
"prepend": "A",
"entitlements": "subscriber_no_ads",
"exp": 1763035200
}

Anonymous: No JWT cookie is set. ECP skips rules evaluation entirely and forwards the request without a variant parameter.

Step 2: Build the rules document

The rules document tells ECP how to translate the entitlements claim into a resolver-query-param value. Because the distinction between news and sports access is enforced in the PageBuilder resolvers β€” not at the edge β€” the uri-pattern field is .* for all rules. ECP applies the same entitlement logic regardless of which article section is requested.

{
"matchers": [
{
"priority": 1,
"uri-pattern": ".*",
"entitlements-pattern": "subscriber_no_ads",
"resolver-query-param": "_subscriber_no_ads"
},
{
"priority": 2,
"uri-pattern": ".*",
"entitlements-pattern": "subscriber_ads",
"resolver-query-param": "_subscriber_ads"
},
{
"priority": 3,
"uri-pattern": ".*",
"entitlements-pattern": ".*",
"resolver-query-param": "_registered"
}
]
}

Rules are evaluated in ascending priority order and processing stops at the first match:

  • entitlements: "subscriber_no_ads" β€” matches rule 1.
  • entitlements: "subscriber_ads" β€” does not match rule 1 (no subscriber_no_ads in value), matches rule 2.
  • entitlements: "registered" β€” does not match rules 1 or 2, matches rule 3.

Rule 3 uses .* as a catch-all for any authenticated user whose entitlements do not include a subscription tier. This covers "registered" and any future entitlement string that does not match a higher-priority rule.

Variants produced

The final variant value is prepend + resolver-query-param. Because all authenticated users share prepend: "A":

Personavariant
Subscriber β€” no adsA_subscriber_no_ads
Subscriber β€” with adsA_subscriber_ads
RegisteredA_registered
Anonymous(none β€” no variant parameter appended)

Step 3: Configure PageBuilder resolvers

A PageBuilder resolver matches an incoming URL, fetches article content, and selects the template to render. The resolver also reads the variant query parameter to determine which template to use. For more information on resolvers, see Configuring resolvers.

This scenario requires two resolvers β€” one per article section. The URL-based access distinction between news and sports is enforced here, not in the ECP rules document.

news-article-resolver

Matches URLs of the form /{year}/{month}/{day}/news/{slug}/.

variantTemplateNotes
A_subscriber_no_adsfull-no-adsFull article, no ad slots
A_subscriber_adsfull-with-adsFull article, with ad slots
A_registeredfull-with-adsNews is free for registered users; ad slots rendered
(absent)anonymous-meteredTruncated article, soft paywall prompt

sports-article-resolver

Matches URLs of the form /{year}/{month}/{day}/sports/{slug}/.

variantTemplateNotes
A_subscriber_no_adsfull-no-adsFull article, no ad slots
A_subscriber_adsfull-with-adsFull article, with ad slots
A_registeredhard-paywallSports requires a subscription; upsell page rendered
(absent)hard-paywallAnonymous users also reach the paywall

Step 4: Build your templates

Four templates are required.

full-no-ads

Renders the complete article body without ad slots. Used for A_subscriber_no_ads in both the news and sports resolvers.

full-with-ads

Renders the complete article body with ad slots. Used for A_subscriber_ads in both resolvers, and for A_registered in the news resolver. Registered users receive free access to news but are on an ad-supported tier.

anonymous-metered

Renders a truncated version of the article body followed by a soft paywall prompt. You control how much content is visible before truncation. Because anonymous users are only one step away from unlocking free news access, this template should include prominent registration and sign-in calls to action β€” directing anonymous readers to create an account or log in reduces friction and improves conversion.

hard-paywall

Renders no article content. The page presents a subscription upsell β€” typically a headline, description, and links to available subscription plans. Used for A_registered on sports (registered users must upgrade to access sports) and for anonymous users on sports.

End-to-end matrix

PersonaNews articleSports article
Subscriber β€” no adsfull-no-adsfull-no-ads
Subscriber β€” with adsfull-with-adsfull-with-ads
Registered (no subscription)full-with-adshard-paywall
Anonymousanonymous-meteredhard-paywall

JWT expiry and the redirect flow

JWT cookies expire based on the exp claim you set. When ECP encounters an expired or otherwise invalid JWT and a redirect URL is configured, the reader is redirected to your authentication system rather than silently falling back to the default template.

The flow for a registered or subscribed reader whose cookie has expired:

  1. The reader’s request arrives at the edge with an expired JWT cookie.
  2. ECP rejects the JWT and redirects the browser to your configured redirect URL.
  3. Your system authenticates the reader, issues a fresh JWT with current entitlements, and sets a new cookie.
  4. Your system redirects the browser back to the original article URL.
  5. ECP validates the new cookie and appends the correct variant parameter.

Without a redirect URL configured, readers with an expired JWT are treated the same as anonymous users β€” they receive no variant parameter and see anonymous-metered (news) or hard-paywall (sports) until they sign in again manually.