amazon-web-servicesbrowserfetchamazon-cloudfrontweb-application-firewall

AWS WAF: Custom Responses are not accessible by browser


I've configured some rules with custom responses in AWS WAF to prevent some users from accessing my website based on their geographical location. I can see that these rules are working as intended because I am able to see the custom response status (406) and response header (custom-header) in the network tab, but I am struggling to find a way for my web client to access any of these values within JS code (using fetch or axios). While using the fetch API, I receive the following error without any response value: TypeError: Failed to fetch.

I've tried using some of the recommended approaches like utilizing a 302 status code + Location header, but these only work for navigation based GET requests, not ajax ones.

Is there any way to do this other than using some proxy web server between the client and cloudfront?

          fetch(URL, {
            headers: {
              Accept: "application/json, text/plain, */*",
              ...
            },
            // mode: "no-cors", // Results in opaque response
          })
            .then((res) => {
              console.log("$$$ - res: ", res);
            })
            .catch((err) => {
              console.log("$$$ - err: ", err); // TypeError: Failed to fetch
            });

Browser Network Tab


Solution

  • Thanks for the clarification in the comments section.

    There's no real way to retrieve the accessed page's response status, so you are correct in making another request from javascript to access itself.

    I'm not sure why your code throws an error, but here's my setup.

    Here is my code for the custom response body. (content-type: text/html)

    <div>error: access deined</div>
    <script>
    async function init() {
      const url = "https://some-app.com/login"; // change here to your URL.
      try {
        const response = await fetch(url);
        console.log(`Response status: ${response.status}`);
    
      } catch (error) {
        console.log(error);
      }
    }
    
    init();
    </script>
    

    Here are the results: custom response body

    And in my network tab:

    Request URL:
    https://some-app.com/login
    Request Method:
    GET
    Status Code:
    403 Forbidden
    Remote Address:
    3.168.167.82:443
    Referrer Policy:
    strict-origin-when-cross-origin
    alt-svc:
    h3=":443"; ma=86400
    content-length:
    305
    content-type:
    text/html
    date:
    Thu, 06 Mar 2025 00:32:38 GMT
    server:
    CloudFront
    via:
    1.1 0ae13e3213ae63cf41504c85bb3ed990.cloudfront.net (CloudFront)
    x-amz-cf-id:
    2N5vTzJNkx3CPXOV7sodx951lleQb8jaL_kTrQTPMDq4KTcQlEAXqw==
    x-amz-cf-pop:
    ICN57-P4
    x-cache:
    Error from cloudfront
    :authority:
    some-app.com
    :method:
    GET
    :path:
    /login
    :scheme:
    https
    accept:
    */*
    accept-encoding:
    gzip, deflate, br, zstd
    accept-language:
    en-US,en-GB;q=0.9,en;q=0.8
    authorization:
    Basic YXBwb2ludG1lbnQ6aGlybzA0MDE=
    priority:
    u=1, i
    referer:
    https://some-app.com/login
    sec-ch-ua:
    "Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"
    sec-ch-ua-mobile:
    ?0
    sec-ch-ua-platform:
    "macOS"
    sec-fetch-dest:
    empty
    sec-fetch-mode:
    cors
    sec-fetch-site:
    same-origin
    user-agent:
    Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36
    

    Hopefully this helps.