I've been having some difficultly performing CORS PUTs for an app I have tunnelled over ngrok with HTTPS + basic auth. A CORS PUT is always preceeded by an automatic preflight OPTIONS call from the browser - this call is failing with a 401 - this from Chrome:
XMLHttpRequest cannot load https://[...].ngrok.com/api/v1/landmarks/0003/bu3d_fe.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://www.landmarker.io' is therefore not allowed access.
The response had HTTP status code 401.
I think the error given may however be a bit of a red herring, as if we try the same with cURL:
> curl -X OPTIONS https://[...].ngrok.com -v
* Rebuilt URL to: https://[...].ngrok.com/
* Hostname was NOT found in DNS cache
* Trying 173.[...].192...
* Connected to [...].ngrok.com (173.[...].192) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
* Server certificate: *.ngrok.com
* Server certificate: PositiveSSL CA 2
* Server certificate: AddTrust External CA Root
> OPTIONS / HTTP/1.1
> User-Agent: curl/7.37.1
> Host: [...].ngrok.com
> Accept: */*
< HTTP/1.1 401 Not Authorized
* Server nginx/1.6.2 is not blacklisted
< Server: nginx/1.6.2
< Date: Sat, 17 Jan 2015 22:40:48 GMT
< Content-Length: 23
< Connection: keep-alive
< WWW-Authenticate: Basic realm="ngrok"
* Connection #0 to host rmaxbksjh8urnqig.ngrok.com left intact
Unless I am mistaken, it seems that ngrok with basic auth is placing a blanket authentication requirement on all endpoints for all calls. However, it seems that the CORS spec says that OPTIONS calls should always be performed and permitted without authentication even when basic auth is turned on:
I've looked at the link spec but I'm no expert in parsing it so I can't be sure that is indeed what it says. However, the linked bug reports and mailing list do seem to make it clear that OPTIONS preflight calls should be permitted without authentication in a basic auth setting.
Looking at the headers that Chrome has dispatched with the OPTIONS call it can be seen that Chrome refuses to include the usual authentication header with the preflight header (which is fair enough, they are just sticking to the spec). Given all that, it seems that ngrok is currently unable to be used in this configuration, unless a special case is allowed to bypass authentication for all OPTIONS calls.
To clarify, the above 401 error is exactly the same whether or not my client is actually running, so I'm fairly sure that this isn't down to some kind of misconfiguration of the thing I am trying to forward.
@jabooth Sorry for the slow turnaround here.
You're absolutely right, this is tricky. For APIs with CORS, the right thing to do would be to allow the request through regardless of the authentication. But for other (non-CORS) applications, this may be undesirable and a unexpected security hole. There are two options:
For now, I'm going to lean on option 2 because while it's more work for the application developer, it provides complete flexibility and doesn't bloat the configuration file with more options.
No problems at all @inconshreveable.
I only tried adapting my app to add HTTPS after writing this bug report and was surprised to find it pretty trivial (menpo/landmarkerio-server@a700175) so I agree that this is a case you can just leave for the app developer to sort out.
My only final comment would be that it might be nice to highlight this issue somewhere, maybe on your FAQ? It wasn't immediately obvious from the errors I was seeing to understand what exactly the problem was - a quick FAQ pointing out that the ngrok basic auth applies to all requests including preflight OPTIONS requests which breaks CORS puts would be useful to help people running into this in the future.
Thanks for all your hard work on ngrok! :)
Yep, this should definitely be part of the FAQ and docs. I'll put it on my docs list to get something up there so it's not confusing for others. Thanks for the detailed bug report!