Fetch.post with basic auth fails on edge (but works in preview)


#1

We want to post to our backend from the edge using basic auth and custom port numbers. It works just fine in the preview, but we get 401 Unauthorised when running in the edge environment.

We did a minimal test with the code below to make sure that it’s a difference between the preview and the edge:

async function log() {
const init = {
method: ‘POST’,
headers: {
‘content-type’: ‘application/json’,
authorization: ‘basic YRNhc3Q6T0JpUkVmZVJiYQ==’,
},
body: JSON.stringify({
message: ‘test’
}),
};

return fetch(‘http://example.com:1234’, init)
}

async function fetchAndApply(request) {
try {
await log();

return new Response('Hello');

} catch (err) {
return new Response(err.message);
}
}

addEventListener(‘fetch’, async (event) => {
console.log(‘Hello’);
event.respondWith(fetchAndApply(event.request));
});

Any idea why it’s only working in the preview?

Thanks,
Markus


#2

Think I figured out what’s happening… When I run code in the preview it makes a POST to the backend as expected. But when it runs in production it makes a GET?? Is this a bug in the fetch implementation or am I doing something wrong in the sample code above?


#3

Maybe @KentonVarda can check this out.


#4

Thanks!


#5

Is it possible that your backend is returning a 301, 302, or 303 redirect? If so, the runtime will, per the Fetch spec, follow the redirect with a GET, not a POST.

To explain the difference in behavior between the playground and production, perhaps the playground is making https requests unconditionally, even when the URL is an http URL (this would presumably be a bug, if so), while the production environment is correctly making an http request, then getting redirected to https?

You might be able to debug further by adding redirect: "manual" to your init blob, then serializing the response you get. Something like this:

async function log() {
  const init = {
    method: ‘POST’,
    headers: {
      ‘content-type’: ‘application/json’,
      authorization: ‘basic YRNhc3Q6T0JpUkVmZVJiYQ==’,
    },
    body: JSON.stringify({
      message: ‘test’
    }),
    redirect: "manual",  // <-- REDIRECT MODE ADDED
  };

  let response = await fetch(‘http://example.com:1234’, init)
  // SERIALIZE RESPONSE
  return new Response(
    `${response.status} ${response.statusText} Location: ${response.headers.get("Location")`)
}

async function fetchAndApply(request) {
  try {
    return log();
  } catch (err) {
    return new Response(err.message);
  }
}

addEventListener(‘fetch’, async (event) => {
  event.respondWith(fetchAndApply(event.request));
});

Edit: changed redirect mode to "manual" in the code snippet. I originally accidentally wrote "follow", which is the default.


#6

I noticed the difference in behaviour using a local node service with ngrok from the edge worker, so I’m pretty certain that it’s not any redirects involved.
Also verified with httpie that our log service sends a 200 back without any redirects:

http POST "http://user:[email protected]:1234" <<<'{ "message": "test }'
HTTP/1.1 200 OK
Content-Length: 2
Content-Type: text/plain

ok

Are you able to recreate this on your end?