Matt Barr
Matt Barr

Reputation: 494

How do I properly configure the OneDrive / SharePoint File Picker for use with internal Sharepoint storage?

Background

I have followed all Microsoft's documentation, and have viewed several of their samples. It appears that I'm doing everything correctly. The steps I have taken so far are as follows.

Configuration

This is a business sharepoint, so the base url is https://{tenant}-my.sharepoint.com/_layouts/15/FilePicker.aspx. I have validated that I can access the file picker by manually navigating to that control with no issues.

We get a SharePoint token by refreshing our AAD Graph token with the https://{tenant}-my.sharepoint.com/.default scope. The Graph token has the following in addition to other scopes necessary for my app:

My app is a Graph app, but just in case, I also added the Sharepoint Delegated permissions

The token refreshes as expected, and I receive a jwt with, among other properties:

"aud": "https://{tenant}-my.sharepoint.com",
"scp": "User.Read Files.Read Files.Read.All Sites.Read.All ..."

I then configure the picker with the following, however, it never reaches the initializeMessageListener event.

const click = (e: MouseEvent<HTMLButtonElement>) => {
  e.preventDefault();

  const win = window.open("", "Picker", "width=800,height=600");

  if (!win) {
    throw new Error("Could not open picker window");
  }

  setupPicker(win);
};

const setupPicker = async (win: Window) => {
  const options: IFilePickerOptions = {
    sdk: "8.0",
    entry: {
      sharePoint: {},
    },
    authentication: {},
    messaging: {
      origin: window.location.origin, // http://localhost:5173
      channelId: "27", // hard-coded for now, as in the samples
    },
    typesAndSources: {
      mode: "files",
    },
  };

  const queryString = new URLSearchParams({
    filePicker: JSON.stringify(options),
  });

  const accessToken = `Bearer ${await getAccessToken()}`; // access token with properties above
  const url = `${baseUrl}?${queryString}`;

  const form = win.document.createElement("form");
  form.setAttribute("action", url);
  form.setAttribute("method", "POST");
  win.document.body.appendChild(form);

  const input = win.document.createElement("input");
  input.setAttribute("type", "hidden");
  input.setAttribute("name", "access_token");
  input.setAttribute("value", accessToken);
  form.appendChild(input);

  win.addEventListener("message", initializeMessageListener);
  form.submit();
};

const initializeMessageListener = async (event: MessageEvent) => {
  console.log(event);

  // ideally I would setup the port here, but I never receive any messages from the window
};

I never receive any messages from the window. For the first 40 seconds, it displays an empty sharepoint picker. After that, it times out, and I receive a setup timeout error.

My gut tells me that maybe there's some kind of configuration issue with messaging. I'm using window.location.origin which in this case resolves to http://localhost:5173... That's my local app. I don't see why I would receive no messages.

Using the v1.0 REST API

I took my sharepoint token, and attempted to call the sharepoint api at

https://{tenant}-my.sharepoint.com/_api/web/folders

I received a 403 Access Denied response.

I am able to call the following endpoint, where /my is the server relative path for "My files".

https://{tenant}-my.sharepoint.com/_api/web/GetFolderByServerRelativeUrl('/my')/Files

However, it returns an empty object (which is not accurate)

{
    "d": {
        "results": []
    }
}

If I try to access the folder directly, I get 403 Access Denied

Using the v2.0 REST API

If I use my original graph token, I am able to call the following URLs to get drive contents for my user account:

https://graph.microsoft.com/v1.0/me/drives
https://graph.microsoft.com/v1.0/me/drives/{id}/root/children

Upvotes: 0

Views: 262

Answers (0)

Related Questions