jwtoffice-jsoffice-addinsoutlook-web-addinsoffice-js-helpers

jsonwebtoken package fails to verify user Office.context.mailbox.getUserIdentityToken result


I'm developing an Outlook web add-in.

I'm trying to verify a token that I'm passing to server side, through a node.js library, but it's failing and I can't understand why.

This is what I'm doing to retrieve the user identity token.

Office.context.mailbox.getUserIdentityTokenAsync(function(result) {
    result.value // contains the token.
    // send this value to server side, which I can see that it's working.
})

On the server side, I retrieve the token and do below:

token; // contains the token passed from the web-app.
const jwt = require('jsonwebtoken');
const request = require('request');

let decoded = jwt.decode(token, {complete: true});

// Get the key, we'll need this later since we'll have to
// find the matching key from the config file.
let key = decoded.header.x5t;
let amurl = JSON.parse(decoded.payload.appctx).amurl;

// Make a request to the url to get the configuration json file.
request(amurl, {}, (err, response, body) => {
    let keys = JSON.parse(body).keys;

    // Filter the keys so we get the one which we can verify.
    let s = keys.filter(t => t.keyinfo.x5t === key);
    let cert = s[0].keyvalue.value;

    // Fails the verification.
    console.log(jwt.verify(token, cert));
});

Just to clarify, I'm retrieving the token correctly and this npm package seems to be functioning fine for other jwt tokens. (So it's not really a configuration issue)


Solution

  • I have now found the answer to this question.

    Just to re-iterate the problem was:

    1. Office.context.mailbox.getUserIdentityToken method returns a jwt token.
    2. When decoded this token contains an amurl field which points to the public certificate as a text.
    3. When jsonwebtoken.verify(token, certText) is called, it's failing with the message invalid algorithm (even if you specify the algorithm from the token's header)

    The problem was the formatting of the certificate text. jsonwebtoken package was looking for a particular formatting (splitted with 64 characters across each line along with the certificate begin and certificate end lines, so when formatted with method below - it started working properly.

    The original code is taken from here: https://github.com/auth0/node-jsonwebtoken/issues/68 and formatted slightly to fit the needs.

    /**
     * @param {string} key - The certificate value retrieved from amurl property.
     */
    formatKey: function(key) {
        const beginKey = "-----BEGIN CERTIFICATE-----";
        const endKey = "-----END CERTIFICATE-----";
    
        const sanitizedKey = key.replace(beginKey, '').replace(endKey, '').replace('\n', '')
    
        const keyArray = sanitizedKey.split('').map((l, i) => {
          const position = i + 1
          const isLastCharacter = sanitizedKey.length === position
          if(position % 64 === 0 || isLastCharacter) {
            return l + '\n'
          }
          return l
        })
    
        return `${beginKey}\n${keyArray.join('')}${endKey}\n`
      }