Intro

Recently I have been discussing my usual webpack-centric workflow with a colleague. He pointed that I use both webpack and powershell, he suggested that I should try to get rid of powershell and work on Mac or Linux (sick bastard!). In theory I can use VS Code on any platform, but I will stay on Windows for now. In any case, I decided that it is a good idea to replace some of my powershell code with nodejs scripts. I have tried to find an auth lib for SharePoint Online with no luck.

There are lots of good libs for the app-authentication, and ADAL.js is awesome. But I wanted to use login/password approach to use it from console. I tried to find a nodejs script that can upload some files to SharePoint 'Style Library' or any other document library. After searching for awhile I didn't find anything that can cover my needs. I found a few old abandoned implementations of client API interfaces to SharePoint REST services, but most of them were broken. Microsoft is constantly changing an authentication piece of Office365, so most of those libs are obsolete now. Unfortunately they are still listed on NPM. That's why I decided to roll out a new NPM module.

I found an awesome article about SharePoint Online remote authentication (and Doc upload) from Paul Ryan. It has everything you need to build an auth module for SPO in any language.

Also, I used this tutorial about publishing an NPM module, .gitignore for Node.

I like to play with console, but unfortunately it's not possible to create a github repository from console, so I created it manually.

Code

I opened console and started working on a new project:

    mkdir spo-auth
    cd spo-auth
    npm init
    // Filled some fields with values...

    npm set init.author.name "Oleksii Udovychenko"
    npm set init.author.email "you@example.com"
    npm set init.author.url "oleksiionsoftware.com"
    npm adduser

    // Prompts for credentials and ...
    Logged in as boades.net on https://registry.npmjs.org/.

    npm install -g pakmanager                                                                                                                                      
    ├── argparse@0.1.16 (underscore@1.7.0, underscore.string@2.4.0)                           
    └── pakman@0.11.5 (future@2.3.1, forEachAsync@2.2.1, detective@0.2.1, npm@1.4.29) 

    echo "# spo-auth" >> README.md
    git init
    git add .                                                                                                                                        
    git commit -m "Initial commit, added readme and package.json"        
    [master (root-commit) 3464ff0] Initial commit, added readme and package.json              
    2 files changed, 12 insertions(+)                                                        
    create mode 100644 README.md                                                             
    create mode 100644 package.json  

    git remote add origin git@github.com:boades/spo-auth.git
    git push -u origin master
    Counting objects: 4, done.                                                                                                             
    Delta compression using up to 4 threads.                                                                                               
    Compressing objects: 100% (3/3), done.                                                                                                 
    Writing objects: 100% (4/4), 510 bytes | 0 bytes/s, done.                                                                              
    Total 4 (delta 0), reused 0 (delta 0)                                                                                                  
    To git@github.com:boades/spo-auth.git                                                                                                  
    * [new branch]      master -> master                                                                                                  
    Branch master set up to track remote branch master from origin. 

    touch index.js
    // Copy pasted contents from another project, and then added dependencies

    npm i --save cookie                                              
    cookie@0.3.1 node_modules\cookie                                                          
                                                                                          
    npm i --save xml2js                                              
    xml2js@0.4.17 node_modules\xml2js                                                         
    ├── sax@1.2.1                                                                             
    └── xmlbuilder@4.2.1 (lodash@4.15.0)    

    touch .gignore
    // Added some content to .gitignore

    git commit -m "Added an actual js code and package config"           
    [master 5d962cd] Added an actual js code and package config                               
    3 files changed, 310 insertions(+), 2 deletions(-)                                       
    create mode 100644 .gitignore                                                            
    create mode 100644 index.js                                                              
                                                                                          
    git push -u origin master                                            
    Counting objects: 7, done.                                                                
    Delta compression using up to 4 threads.                                                  
    Compressing objects: 100% (5/5), done.                                                    
    Writing objects: 100% (5/5), 2.97 KiB | 0 bytes/s, done.                                  
    Total 5 (delta 0), reused 0 (delta 0)                                                     
    To git@github.com:boades/spo-auth.git                                                     
    3464ff0..5d962cd  master -> master                                                     
    Branch master set up to track remote branch master from origin.                           
                                                          
    npm publish ./                                                       
    + spo-auth@1.0.0    

Now let's test the module:

    mkdir spo-auth-test
    npm init
    npm i --save spo-auth                                       
    npm WARN package.json spo-auth-test@1.0.0 No description                                  
    npm WARN package.json spo-auth-test@1.0.0 No repository field.                            
    npm WARN package.json spo-auth-test@1.0.0 No README data                                  
    spo-auth@1.0.0 node_modules\spo-auth   

    touch index.js

There are only 3 methods in this small lib, it is very easy to check how they work by executing this small snippet:

var spAuth = require('spo-auth');

var config = {
    host : "devserver.sharepoint.com",
    login : "LOGIN@devserver.onmicrosoft.com",
    password : "PASSWORD"
};

spAuth.getAccessToken(config, function (err, data) {
    console.log(data);
});

spAuth.getFedCookies(config, function (err, data) {
    console.log(data);
});

spAuth.getRequestDigest(config, function (err, data) {
    console.log(data);
});

These methods are very straightforward:

  • getAccessToken makes a request to //login.microsoftonline.com/extSTS.srf to get a security
  • getFedCookies calls getAccessToken and then makes a request to //yourdomain.sharepoint.com/_forms/default.aspx?wa=wsignin1.0 to get FedAuth and rtFa cookies
  • getRequestDigest calls getFedCookies and then makes a request to //yourdomain.sharepoint.com/_api/contextinfo to get FormDigestValue

After that you will be able to use SPO REST interfaces from your code, just pass a correct header or cookie with your request.

Summary

I have published the module to npm, you can find it at spo-auth.

SharePoint Online is an awesome platform that allows you to interact with its content using REST, but sometimes things can get complicated. On the other hand, now I have a better understanding of how SPO Auth works.


;