Upload files to SharePoint with JavaScript using Microsoft Graph and Microsoft Authentication Library
Tags: sharepoint, m365, javascript, microsoftgraph
Published: 2021-11-23 09:00:28

<!-- wp:paragraph -->
<p>Phu, thats a long title - but I wanted to make it really clear what this blogpost is about. So as you might have guessed, in this blogpost I will cover how to upload files to SharePoint with JavaScript using Microsoft Graph for the request, and Microsoft Authentication Library for authentication.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>I recently had to solve this for a client, and I used a lot of time banging my head against the wall looking for resources.  It was not really the lack of resorces that was the issue - but that every example was either to big - or it took for granted that I had some sort of understanding that I was obviously lacking. So when I finally figured out how to do it - and how little code it actually requires - I decided that I needed to blog about it. Hopefully this blogpost will save you some time! </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>I also mada a small vuejs app so you can get up and running quicly. My goal was to present you with the bare minimum amount of code that you need - and hopefully you can build on top of that. </p>
<!-- /wp:paragraph -->

><p><strong>Prerequesites: </strong>You should know basic programming, and have an understanding of working against an API - and different authentication flows.</p><p>
</p><p>
<strong>Source code: </strong>You can find the <a target="_blank" href="https://github.com/Eli-Schei/upload-files-to-sp-using-graph" rel="noopener">full source code for this example on my github</a>. Note, this is a stripped down example to show you the minimum of what you need to upload a file. Its a good baseline/starting point to build on. 
</p>

<!-- wp:heading -->
<h2>Table of contents:</h2>
<!-- /wp:heading -->

<!-- wp:list -->
<ul><li><a href="#introduction" title="#introduction">Introduction</a></li><li><a href="#register-app" title="#register-app">Creating an app registration for a single page application in Azure AD</a></li><li><a href="#auth-with-msal" title="#auth-with-msal">Authenticating with MSAL</a></li><li><a href="#handle-file" title="#handle-file">Handling the file using FileReader</a></li><li><a href="#graph-request" title="#graph-request">Making request to graph</a></li><li><a href="#resources" title="#resources">Resources</a></li></ul>
<!-- /wp:list -->

<!-- wp:heading -->
<h2 id="introduction">Introduction</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>There are four steps you need to complete when uploading files from a javascript app with graph. Lets have a quick look at each of them before we go into the details.</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>You need to register a single page application (SPA) in Azure Acive Directory (AAD). <ul><li>You will use this to authenticate your users.</li></ul></li><li>You need to use Microsoft Authentication library (msal) to authenticate against the SPA you create in the first step.<ul><li>So you know who wants to upload a file - and that they have permission to do so.</li></ul></li><li>You need to handle the file the user has selected. <ul><li>Microsoft Graph accepts ArrayBuffer, Buffer or Blob objects.</li></ul></li><li>You need to make a request to Microsoft Graph with an Authentication Token from msal, and the file your user has selected.</li></ol>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Maybe you allready know how to do some of these steps, or maybe you are new to all of them. In the rest of this blogpost I will cover every step in detail. I also provide you with a list of <a href="#resources" title="#resources">resources</a>. </p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 id="register-app">Creating an app registration for a single page application in Azure AD</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p><em>Since you are reading this blogpost I'll asume that you allready have a Microsoft 365 tenant where you would like to upload the documents. If not you can <a href="https://developer.microsoft.com/en-us/microsoft-365/dev-program" target="_blank" rel="noreferrer noopener" title="https://developer.microsoft.com/en-us/microsoft-365/dev-program">register for a free dev tenant her</a>. </em></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>If you don't have admin priveleges to Azure AD you need to get somenone who does to register the app for you. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>1.</strong> Log in to <a href="https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/Overview" target="_blank" rel="noreferrer noopener" title="https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/Overview">Azure Active Directory</a>. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>2.</strong> In the menu on the left select App registrations</p>
<!-- /wp:paragraph -->

