Requests that redirect with 301 response code, sends http requests without header

Am using the below in a k6 test where in the request url has continuationToken, where header has the authentication token for the http call.

let params = {
headers: { “Authorization”: “Bearer token_value” }
}
http.get(http://test.com?continuationToken=token, params);

When the script in run with --http-debug=full , i can see that request is sent with headers and the response is a 301 Moved Permanently and there is an automatic redirect to the same url and could see that header is not sent in the redirect request and hence resulting in 401 response code.

Note: have tried the same request via postman, and the request goes fine after the 301 redirect.

Please let me know if the topic needs more clarification.

Hi there,

so this is a tricky topic worth a discussion, but here’s what I’m currently aware about it:

The native Go HTTP client used by k6 does in fact forward headers when following redirects, except for security-sensitive headers like Authorization when the redirect is to a different domain. For example, if the initial request is to test.com and the redirect is to example.com, then the headers won’t be forwarded. This is to protect against CSRF type of attacks, where the sensitive header could be leaked to 3rd parties.

You can read more about this in the http.Client documentation.

From what I’ve been able to research about this, header forwarding is undefined in the HTTP RFCs, meaning that it’s up to clients to determine this behavior. If Postman does this by default, it should come with a warning, perhaps even more explicitly than how curl(1) mentions it in their documentation about --header.

You might be able to workaround this with a cookie-based auth system, as from what I’ve seen in my tests cookies are currently forwarded regardless of the domain, but that will require changes in your backend, which you probably want to avoid. :slight_smile:

It might be worth considering adding an option or environment variable to override the current behavior in k6 to explicitly forward all headers, but let’s see what @mstoykov and @ned think about this.

Hi @imiric thanks for the reply. I double checked my request, and both the requests have the same host. so according to you, header should be passed on ? But it does not do send the Authorization header.

@jeevananthank What k6 version are you using (output of k6 version)?

Also, could you post the k6 and Postman scripts? Or relevant parts of them, if they’re private or too complex?

This is the behavior I’m seeing with a trivial localhost test (output of k6 run --http-debug=full):

Request:
GET /hello HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: k6/0.26.1 (https://k6.io/)
Authorization: Token
Accept-Encoding: gzip


Response:
HTTP/1.1 301 Moved Permanently
Content-Length: 42
Content-Type: text/html; charset=utf-8
Date: Tue, 21 Apr 2020 07:42:30 GMT
Location: /hello2

<a href="/hello2">Moved Permanently</a>.


Request:
GET /hello2 HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: k6/0.26.1 (https://k6.io/)
Authorization: Token
Referer: http://127.0.0.1:8080/hello
Accept-Encoding: gzip


Response:
HTTP/1.1 200 OK
Content-Length: 97
Content-Type: text/plain; charset=utf-8
Date: Tue, 21 Apr 2020 07:42:30 GMT

User-Agent: k6/0.26.1 (https://k6.io/)
Authorization: Token
Referer: http://127.0.0.1:8080/hello

I see the Authorization header sent in the second request, and then echoed back by the second endpoint. I would expect the same would happen if redirecting to the same domain, but maybe I’m overlooking something.

am using k6 v0.26.2 (2020-03-18T11:45:39+0000/v0.26.2-0-g459da79e, go1.13.8, windows/amd64)
below is what i see when the test is run.

Its just a http.get request where the endpoint has a continuationToken with Authorization in the header. The headers are not passed on even when the test.js k6 script has only the http.get

And with respect to the postman request, its a normal GET request with authorization with no additional settings to the requst. and postman console shows that after the request with 301 response, the redirect request returns the response as expected.

Hi, sorry about the delay. Unfortunately, I’m not able to reproduce this. If you can provide a working k6 script that reproduces it using e.g. httpbin.test.k6.io we can take a further look at it.

In the meantime you can use a workaround to manually follow the redirect and insert the Authorization header in the second request by setting the redirects request parameter or the global maxRedirects option to 0.

For example:

import http from "k6/http";

const baseURL = 'https://httpbin.test.k6.io';

export default function() {
    let headers = { "Authorization": "Token" };
	let res = http.get(`${baseURL}/redirect/1`, { headers: headers, redirects: 0 });
	http.get(baseURL + res.headers.Location, { headers: headers });
}

See the documentation and this sample script.