0

I have an Angular application that is using OneDrive/Sharepoint to store files it has created. Authentication is working correctly and I can save my files successfully. I am having a problem with downloading the file that I created and stored using the Angular HttpClient.

My code looks like this:

export class MicrosoftService {

   private graphUri = 'https://graph.microsoft.com/v1.0';

   constructor(private http: HttpClient) {}

   public loadFile(id: string, next: (saved: string) => void): void {
  
        this.http.get(this.graphUri + '/me/drive/items/' + id + '/content', { headers: this.getOAuthHeader() })
             .subscribe((response: any) => {
                console.log(response.toString());
                next(response.toString());
            });
    }

    getOAuthHeader(): HttpHeaders {
       // a bunch of stuff that generates the OAuth headers, definitely works
    }

}

Obviously I'll do something else with the response when I can receive it.

The problem is that when the GET request is triggered it correctly makes a request to graph, which then returns a 302 redirect to https://foozlecorporation-my.sharepoint.com/drive/path/_layouts/15/download.aspx?UniqueId=a-bunch-of-url-params - this is also correct and I can download the content from a REST client, but in the browser (currently using Safari) the redirect raises a Browser cannot load [...url...] due to access control checks error.

I have Access-Control-Allow-Origin: * in my application headers, which is presumably why I can use Graph in the first place, but the Sharepoint response does not include Access-Control-Allow-Origin. What more do I need to do?

glenatron
  • 11,018
  • 13
  • 64
  • 112
  • 1
    Do you get the same error while not using Safari? I have noticed sometimes Safari interprets this error differently and other browsers give better insight – Jeremy Jan 06 '22 at 17:28
  • 1
    Related: https://stackoverflow.com/questions/69494027/access-control-allow-origin-equals-origin-but-the-browser-still-denies-access/69497937#69497937 – jub0bs Jan 06 '22 at 19:03
  • Does `https://foozlecorporation-my.sharepoint.com/drive/path/_layouts/15/download.aspx?UniqueId=a-bunch-of-url-params` itself respond with `Access-Control-Allow-Origin: *`? – jub0bs Jan 06 '22 at 19:03
  • 1
    @jub0bs it does not add any `Access-Control-Allow-Origin` header. – glenatron Jan 07 '22 at 10:02
  • 1
    @glenatron There is your problem. When a CORS request responds with a cross-origin redirect, a new CORS access-control check is carried out for the new destination origin. If the server in question isn't configured for CORS, you're out of luck. – jub0bs Jan 07 '22 at 10:09
  • Thanks for confirming my concern. Love that Microsoft offer a Javascript-accessible Rest API that you can't use from Javascript. That's a real delight. – glenatron Jan 07 '22 at 10:31
  • 1
    @Jub0bs, I've edited the question, why don't you reformat your comment there as an answer so there's a clearer record. – glenatron Jan 07 '22 at 10:33

1 Answers1

1

Problem

You write that endpoint https://foozlecorporation-my.sharepoint.com/drive/path/_layouts/15/download.aspx?UniqueId=a-bunch-of-url-params doesn't responds with any Access-Control-Allow-Origin header.

When you send, from origin A, a CORS request to some endpoint on origin B (https://graph.microsoft.com) and the response allows origin A but results in a cross-origin redirect to some endpoint on origin C (https://foozlecorporation-my.sharepoint.com), the browser carries out a new CORS access-control check for origin A on origin C. If origin C isn't configured for CORS or doesn't allow origin A, your overall CORS request will fail.

Possible solution

One solution consists in making the call to https://graph.microsoft.com from your backend rather than from your frontend; that way, because CORS doesn't apply to non-browser user agents, you'd sidestep the problem.

jub0bs
  • 60,866
  • 25
  • 183
  • 186
  • 1
    I think your solution is probably what I'm going to have to go for- intercepting the 302 and then proxying the request is inelegant but it seems like the only thing that will work. – glenatron Jan 07 '22 at 10:55