<img src="https://elischei.com/wp-content/uploads/2021/11/image-9.png" alt="Upload files to SharePoint with JavaScript using Microsoft Graph you need to first register an app in azure" class="wp-image-1305"/></figure>


3.Select "New registration

<!-- wp:image <img src="https://elischei.com/wp-content/uploads/2021/11/image-10.png" alt="" class="wp-image-1306"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p><strong>4.</strong> Fill in the name, select the account types you would like to support. And set the Redirect URI type to "Single-page application (SPA)". </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><em>Note, the URI you fill in must match the url where your app is running. In my example code that is localhost:3000. You can change this URI later when the code is running from somewhere else.</em> </p>
<!-- /wp:paragraph -->
<!-- wp:image {"id":1307,"sizeSlug":"large","linkDestination":"none"} -->
<figure class="wp-block-image size-large"><img src="https://elischei.com/wp-content/uploads/2021/11/image-11-1024x619.png" alt="" class="wp-image-1307"/></figure>
<!-- /wp:image -->

5. Click "Register". On the app info page copy down the Application (client) ID, and the Directory (tenant) ID. 
<figure class="wp-block-image size-large"><img src="https://elischei.com/wp-content/uploads/2021/11/image-12-1024x352.png" alt="App registration landing page with App id and tenant ID hightlightet. " class="wp-image-1308"/></figure>

 Thats it. You now have a single page app registration.

<!-- wp:heading -->
<h2 id="auth-with-msal">Authenticating with Microsoft Authentication Library</h2>
<!-- /wp:heading -->

><strong>Example code</strong>
<p>
I have made a small vue app to give you an example that you can actually run right away. But all the logic is written in vanilla javascript so you don't need to know vuejs to use the example. <a href="https://github.com/Eli-Schei/upload-files-to-sp-using-graph">You can find the source code here</a>. </p>
<p><em>Information on how to get the example code up and running is <a href="https://github.com/Eli-Schei/upload-files-to-sp-using-graph#readme">documentet in the repos readme file</a> so I will not cover that in this blogpost. </em>
</p>

<!-- wp:paragraph -->
<p>To be able to upload a document we first need to authenticate the user against the SPA you have registered in Azure AD.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Configuration</strong></p>
<!-- /wp:paragraph -->

```javascript
const msalConfig = {
  auth: {
    clientId: "YOUR APP ID FROM AZURE REGISTRATION",
    authority:
      "https://login.microsoftonline.com/YOUR_TENANT_ID",
    //This URL must match the one set in azure app reg
    redirectUri: "http://localhost:3000/"
  },
};

const msalRequest = {
  scopes: ["User.Read", "Files.ReadWrite", "Files.ReadWrite.All"] 
};
```

<!-- wp:paragraph -->
<p><strong>Code</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>First we create and initialize an msal-client.  This is what we'll use to communicate with the Azure SPA and authenticate the user.</p>
<!-- /wp:paragraph -->
```javascript
const msalClient = new msal.PublicClientApplication(msalConfig);
```
<!-- wp:paragraph -->
<p>Then we write a function to handle the login. This is done by using the msal-client and calling the loginPopup function with the scopes we created in the configuration.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>You can also add functionallity to get the token silently first if the user is allready logged in - so the user is not promted to log in every time. But since I wanted to keep this code sample as small as possible I left this out here, but you can see an example in the next code snippet.</p>
<!-- /wp:paragraph -->
```javascript
export async function signInWithMsal() {
  const authResponse = await msalClient.loginPopup(msalRequest);
  sessionStorage.setItem("msalAuthName", authResponse.account.username);
}
```
We also have a function to get the msal token. This function is used in the next step when we call Graph. Here you can also se an example of ataining the token silently. 
```javascript
export async function getMsalToken() {
  let username = sessionStorage.getItem("msalAuthName");
  try {
    const silentRequest = {
      scopes: msalRequest.scopes,
      account: msalClient.getAccountByUsername(username),
    };
    const silentResult = await msalClient.acquireTokenSilent(silentRequest);
    return silentResult.accessToken;
  } catch (error) {
      //Add handling for new login promt here - if the silent request should fail
    console.error(error);
  }
}

```

