My front-end application (Angular 8) needs to be able to download files from multiple storage providers (currently Azure Blob Storage and Autodesk OSS). I would like the front-end to download directly from the provider rather than having to download first on my back-end. I would like to prevent having the front-end care about the specific providers, so I'm trying to avoid using provider-specific SDKs on the front-end (e.g. @azure/storage-blob) and instead retrieve a pre-authenticated URL from my back-end and then just download from there.
I'm using the following code to retrieve metadata about file (url, filename, and content type), do a GET request to the retrieved (pre-authenticated) URL to download the data, then use saveAs (from the file-saver package) to save to disk:
downloadDocument(id: string) {
this.getDocumentFileInfo(id).pipe(
concatMap(fileInfo => {
const headers = new HttpHeaders().set('Accept', fileInfo.contentType);
return combineLatest(this.http.get(fileInfo.url, { responseType: 'arraybuffer',
headers: headers }), of(fileInfo));
})
)
.subscribe(latest => {
const [data, fileInfo] = latest;
const blob = new Blob([data], { type: fileInfo.contentType });
saveAs(blob, fileInfo.name);
});
}
private getDocumentFileInfo(id: string): Observable<DocumentFileInfo> {
return this.http.get<Document>(`${this._config.apiUrl}documents/${id}/fileinfo`, {withCredentials: true}).pipe(
catchError((error: any) => this.handleError(error))
);
}
When downloading from Azure Blob Storage using this code, I get a 403 response with the following message:
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
If I copy the URL that is logged from browser dev tools and just paste into the address bar of new tab, the file downloads fine, so it doesn't seem to be a problem with the SAS. I've also setup CORS for my storage account to (for now) allow all origins, all methods, and all headers.
What am I missing?