Limitations of Internet Explorer when considering using Cookies with O365 Add-Ins

In this article I will demonstrate some of the limitations of Internet Explorer’s cookie handling and how we need to architect out Office Add-Ins to prevent overload thereof.

Introduction

In a previous article I demonstrated how we could cache data within an O365 Add-In using document.cookie. The logical extension of this would be to use it to cache OAuth tokens from Azure AD. In that way users would not have to re-authorize every time then opened the Add-In.

An OAuth token in the O365 environment is typically around 1500 characters in length !

c1

Blowing up cookies in Internet Explorer(11)

In Internet Explorer there is a finite limit to the total size of the cookies on any one page. Those cookies are built up of all the cookies valid for that path.

We can easily demonstrate how to blow this up by successively adding more and more data to a cookie as you can see below. As we add the same OAuth token over and over again we successively increase the length of the cookie until we cross 10,000 bytes and it blows up to zero.

c2

The implications of this are stark; if we cache an OAuth token for more than six O365 Add-Ins (even if they all get a different name) in the same path, we could destroy all of them without the user even knowing. This is not acceptable and we need a more elegant solution.

Cookie Pathing

When creating a cookie, the path is an optional variable and if it is not added the “path” it defaults to the current location.

;path=path (e.g., ‘/‘, ‘/mydir‘) If not specified, defaults to the current path of the current document location.” – From Mozilla’s documentation

Using smart deployment architecture of Add-Ins

The implication therefore it to ensure that all of the Add-Ins are hosted in different directories (if they are in fact all deployed on the same server). Without setting a path the cookie will be created with the path to the current location.href directory

In the following example we set a cookie in one directory, and it is unavailable in the second directory.

c3

c4

Conclusions

Although this is probably not a significant issue in the wild (because most people are not going to put all their Add-Ins in the same folder for deployment), it is something good to be aware of. There is a finite limit to the size of any single cookie in Internet Explorer, don’t blow it.

 

Advertisements

Office Add-In problem solved: Internet Explorer by default does not allow CORS

In this article I will highlight an issue you may come across when you are trying to deploy an Office Add-In pulling data from a different domain.

Introduction

As my adventure into Office Add-Ins has continued I began to look at integrating data from outside of the O365 environment, into Office Add-Ins. In this example specifically pulling data from an external source into an Excel spreadsheet.  I followed the example code from the Build your first Excel add-in site and as I showed in the Firebug Lite post I was able to take the example code and make it work in an Add-In. I then wanted to prove to myself that I could pull it from a real data source.

The Data Source

The data source was a Domino web service which I was able to duplicate the data feed from. As you can see from the response headers I am adding everything necessary to allow CORS. I was hosting the Add-In at napacloudapp.com and looking to pull the data from copper.xomino.com

d1

But every time I ran the code I had an error which told me that the data could not be pulled from copper. For the life of me I could not figure out how until I came across a post on stackoverflow (which I cant find to reference now) which pointed me in the direction of IE security settings.

By Default CORS is turned off in Internet Explorer !

This is a setting which goes WAY back to the start of Cross Site Scripting issues and way before CORS itself was even a standard. This was actually something Microsoft did right with old IE !

If you go to Tool – Internet options – Security and look inside the Custom Settings option for Internet sites you will find that accessing data across domains is Disabled! So CORS isn;t even an options – cross domain data retrieval is off.

d2

The solution – Trusted sites

You can change this for Internet sites in IE10 or IE11 because both of those browsers have CORS built in to protect you – not so much in IE9.

In a business environment though you should be using Trusted Sites. If your Add-In HOST website (www.napacloudapp.com in my case) is added to Trusted Sites then the Access data across domain options is set to “Enable” and the problem is fixed.

Conclusion

This was something I first encountered way way back over 10 years ago when I was messing with XML Islands back in IE5 ! I knew it was there but had never really though about it in this context.