<!-- wp:heading -->
<h2 id="handle-file">Handling the selected file</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Graph will axcept the file as an ArrayBuffer, a Buffer or a Blob. In my example we use a filereader object to read the file as an ArrayBuffer and send it to the uploadDocument function. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Obtain the filename and the file itself from the input field. </p>
<!-- /wp:paragraph -->

```javascript
const filename = 
          document.getElementById("selectedFile").files[0].name;
const fileToUplode = 
          document.getElementById("selectedFile").files[0];
```

Create a FileReader and a function that will run when the FileReader is loading. Then call the readFileAsArrayBuffer function passing in the file. The onload function has an event parameter 'event.target.result' will contain the ArrayBuffer version of the selected file. 

```javascript
filereader.onload = async (event) => {
  await uploadDocument(filename, event.target.result);
};
//This will trigger the onload function above.
filereader.readAsArrayBuffer(fileToUplode);
```
Complete code for handling the file and calling uploadDocument().

```javascript
const onSubmit = async (event) => {
      //prevents the site from reloading
      event.preventDefault();
      // sign the user in
      await signInWithMsal();
      //obtain the filename from the file
      const filename = document.getElementById("selectedFile").files[0].name;
      //obtain the file itself
      const fileToUplode = 
          document.getElementById("selectedFile").files[0];
      //create filereader
      const filereader = new FileReader();
      //create function that will run when filereader is loading
      filereader.onload = async (event) => {
        //call uploadDocument function and pass in filename and file as ArrayBuffer
        await uploadDocument(filename, event.target.result);
      };
      //call the readAsArrayBuffer on fileReader and pass inn file.
      //This will trigger the onload function above.
      filereader.readAsArrayBuffer(fileToUplode);
    };
```
<!-- wp:heading -->
<h2 id="graph-request">Making a request to graph</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Now that the authenitcation is handled we can go ahead an make a request to Microsoft Graph. First we need to build the url to use with the request. Then we need to handle the file so it can be sent with the request, and lastly we need to send the request to graph. </p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Building the graph url to use</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>I decided to write a section on how to build your graph-url since I thought it was difficult to figure out exactly what it should contain. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This is how the url should look:</p>
<!-- /wp:paragraph -->

```javascript
  const uploadURL = "https://graph.microsoft.com/v1.0/sites/<YOUR DOMAIN, SOME_ID, SOME_OTHER_ID>/drive/root:/"
 + filename + ":/content";
```
<!-- wp:paragraph -->
<p>I think "SOME_ID" should be the Site-id, and the "SOME_OTHER_ID" should be the web-id. But instead of looking these up I found a graph request that will return the complete id including domian.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To attain it just run the below request in <a href="https://developer.microsoft.com/en-us/graph/graph-explorer" target="_blank" rel="noreferrer noopener" title="https://developer.microsoft.com/en-us/graph/graph-explorer">Graph Explorer</a> (or Postman). </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>N<em>ote, to run this request you need to include a bearer token. If you do it from graph explorer it does this for you when you log in. If you do it from postman you need to get the access token first - and then run the below request.</em></p>
<!-- /wp:paragraph -->

