Search code examples
cloudflarecloudflare-workers

Cloudflare Worker redirect stripping auth headers


I set up a Cloudflare worker to redirect to our API gateway since we don't have control of the DNS and can't just set up a CNAME. The redirect works and it passes along the body and all the headers except Authorization. It receives it, and when I look at the worker console it lists it as redacted. It also redacts the user_key param I'm passing but it passes that through.

const base = 'https://myurl.com'
const statusCode = 308;

addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const url = new URL(request.url);
  const { pathname, search } = url;

  const destinationURL = base + pathname + search;

  return Response.redirect(destinationURL, statusCode);
}

Solution

  • First, note that the redactions you are seeing are purely for display in the workers console. This is a feature to protect sensitive secrets from being logged, but it doesn't affect the content of any live request.

    Now, with regard to what your Worker is actually doing:

    This worker returns a 308 redirect response back to the client. It is then up to the client to follow the redirect, sending the same request to the new URL.

    It is the client, then, that decides whether to send the Authorization header to the new location -- the behavior is NOT controlled by Cloudflare Workers. As it turns out, many clients intentionally drop the Authorization header when following redirects to a different domain name. For example, the Go HTTP client library does this, and node-fetch recently started doing this as well. (I happen to disagree with this change, for reasons I explained in a comment.)

    If the client is a web browser, then the behavior is complicated. If the Authorization header was added to the request as part of HTTP basic auth (i.e. the user was prompted by the browser for a username and password), then the header will be removed when following the redirect. However, if the Authorization header was provided by client-side JavaScript code when it called fetch(), then the header will be kept through the redirect.

    Probably the best way to solve this is: Don't use a 3xx redirect. Instead, have the Worker directly forward the request to the new URL. That is, instead of this:

      return Response.redirect(destinationURL, statusCode);
    

    Try this:

      return fetch(destinationURL, request);
    

    With this code, the client will not receive a redirect. Instead, the Worker will directly forward the request to the new URL, and then forward the response back to the client. The Worker acts as a middleman proxy in this case. From the client's point of view, no forwarding took place, the original URL simply handled the request.