Because the client based Add-In experience is basically an embedded Internet Explorer instance, all the browser settings are carried into the experience with it.

As is often the case, once you understand the problem, the solution is relatively simple – it’s just getting there which is bothersome 🙂

 

 

 

 

Caching data across disparate O365 Add-Ins (and across client types)

In this article I will show how data can be cached between O365 office Add-Ins. This also includes different clients (Outlook, Excel etc, even Internet Explorer)

Introduction 

In the previous article we looked at how we are able to cache data within an Office Add-In using the browser’s document.cookie capability. In this article I will demonstrate how flexible this capability is and how it will even work across different Add-Ins and different applications.

Creating a Cookie

Cookies can be created and be stored within a specific domain/path and this is critical for this example to work. If you do not add a path variable to the cookie when creating it, it will not be available outside of the specific URL from whence it was created.

Going back to the setCookie code I used before:

function setCookie(name, value, duration) { 
  var now = new Date();
  var time = now.getTime();
  var expireTime = time + 1000*duration;
  now.setTime(expireTime);
  document.cookie = name+'='+value+';expires='+now.toGMTString()+';path=/';
}

We can see that there is a path=/ variable added in the creation. This statement means that this cookie is available to all web pages within the domain. Without it, the cookie is tied to the exact URL it was created from. Ideally you would not use the whole domain and you would be more specific to a single directory path. For the sake of this example though it makes life easier 🙂

What this means for us though is that we are able to create a cookie from one Add-In (URL Host) and as long as it is in the same domain, we can access that cookie value in another.

Creating the cookie in one Add-in

In the example below we are setting the cookie in the Outlook Add-in. The location.href  (which is the host page for the Add-In) is https://copper.xomino.com/xomino/extjs.nsf/O365Token/index.html. You can see from the Firebug Lite console that Outlook has appended the client name to the end of the URL.

c6

Using the setCookie function we create the “EXAMPLEToken” cookie and make it valid for 120 seconds.

We then open Excel and look at an Add-In I created there. As you can see from the example below the location.href for the hosted Add-In file is https://copper.xomino.com/xomino/O365.nsf/index.html. While the path is not exactly the same as the Outlook example – the hosting domain is (copper.xomino.com).

c7

The example above uses a getCookie function to get the value of the “EXAMPLEToken” and our value “xomino365” is returned successfully.

After two minutes a subsequent attempt to get the cookie fails because it has expired

c8

And it is as simple as that.

Conclusion

Adding a path variable to the cookie creation has allowed us to create the cookie within on Add-In (Outlook in this case) and access it from within another Add-In (Excel in the second case).

Caveat

Be aware that you need to have control and consideration about how much data you load into a cookie. Any Internet Explorer cookie for a given domain cannot be more than 10234 chars.

Addendum

What is actually interesting to find out is that even though the embedded client Add-In used Internet Explorer – any cookies created within the client are actually available within the stand alone Internet Explorer – and Vice Versa!

The cookie created in outlook before – is available in full Internet Explorer as well.

c9

This has to raise some fascinating potential for a truly immersive experience between users in the outlook clients and their web browsing. Here it is being set in IE and being read in the Excel Add-In

c10

 

 

Caching data in O365 Add-ins using document.cookie

In this article we will look at a technique for caching data (ultimately an OAuth token) within an Office Add-in.

Introduction