```javascript
https://graph.microsoft.com/v1.0/sites/YOUR_DOMAIN.sharepoint.com:/sites/NAME_OF_SITE_YOU_WANT_TO_UPLOAD_TO/
```
This will give you a response that contains an id like this:
<figure class="wp-block-image size-large"><img src="https://elischei.com/wp-content/uploads/2021/11/image-8-1024x134.png" alt="" class="wp-image-1302"/></figure>
Copy the whole "id" and put it in your uploadURL
```javascript
https://graph.microsoft.com/v1.0/sites/PUT_THE_ID_FROM_PREVIOUS_STEP_HERE/drive/root:/"
 + filename + ":/content"
```
<!-- wp:heading {"level":3} -->
<h3>Making the request</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>There is a Microsoft Graph SDK for javascript, but for this example I'm using a regular window.fetch request instead of creating a graphClient. To learn more about the Graph SDK see links listed in <a href="#resources" title="#resources">Resources</a>. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We pass our uploadURL as the first parameter to fetch. The secod parameter is an object that contains the header with the authorization Bearer token, and a body that contains the file. </p>
<!-- /wp:paragraph -->
```javascript
export async function uploadDocument(filename, fileToUpload){
  const uploadURL = "https://graph.microsoft.com/v1.0/sites/<YOUR DOMAIN, SITE, AND WEB ID HERE >/drive/root:/" + filename + ":/content";
    await window
    .fetch(uploadURL, {
      method: "PUT",
      headers: {
        Authorization: `Bearer ${await getMsalToken()}`,
      },
      body: fileToUpload,
    })
    .then((response) => {
        // Here you can implement some user feedback. "File uploaded" etc.. 
    })
    .catch((error) => {
      console.error("ERROR UPLOADING");
      console.error(error);
    });
}
```
<!-- wp:paragraph -->
<p>And thats it. You have now uploaded a file to SharePoint! </p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Working with large files</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>If you are working with larger files (4MB+) you could use an upload session to handle the request. See links in Resources below for more information about that. </p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Resources</h2>
<!-- /wp:heading -->

<!-- wp:list -->
<ul><li><a href="https://www.npmjs.com/package/@microsoft/microsoft-graph-client" target="_blank" rel="noreferrer noopener" title="https://www.npmjs.com/package/@microsoft/microsoft-graph-client">Microsoft Graph JavaScript Client Library </a>- npm site.</li><li><a href="https://docs.microsoft.com/en-us/graph/sdks/create-requests?tabs=TypeScript" target="_blank" rel="noreferrer noopener" title="https://docs.microsoft.com/en-us/graph/sdks/create-requests?tabs=TypeScript">Make API calls using the Microsoft Graph SDK</a> - Microsoft docs</li><li><a href="https://docs.microsoft.com/en-us/graph/api/driveitem-createuploadsession?view=graph-rest-1.0&amp;preserve-view=true" target="_blank" rel="noreferrer noopener" title="https://docs.microsoft.com/en-us/graph/api/driveitem-createuploadsession?view=graph-rest-1.0&amp;preserve-view=true">Upload a large file with a upload session</a> - Microsoft docs</li><li><a href="https://www.youtube.com/watch?v=YYMFP8xcNOQ" target="_blank" rel="noreferrer noopener" title="https://www.youtube.com/watch?v=YYMFP8xcNOQ">Upload small or large files using Graph</a> - YouTube, Microsoft 365 Developer channel</li><li><a href="https://github.com/microsoftgraph/msgraph-sdk-javascript" target="_blank" rel="noreferrer noopener" title="https://github.com/microsoftgraph/msgraph-sdk-javascript">Microsoft Graph JavaScript Client Library</a> - GitHub, Microsoft Graph repo</li><li><a href="https://docs.microsoft.com/en-us/graph/tutorials/javascript" target="_blank" rel="noreferrer noopener" title="https://docs.microsoft.com/en-us/graph/tutorials/javascript">Build JavaScript single page apps with Graph</a> - Tutorial - Microsoft docs</li></ul>
<!-- /wp:list -->

***
Did you find this article usefull? [Follow me on twitter](https://twitter.com/acupof_dev) to be notified when I publish something new!

Also, if you have any feedback or questions, please let me know in the comments below. 🙂

Thank you for reading, and happy coding!

/Eli