1: Why Add Basic Auth to a Static Cloudflare Page?
As a remote software developer, I know how we frequently need to access and make tools to make our work easier, and how important it is to share this with our colleagues, however I also sometimes don’t want to share these with the entire world, and the dreaded AI scrapers. It’s also extremely convenient for sites like this, where it was created using a CI pipeline, but I don’t want it to be accessible until it was complete, hence the need for basic auth.
2: What You’ll Need Before Getting Started
- A git repository
- A cloudflare account, with workers enabled
- An IDE and Website
3: Creating the Functions Folder in Your Static Project
The way this script works is using a tool in Cloudflare called Cloudflare Functions which allows a serverless site to run with middleware. To set this up, in the root folder of your repository create a /functions folder, which will be automatically picked up by Cloudflare when deployed.
4: Adding Middleware to Protect Specific Routes
After making the functions folder, you can make an _middleware.js file, which basically applies the code to the entirety of the website (don’t worry we will add specifc paths later!)
5: Implementing Basic Auth in Cloudflare Pages
This code should then be added to your _middleware.js file.
export async function onRequest(context) {
const USERNAME = context.env.AUTH_USER || "admin";
const PASSWORD = context.env.AUTH_PASS || "secret";
const url = new URL(context.request.url);
if (!authHeader || !checkAuth(authHeader, USERNAME, PASSWORD)) {
return new Response("Authentication required", {
status: 401,
headers: {
"WWW-Authenticate": 'Basic realm="Protected Area"',
},
});
}
}
return context.next();
}
function checkAuth(header, username, password) {
const encoded = header.replace("Basic ", "");
const decoded = atob(encoded);
const [user, pass] = decoded.split(":");
return user === username && pass === password;
}In your Cloudflare Page you should then add in two env variables, one for the username with the name as AUTH_USER and the password should also be added in as AUTH_PASS.
6: Protect specific endpoints
To protect a specifc endpoint like /admin you must update your _middleware.js to contain this:
export async function onRequest(context) {
const USERNAME = context.env.AUTH_USER || "admin";
const PASSWORD = context.env.AUTH_PASS || "secret";
const url = new URL(context.request.url);
// Only protect /admin and subpaths
if (url.pathname.startsWith("/admin")) {
const authHeader = context.request.headers.get("Authorization");
if (!authHeader || !checkAuth(authHeader, USERNAME, PASSWORD)) {
return new Response("Authentication required", {
status: 401,
headers: {
"WWW-Authenticate": 'Basic realm="Protected Area"',
},
});
}
}
return context.next();
}
function checkAuth(header, username, password) {
const encoded = header.replace("Basic ", "");
const decoded = atob(encoded);
const [user, pass] = decoded.split(":");
return user === username && pass === password;
}7: Final Thoughts
I hope this helped, and if you have any questions about it or need a hand don’t hesitate to email blog@bizbazboz.uk for assitance!