const secretKey = 'your_secret_key'; // Replace with your actual secret key
const expiration = 60; // Expiration time in seconds (how long an HMAC token should be valid for)
const encoder = new TextEncoder();
// Import the secret key for HMAC-SHA256 signing
const key = await crypto.subtle.importKey(
encoder.encode(secretKey),
{ name: "HMAC", hash: "SHA-256" },
const url = new URL(request.url);
// Check if the request URL starts with /generate/
if (url.pathname.startsWith("/generate/")) {
// Replace /generate/ with /
url.pathname = url.pathname.replace("/generate/", "/");
const currentTimestamp = Math.floor(Date.now() / 1000); // Current timestamp in seconds
// Data to authenticate: combine pathname and timestamp
const dataToAuthenticate = `${url.pathname}${currentTimestamp}`;
// Sign the data with HMAC-SHA256
const signature = await crypto.subtle.sign(
encoder.encode(dataToAuthenticate)
// Encode the timestamp and HMAC in a secure manner
const signatureBase64 = btoa(String.fromCharCode(...new Uint8Array(signature)));
const signedData = `${currentTimestamp}-${signatureBase64}`;
const encodedSignedData = encodeURIComponent(signedData);
const signedURL = `${url}?verify=${encodedSignedData}`;
// Return the signed URL in the response body
return new Response(signedURL, { status: 200 });
// For all other request URLs, verify the signed URL
const params = new URLSearchParams(url.search);
const verifyParam = params.get('verify');
return new Response('Verification parameter is missing', { status: 403 });
// Decode and split the verify parameter into timestamp and HMAC
const decodedVerifyParam = decodeURIComponent(verifyParam);
const [timestampStr, receivedMac] = decodedVerifyParam.split("-");
// Parse timestamp and ensure it's a valid number
const timestamp = parseInt(timestampStr, 10);
return new Response('Invalid timestamp', { status: 403 });
// Check if the request has expired
const currentTimestamp = Math.floor(Date.now() / 1000);
if (currentTimestamp > timestamp + expiration) {
return new Response('Signed URL has expired', { status: 403 });
// Remove the verify parameter to verify the URL
url.search = params.toString();
// Construct the data to authenticate for verification
const dataToVerify = `${url.pathname}${timestamp}`;
// Verify the signature with HMAC-SHA256
const isValid = await crypto.subtle.verify(
new Uint8Array([...atob(receivedMac)].map(char => char.charCodeAt(0))),
encoder.encode(dataToVerify)
return new Response('Invalid signature', { status: 403 });
// Continue processing the request if the signature is valid