Cloudflare Zero Trust Site Protection
Integrating Cloudflare Zero Trust provides granular control over who can access your website or applications. Through its authentication and authorization features, you can ensure only users that meet your defined security criteria are granted access, which reduces the risk of unauthorized access and potential threats.
Prerequisites
To follow this guide you will need the following
- A previously setup Edge Delivery Services site, for this demo, we’ll use a site called
zero-trust-site
in theaemsites
github org. - You will need to be a configuration administrator of the org or site and have an authorization token to make requests to the configuration service.
If you don’t already have a site to use, create an Edge Delivery Website by following our developer tutorial.
Create a Cloudflare Site
Follow the steps to set up a Cloudflare site and worker using the wrangler
CLI. If you’re hosting the application on a subdomain, ensure your CNAME record is updated accordingly. In this guide, we configured a CNAME record for our example application at zero-trust.example.com
.
Create a site secret
Create a site access token, this token can be used to restrict access to your edge delivery site.
curl -X POST https://admin.hlx.page/config/aemsites/sites/zero-trust-site/secrets.json \
-H 'x-auth-token: <your-auth-token>'
{
"id": "MEXwhn7J7m1c29ngZqriA5N9DVIb67R_9394vsJ",
"Type": "hashed",
"value": "hlx_sQP7218fBcODiUi7NLVUH6VVT",
"created": "2024-08-21T18:28:54.075Z",
"lastModified": "2025-03-25T12:44:13.235Z"
}
In the response you will get back an id
and a value
. Keep track of these as you will need them in the next steps.
Enable site authentication using the site token
Use the token id
from the response above in place of the TOKEN_ID
in the body.
curl --request POST \
--url https://admin.hlx.page/config/aemsites/sites/zero-trust-site/access/site.json \
--header 'Content-Type: application/json' \
--header 'x-auth-token: <your-auth-token>' \
--data '{
"allow": ["*@acme.com"],
"secretId": ["MEXwhn7J7m1c29ngZqriA5N9DVIb67R_9394vsJ"]
}'
The .page
and .live
origins will now be protected. Users wanting to access the site directly via these origins will now need to sign into the sidekick.
Set Zero Trust Authentication methods
Navigate to the Zero Trust home from the left navigation bar in Cloudflare
and select Settings and the pick Authentication
From Login methods select the Add new button
This is your opportunity to configure the identity provider you want to use for your site. For this demo we will use One-time PIN.
Setup the Zero Trust Policies
Select Access → Policies
Select the Add a policy button
Add a policy with the name TestApp_EmailAccessPolicy
and duration of 24 hours. Change either of these values as you see fit.
Under rules, you can pick whether there is an explicit list of emails you want to have access to the application or want to allow an entire domain access. For this example we will allow anyone with an email address ending in adobe.com
to access the site.
Select Save
Create the Zero Trust Application
Select Access → Applications and click the Add an application button
Select Self-hosted
Enter TestApp
or any name of your choice for the application name. You can keep the session duration set to 24 hours
.
Select Add public hostname and enter in the domain (and optional subdomain) you setup in the first step of this guide. For path enter *
. For our demo we are setting out public hostname to zero-trust.example.com
Under Access policies click Select existing policies
Select our TestApp_EmailAccessPolicy
we previously created and click Confirm.
Select Next at the bottom to get to the Login methods page
Below, you’ll find a list of all the login methods permitted for our application. By default, Accept all available identity providers is selected. However, if you deselect this option, you can choose a specific login method from the list of configured options. Currently, only the One-time PIN has been set up, so it is the only available choice.
Select Next again to get to the advanced settings page.
Open the Cross-Origin Resource Sharing (CORS) settings and enable Bypass options requests to origin to let Edge Delivery handle CORS.
Select Save
Now select the 3 dots on the right of the new application and click Edit.
Take note of the Application Audience Tag, we will need this in a future step.
Update the worker
Next, we’ll update our worker to validate incoming requests, ensuring only approved traffic can access your site.
Install the jose package
In the worker code we created at the start of the guide, install the jose
package. This library is designed to simplify working with JWT tokens.
npm install jose
Edit worker code
Copy the content of this file and paste it into src/index.js
Import functions from the jose package
At the top of the index file, add the following to import the required functions from the jose package.
import { jwtVerify, createRemoteJWKSet } from "jose";
Add token validation logic
Around line 26 at the top of your handleRequest
method, insert the following logic to validate the JWT token provided in the cf-access-jwt-assertion
header. This snippet retrieves the token, sets up the verification context by referencing your Cloudflare Access domain and audience, and uses a remote JSON Web Key Set (JWKS) to verify the token’s integrity. If the token is missing or fails verification, the worker immediately returns an error response, ensuring that only authenticated and authorized requests proceed.
try {
const TEAM_DOMAIN = `https://${env.TEAM_DOMAIN}`;
const AUD = env.POLICY_AUD;
const CERTS_URL = `${TEAM_DOMAIN}/cdn-cgi/access/certs`;
const JWKS = createRemoteJWKSet(new URL(CERTS_URL));
const token = request.headers.get("cf-access-jwt-assertion");
if (!token) {
return new Response('missing required cf authorization token', { status: 403 });
}
await jwtVerify(token, JWKS, {
issuer: TEAM_DOMAIN,
audience: AUD,
});
} catch (error) {
return new Response(`Token verification failed: ${error.message}`, {status: 401});
}
Update wrangler.toml
Note: Some of the values below are considered sensitive and must be kept confidential; ensure they are securely stored and never committed to a public repository in GitHub.
Update route to to match your DNS setup (ex zero-trust.example.com/*
)
Ensure you have the correct account_id
set. To find your account_id
visit the Websites Dashboard in Cloudflare, select your site and it will be listed on the right hand side of the dashboard under API.
Ensure the compatibility_date
is set to at least 2025-03-17
Update the ORIGIN_HOSTNAME
to the edge delivery origin host name (for instance main--zero-trust-site--aemsites.aem.live
)
If commented out, remove the #
in front of PUSH_INVALIDATION
Update the ORIGIN_AUTHENTICATION
to the value from the site token created in a previous step (ex hlx_sQP7218fBcODiUi7NLVUH6VVTpucnHIA51yEuDFS0GE0
)
Get your team domain by going to the Zero Trust dashboard and opening Settings → Custom Pages. Create a new variable with the name TEAM_DOMAIN
and the your team domain (for instance dylandepass.cloudflareaccess.com
)
Create a new variable called POLICY_AUD
and set it to the AUD value from the Zero Trust application you created above.
Your wrangler.toml
should look something like this.name = "zero-trust-worker"
main = "src/index.mjs"
route = "zero-trust.example.com/*"
account_id = "abb72b21b09d6ac32460ac4654da1248"
compatibility_date = "2025-03-17"
[build]
command = "npm install"
[vars]
# TODO: set origin host name
ORIGIN_HOSTNAME = "main--zero-trust-site--aemsites.aem.live"
# Optional, but recommended: enable push invalidation
# see https://www.aem.live/docs/setup-byo-cdn-push-invalidation#cloudflare
PUSH_INVALIDATION = "enabled"
# Optional: enable origin authentication
# see https://www.aem.live/docs/authentication-setup-site
ORIGIN_AUTHENTICATION = "hlx_sQP7218fBcODiUi7NLVUH6VVTpucnHIA51yEuDFS0GE0"
TEAM_DOMAIN = "example-domain.cloudflareaccess.com"
POLICY_AUD = "94k128458a52641b9a5294d2cebc5kjk124021964fa01e4aal8b5c11d34948e8s0"
Congratulations, your site should now be protected by Cloudflare Zero Trust. Try navigating to your site and authenticating using a PIN. Upon successful authentication you should see your site.