Use Cloudflare Worker to deploy it as a middleware, for simple authentication (username+passwrod). Below are mutiple versions you can choose. Code was modfied by Claude 3.5 if i remember correctly, original code can be found in Credits.
I used to use the Hono.js middleware but sometimes use this javascript version is actually faster and less clusterf**k.
Before you use: Make sure you add all urls as Routes in your Worker dashboard. Otherwise it won’t work. The paths added in Routes are protected.
Cloudflare Worker 1 - Standard
This is the standard version which supports multiple user&password for authentication, I used this in for early file downloading site. recommended
1const credentials = [2 { username: 'user0', password: 'password0' },3 { username: 'user1', password: 'password1' },4 { username: 'user2', password: 'password2' },5 // Add more users here...6];7
8const REALM = 'Secure Area';9
10addEventListener('fetch', (event) => {11 event.respondWith(handleRequest(event.request));12});13
14async function handleRequest(request) {15 const authorization = request.headers.get('authorization');16 if (!request.headers.has('authorization')) {17 return getUnauthorizedResponse('Provide Username and Password to access this page.');18 }19 const parsedCredentials = parseCredentials(authorization);20 const validCredential = credentials.find((credential) => {21 return credential.username === parsedCredentials[0] && credential.password === parsedCredentials[1];22 });23 if (!validCredential) {24 return getUnauthorizedResponse('The User Name and Password combination you have entered is invalid.');25 }26 return await fetch(request);27}28
29function parseCredentials(authorization) {30 const parts = authorization.split(' ');31 const plainAuth = atob(parts[1]);32 const credentials = plainAuth.split(':');33 return credentials;34}35
36function getUnauthorizedResponse(message) {37 let response = new Response(message, {38 status: 401,39 });40 response.headers.set('WWW-Authenticate', `Basic realm="${REALM}"`);41 return response;42}Example:
I will give this Worker my subdomain “hello.talesofstar.com”, then I can add the Route “hello.talesofstar.com/*”, then all requests to this site will need authentication.
Users defined in code will use their username+password to finish the authentication, very like logging in a website.
Is this secure? HTTP Basic Authentication is secure on severless environment from my understanding (also using experience). But just let you know, there is no rate limiting in this middleware, so tecnically an attacker can try accessing many times however they want.
I have moved to new framework Hono.js. I used it’s middleware but envolved many versions with more advanced and secure setup. However Hono.js needs more code (tho it’s already super lit and fast), sometimes I just prefer pure javascript like this to build a middleware to test out new things on new sub domains.
Cloudflare Worker 2 - Specific Paths
Well, this version supports multiple users but can specific multiple different urls. More control but more “unnecessary” sometimes.
1const credentials = [2 { username: 'u1', password: 'p1', urls: ['https://talesofstar.com/1', 'https://talesofstar.com/1x'] },3 { username: 'u2', password: 'p2', urls: ['https://talesofstar.com/2', 'https://talesofstar.com/2x'] },4
5 // Add more users here...6];7
8const REALM = 'Secure Area';9
10addEventListener('fetch', (event) => {11 event.respondWith(handleRequest(event.request));12});13
14async function handleRequest(request) {15 const authorization = request.headers.get('authorization');16 if (!request.headers.has('authorization')) {17 return getUnauthorizedResponse('Provide User Name and Password to access this page.');18 }19 const parsedCredentials = parseCredentials(authorization);20 const validCredential = credentials.find((credential) => {21 return credential.username === parsedCredentials[0] && credential.password === parsedCredentials[1] && credential.urls.includes(request.url);22 });23 if (!validCredential) {24 return getUnauthorizedResponse('The User Name and Password combination you have entered is invalid or do not have access to the requested URL.');25 }26 return await fetch(request);27}28
29function parseCredentials(authorization) {30 const parts = authorization.split(' ');31 const plainAuth = atob(parts[1]);32 const credentials = plainAuth.split(':');33 return credentials;34}35
36function getUnauthorizedResponse(message) {37 let response = new Response(message, {38 status: 401,39 });40 response.headers.set('WWW-Authenticate', `Basic realm="${REALM}"`);41 return response;42}Note:
Add thse paths to Routes in your Worker settings, just one by one if you have multiple.
Credits
Original middleware code was created by @Max Ivanov (link in links section):
Max Ivanov’s code:
1/**2 * @param {string} USERNAME User name to access the page3 * @param {string} PASSWORD Password to access the page4 * @param {string} REALM A name of an area (a page or a group of pages) to protect.5 * Some browsers may show "Enter user name and password to access REALM"6 */7const USERNAME = 'demouser'8const PASSWORD = 'demopassword'9const REALM = 'Secure Area'10
11addEventListener('fetch', (event) => {12 event.respondWith(handleRequest(event.request))13})14
15async function handleRequest(request) {16 const authorization = request.headers.get('authorization')17 if (!request.headers.has('authorization')) {18 return getUnauthorizedResponse(19 'Provide User Name and Password to access this page.',20 )21 }22 const credentials = parseCredentials(authorization)23 if (credentials[0] !== USERNAME || credentials[1] !== PASSWORD) {24 return getUnauthorizedResponse(25 'The User Name and Password combination you have entered is invalid.',26 )27 }28 return await fetch(request)29}30
31/**32 * Break down base64 encoded authorization string into plain-text username and password33 * @param {string} authorization34 * @returns {string[]}35 */36function parseCredentials(authorization) {37 const parts = authorization.split(' ')38 const plainAuth = atob(parts[1])39 const credentials = plainAuth.split(':')40 return credentials41}42
43/**44 * Helper funtion to generate Response object45 * @param {string} message46 * @returns {Response}47 */48function getUnauthorizedResponse(message) {49 let response = new Response(message, {50 status: 401,51 })52 response.headers.set('WWW-Authenticate', `Basic realm="${REALM}"`)53 return response54}Useful Links
- Max Ivanov: How to password-protect your website with Cloudflare Workers
- Hono.js: Basic Auth Middleware
- Cloudflare Workers Pricing
Links: