Skip to content

Instantly share code, notes, and snippets.

@tanaikech
Last active August 2, 2024 22:07
Show Gist options
  • Save tanaikech/22bfb05e61f0afb8beed29dd668bdce9 to your computer and use it in GitHub Desktop.
Save tanaikech/22bfb05e61f0afb8beed29dd668bdce9 to your computer and use it in GitHub Desktop.
Uploading Files to OneDrive Using Node.js

In order to use this script, please retrieve client id, client secret and refresh token before. About this, you can see the detail information at https://gist.github.com/tanaikech/d9674f0ead7e3320c5e3184f5d1b05cc.

1. Simple item upload

This is for the simple item upload is available for items with less than 4 MB of content. The detail information is https://dev.onedrive.com/items/upload_put.htm.

var fs = require('fs');
var mime = require('mime');
var request = require('request');

var file = './sample.zip'; // Filename you want to upload on your local PC
var onedrive_folder = 'SampleFolder'; // Folder name on OneDrive
var onedrive_filename = 'sample.zip'; // Filename on OneDrive

request.post({
    url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
    form: {
        redirect_uri: 'http://localhost/dashboard',
        client_id: onedrive_client_id,
        client_secret: onedrive_client_secret,
        refresh_token: onedrive_refresh_token,
        grant_type: 'refresh_token'
    },
}, function(error, response, body) {
    fs.readFile(file, function read(e, f) {
        request.put({
            url: 'https://graph.microsoft.com/v1.0/drive/root:/' + onedrive_folder + '/' + onedrive_filename + ':/content',
            headers: {
                'Authorization': "Bearer " + JSON.parse(body).access_token,
                'Content-Type': mime.getType(file), // When you use old version, please modify this to "mime.lookup(file)",
            },
            body: f,
        }, function(er, re, bo) {
            console.log(bo);
        });
    });
});

2. Resumable item upload

This is for the resumable item upload is provided for large files or when a resumable transfer may be necessary. The detail information is https://dev.onedrive.com/items/upload_large_files.htm.

The flow of this script is as follows.

  1. Retrieve access token from refresh token.
  2. Create sesssion.
  3. Upload file by every chunk. Current chunk size is max which is 60 * 1024 * 1024 bytes. You can change freely.

The async module is used for this sample to do the asynchronous processing. By this, the chunk data of the file can be sent in order. stime is used for setTimeout(). When the size of file is large, the transfer error can be avoided by increasing stime.

var fs = require('fs');
var request = require('request');
var async = require('async');

var client_id = "#####";
var redirect_uri = "#####";
var client_secret = "#####";
var refresh_token = "#####";
var file = "./sample.zip"; // Filename you want to upload.
var onedrive_folder = 'SampleFolder'; // Folder on OneDrive
var onedrive_filename = file; // If you want to change the filename on OneDrive, please set this.

function resUpload(){
    request.post({
        url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
        form: {
            client_id: client_id,
            redirect_uri: redirect_uri,
            client_secret: client_secret,
            grant_type: "refresh_token",
            refresh_token: refresh_token,
        },
    }, function(error, response, body) { // Here, it creates the session.
        request.post({
            url: 'https://graph.microsoft.com/v1.0/drive/root:/' + onedrive_folder + '/' + onedrive_file + ':/createUploadSession',
            headers: {
                'Authorization': "Bearer " + JSON.parse(body).access_token,
                'Content-Type': "application/json",
            },
            body: '{"item": {"@microsoft.graph.conflictBehavior": "rename", "name": "' + onedrive_filena '"}}',
        }, function(er, re, bo) {
            uploadFile(JSON.parse(bo).uploadUrl);
        });
    });
}

function uploadFile(uploadUrl) { // Here, it uploads the file by every chunk.
    async.eachSeries(getparams(), function(st, callback){
        setTimeout(function() {
            fs.readFile(file, function read(e, f) {
                request.put({
                    url: uploadUrl,
                    headers: {
                        'Content-Length': st.clen,
                        'Content-Range': st.cr,
                    },
                    body: f.slice(st.bstart, st.bend + 1),
                }, function(er, re, bo) {
                    console.log(bo);
                });
            });
            callback();
        }, st.stime);
    });
}

function getparams(){
    var allsize = fs.statSync(file).size;
    var sep = allsize < (60 * 1024 * 1024) ? allsize : (60 * 1024 * 1024) - 1;
    var ar = [];
    for (var i = 0; i < allsize; i += sep) {
        var bstart = i;
        var bend = i + sep - 1 < allsize ? i + sep - 1 : allsize - 1;
        var cr = 'bytes ' + bstart + '-' + bend + '/' + allsize;
        var clen = bend != allsize - 1 ? sep : allsize - i;
        var stime = allsize < (60 * 1024 * 1024) ? 5000 : 10000;
        ar.push({
            bstart : bstart,
            bend : bend,
            cr : cr,
            clen : clen,
            stime: stime,
        });
    }
    return ar;
}

resUpload();

Testing

  • June 19, 2020: I could confirm that these scripts worked.
@chrisvdt
Copy link

chrisvdt commented Jul 5, 2020

nice script , helped me a lot.
But I was wondering whether the setTimeout(function() is neccessary in the uploadFile function.

If you put the eachSeries callback function after the console.log(bo) in the request.put(), the uploads will be performed in series and the setTimeout is not needed.
}, function(er, re, bo) {
console.log(bo);
callback();
});

or is there another reason for the setTimeout?

@sweatysock
Copy link

Excellent work. Thanks for posting this. Aside from the typos (onedrive_file and onedrive_filena) this is a solid example that has really helped me.

Many thanks amigo.

@maxsalibe
Copy link

I got this. Any idea on what might be wrong?
"{"error":{"code":"InvalidAuthenticationToken","message":"IDX14100: JWT is not well formed, there are no dots (.).\nThe token needs to be in JWS or JWE Compact Serialization Format. (JWS): 'EncodedHeader.EndcodedPayload.EncodedSignature'. (JWE): 'EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag'.","innerError":{"date":"2024-02-01T00:03:12","request-id":"######","client-request-id":"######"}}}"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment