After trying a lot of configuration options, I did get rendering panels with HTTPS, basic auth and the reverse proxy working.
What helped was checking the Apache access log. It shows you what calls PhantomJS is trying to make on your server and what IP/username it is using. PhantomJS is added to the user agent string of the calls it makes. PhantomJS is used as a headless browser by Grafana to make a screenshot of the panel.
I now use the following root_url in
root_url = %(protocol)s://%(domain)s/grafana/
When using the default protocol/domain this makes PhantomJS call
VirtualHost for port 80 in my Apache configuration uses the following
Require ip ::1
ProxyPass http://localhost:3000 retry=0 timeout=3600
This excludes ::1 (localhost, where PhantomJS is running) from the basic auth.