In previous articles I have discussed how to create an Authorization token in an Office Add-in and created the O365Token project on Github. These set up the possibility for using only JavaScript (no C#) to generate an Azure AD Authorization token which can then be used to interact with the O365 environment.

The only drawback so far is that every time the Add-In loads, a new window pops up to collect the token. It would be a much more elegant solution to be able to cache the token somehow and then re-use it. In this article we will look at using cookies for “caching” tokens in both the Outlook Client and the O365 web mail experience.

 

Cookies

Cookies have been around for almost as long as web browsers. They can be set to hold a value for a finite amount of time (permanent) or fixed to only this browser session (session).

Using the FireBug Lite technique previous described we are able to take a look at cookies and how they are stored within the browser.

Within Outlook itself we can see the cookies using document.cookie

c1

and we can set a cookie like this

c2

Setting an expire date

So that’s all well and good but if we actually want to store an OAuth token we want the cookie to be valid for no longer than the token itself. So then we have to set an expire date when we create the cookie. This is achieved like this:

function setCookie(value, duration) { 
  var now = new Date();
  var time = now.getTime();
  var expireTime = time + 1000*duration;
  now.setTime(expireTime);
  document.cookie = 'OAuthToken='+value+';expires='+now.toGMTString()+';path=/';
}

And in FireBug we can see this in action – in this case we set the cookie for 10 seconds, and immediately log it to the console

c3

and then more than 10 seconds later we just test the document.cookie and the OAuthToken is gone

c4

OAuth token generation

When requesting the OAuth token for O365, the token returned is valid for 3600 seconds (an hour). So if we cache the cookie for an hour it will be a good indication (by its existence) that it is still valid. If there is no cookie – we have to get a new token.

Conclusion

In this article we have seen how through the use of the browser’s cookies, we are able to potentially store data. In a future article we will look at how to store and reuse an OAuthToken

 

 

Simplifying O365 Outlook client Add-In Authorization without C#

In this article I will demonstrate a simple method for getting an Authorization into and Outlook Add-in without writing any C# code. I will also highlight some of the problems involved and how the solution elegantly overcomes this.

Introduction

In the previous article we looked at how the How the example O365 Authorized CORS application works and in that example is a location.href change which works just fine within a web browser, but fails badly as an outlook client Add-in.

When the example CORS application is packaged and deployed as a client Add-in it appears to work until you click the “Get Token Button”. The location.href change causes an Internet Explorer window to open, where you can log in……but the end result is you being in an Internet Explorer Window and the token is not in the Outlook Add-in.

A recognized way to solve this issue 

Simon Jaeger has written a number of excellent articles on how to create Outlook Add-ins through Visual Studio and writing some C#

http://simonjaeger.com/developing-outlook-add-ins-where-to-integrate-and-what-you-can-do/

http://simonjaeger.com/building-a-good-authentication-flow-in-an-office-add-in/

The guys in my team tell me that those are a pretty sweet solution to the problem, but my problem is I am not a C# developer and have no desire to become one.

What Simon’s code did do though, was was to inspire me to try something different.

Solving the problem without C#

As I understand it Simon’s example opens an authentication window and then passes the authentication token back to the Add-In via SignalR

 // Show prompt in a new window
    window.open(redirectUri.replace("signalrid", signalrId), "",
        "menubar=0,location=1,resizable=1,scrollbars=0,status=0,toolbar=0,width=550,height=600");

But it struck me that the window.open opens the possibility for the open window to communicate with the opener. (Yeah I know that’s a dumb sentence but it is accurate).

So I put it to the test. I created a button on my sample index.html and made the deployment as an add-in

c1

The code on the button – dead simple – open the window on itself (it really doesn’t matter which site)

<button onClick="window.open('https://xomino365.azurewebsites.net/o365/index.html')">Open Window</button>

Looking at the open window we can bring up developer tools and use the console to test if window.opener is null.

c3

and it isn’t.

So then let’s do a test – let’s see if we can manually stick a value back into the opener……and it did !!

c4

Well in that case we are all sorted !!

Modifying the example code

I am modifying my existing code for the sake of a consistent story, this is not how you would do it in production.

  • If the index.html opens and window.opener is not null I call the function to requestToken() automatically.
  • The page reloads
  • If the page loads detects that we have a token, and we have a window.opener, it
    • Sends the token back to the Outlook client Add-In
    • Hides all the buttons
    • Clicks the Make CORS Request button automatically
    • Closes the popped up window
            if (window.opener){
                window.opener.document.getElementById("TxtOauthToken").value = token;
                window.opener.document.getElementById("doCors").style.visibility = "visible";
                window.opener.document.getElementById("doCors").click()
                window.opener.document.getElementById("getToken").style.display = "none";
                window.close()
            }

And that’s it – the user either sees a quick popup and then the Add-In gets the data from SharePoint. If they have not checked the “keep me logged in” box, or have had their login expire, they see a log in screen where they authenticate with O365 SharePoint, the window then closes and runs in the Add-In.

c5

Conclusion

In this article we have seen how to use a window.open from within our Outlook Add-in to be able to create an Authorization token which can be passed back to the Add-In and used to get Cross-Domain SharePoint data from O365.

In a future article I will streamline this code to create something which can be used for just authorization and is not the same webpage as the Add-In.

 

PS

If you have never done this before you may be prompted with the following dialog – which MAY come up in the background as well. You need to (and tell your users to ) check the box and Allow this in the future.

c2

PPS

I also discovered that you can use WebSockets to transfer data “into” the Outlook Client Add-In. This turned out to be unnecessarily complex and raises some security concerns – but – makes for some excellent ideas for future Add-In functionality ideas.

Two ways to remove a Napa developed Office Add-in

In this article I will show the two methods available for removing a Napa developers plugin from your mail file.

Introduction

As I was developing some Add-ins using Napa I unwittingly deleted them from my dev site not thinking about the consequences – well then I had to deal with them…..

Deleting a development Add-in

So let’s say we created a new Add-in and you delete it from the Napa interface

j2

and then you realize it is still attached to your mail (doh)

j1

you need to manage you own Add-ins

Managing your own Add-ins

Top right – Gear > Manage Add-ins

j3

j4

Select the one to remove and click on the (-) icon above the grid

j5

And there you have it – pretty simple.

j6

Now here’s the “Better” way of doing it

DON’T delete it from the front page of the napa interface

Within the napa developer IDE for the project, right under the Run Project icon there is a “Retract App” icon – use that instead

j7

So then Jeff still exists in your development IDE but not inside your email. Much more elegant.

Conclusion

In this article we have seen two methods for removing a Napa developed add-in from your email client(s)

 

Creating your first custom Outlook Add-in

In this article we will look at how to modify the sample Add-in app and make it do something other than the sample app.

Introduction

In the previous articles we have looked at how to create a sample app, how it works and how to make it contextual. In this article we will make the sample Add-In actually link to something useful.

Bluemix Websockets chat

A while ago I created a sample websockets chat demo – https://xominosocket.mybluemix.net/. It is hosted on IBM’s Bluemix PaaS cloud and uses Socket.io ontop of a node.js server. The back end application runs an in-memory data cache using Redis.

None of which is anything in the slightest to do with Microsoft! Which is the main reason I picked it (the fact that I am lazy and it was just sitting out there as a great example already has nothing to do with it….)

Modifying the sample app

In this article we are going to make a few simple changes to the sample app Home.html which will make the Bluemix Chat demo appear contextually within a email.

Admittedly this is a bit of a hack but hey – it is just a demo.

  • I removed App.js, App.css, Home.js and Home.css – don’t need them
  • I removed the contents of the Body of Home.html and replaced it with an iframe pointing at the websockets demo.
  • I added a little styling to make it seamless
    and ran it

n9

 

n10

As far as the user is aware – we now have a websockets chat application embedded within their Outlook email. The Websockets chat is fully functional within the context of the email.

n11

Marky’s Use Cases #1: Helpdesk support Add-in

So there is an application for this Add-in technology. A “Contact the Helpdesk” link within a business email which would facilitate pulling up a web chat session with a helpdesk representative. The context of the email from whence it was created could be passed to the helpdesk and they would then be able to assist the user.

How cool is that 🙂

Conclusion

In this article we have seen how to insert a completely non-Office application, contextually within an email which only contains the word websockets.