I want to send data from Angular into Logstash HTTP input. Because Logstash HTTP input doesn't handle the CORS preflight request gracefully (can't disable basic authentication for OPTIONS), I want to use nginx in front of Logstash as a proxy. The relevant part of my nginx configuration is as follows:
location / {
add_header 'Access-Control-Allow-Origin' *;
add_header 'Access-Control-Allow-Credentials' true;
add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With';
add_header 'Access-Control-Expose-Headers' 'Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With,Content-Disposition';
return 200;
limit_except OPTIONS {
auth_basic "Restricted access zone";
auth_basic_user_file /etc/nginx/htpasswd;
proxy_pass http://localhost:31311; # logstash listens here
}
}
This works fine for allowing the OPTIONS. Relevant cURL output (from Chrome's "Copy as cURL" function:
> OPTIONS / HTTP/1.1
> Host: MUNGED
> Access-Control-Request-Method: PUT
> Origin: MUNGED
> Accept-Encoding: gzip, deflate, br
> Accept-Language: en-IL,en;q=0.9,he-IL;q=0.8,he;q=0.7,en-US;q=0.6
> User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/71.0.3578.80 Chrome/71.0.3578.80 Safari/537.36
> Accept: */*
> Referer: MUNGED
> Connection: keep-alive
> DNT: 1
> Access-Control-Request-Headers: content-type
>
{ [5 bytes data]
< HTTP/1.1 200 OK
< Server: nginx/1.14.0 (Ubuntu)
< Date: Tue, 25 Dec 2018 20:13:01 GMT
< Content-Type: application/octet-stream
< Content-Length: 0
< Connection: keep-alive
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Methods: GET,HEAD,OPTIONS,POST,PUT
< Access-Control-Allow-Headers: Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With
< Access-Control-Expose-Headers: Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With,Content-Disposition
(I'm not sure if Access-Control-Expose-Headers
is necessary, but it doesn't work either way...)
However, for some reason, the subsequent PUT fails because the Authorization header isn't sent in the request. The relevant Angular code looks something like:
const headers = new HttpHeaders();
headers.set('Authorization', 'basic ' + btoa(environment.eventUsername + ':' + environment.eventPassword));
headers.set('Content-Type', 'application/json');
this.httpClient.put(environment.eventTrackingUrl, event, { headers: headers }).subscribe();
However, the PUT headers look like this (again using copy to cURL):
> PUT / HTTP/1.1
> Host: MUNGED
> Origin: MUNGED
> Accept-Encoding: gzip, deflate, br
> Accept-Language: en-IL,en;q=0.9,he-IL;q=0.8,he;q=0.7,en-US;q=0.6
> User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/71.0.3578.80 Chrome/71.0.3578.80 Safari/537.36
> Content-Type: application/json
> Accept: application/json, text/plain, */*
> Referer: MUNGED
> Connection: keep-alive
> DNT: 1
> Content-Length: 144
>
} [144 bytes data]
* upload completely sent off: 144 out of 144 bytes
{ [5 bytes data]
< HTTP/1.1 401 Unauthorized
< Server: nginx/1.14.0 (Ubuntu)
< Date: Tue, 25 Dec 2018 21:03:34 GMT
< Content-Type: text/html
< Content-Length: 606
< Connection: keep-alive
< WWW-Authenticate: Basic realm="Restricted access zone"
No Authorization header... This results in the PUT failing with a 401.
Any clues as to why Angular or the browser isn't sending the Authorization header?