HTTP Basic Authentication
An example of restricting access using HTTP Basic.
warning
Be careful for use in the production environment!
This code is an example and is not suitable for operational and production environments. Basic Authentication sends authentication values unencrypted and should be used with an HTTPS connection for added security.
'use strict';
addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const authHeader = request.headers.get("Authorization");
let response;
if (authHeader != null && authHeader.startsWith("Basic")) {
let encodedCredential = authHeader.substring(6);
if (CREDENTIALS.has(encodedCredential)) {
let newUrl = new URL(request.url);
newUrl.protocol = UPSTREAM_PROTOCOL;
newUrl.host = UPSTREAM_HOST;
let newReq = new Request(newUrl.toString(), request);
newReq.headers.delete("Authorization");
response = await fetch(newReq);
}
else {
response = UNAUTHORIZED_INVALID_CREDENTIALS_RESPONSE;
}
}
else {
response = UNAUTHORIZED_NEEDS_LOGIN_RESPONSE;
}
return response;
}
// Credentials for users
const UserPassList = [{ user: "admin", pass: "adminpass" }];
// Upstream url
const UPSTREAM_URL = "http://localhost:4000";
const UNAUTHORIZED_NEEDS_LOGIN_RESPONSE = new Response(null, {
//TODO: Add realm and/or charset if needed
headers: new Headers({
"WWW-Authenticate": "Basic",
}),
status: 401,
});
const UNAUTHORIZED_INVALID_CREDENTIALS_RESPONSE = new Response(null, {
status: 401,
});
// Key: Base64 encoded username:password
// Value: username
const CREDENTIALS = (() => {
const map = new Map();
for (let i of UserPassList) {
// TODO: this may not properly work with utf8
const encoded = btoa(`${i.user}:${i.pass}`);
map.set(encoded, i.user);
}
return map;
})();
const UPSTREAM_PROTOCOL = new URL(UPSTREAM_URL).protocol;
const UPSTREAM_HOST = new URL(UPSTREAM_URL).host;