Answering my own question.
For local development I used a CORS browser extension (https://addons.mozilla.org/en-GB/firefox/addon/cors-everywhere) to work around the CORS missing headers.
In production, we serve the app via nginx and set up a proxy pass to set the correct headers. The app uses the proxy URL rather than the ActiveCollab API URL.
In the app settings:
VUE_APP_AC_API_URL = '<SERVER_URL>/ac-forwarder/<ACTIVECOLLAB_ACCOUNT>/api/v1'
In the nginx site settings:
location /ac-forwarder/ {
proxy_pass https://app.activecollab.com/;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '<SERVER_URL>';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-Angie-AuthApiToken';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'GET') {
#add_header 'Access-Control-Allow-Origin' '<SERVER_URL>';
add_header 'Access-Control-Allow-Methods' 'GET';
add_header 'Access-Control-Allow-Headers'
'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-Angie-AuthApiToken';
add_header 'Access-Control-Expose-Headers'
'Content-Length,Content-Range';
}
}
location /app {
alias /path/to/the/built/app;
}