Obtain an Office 365 OAuth token from within an Office Add-in without pop-ups or dialogs

In this article I will describe a simple process for generating and storing an O365 token from within an Office Add-in.

Introduction

In the previous article  I described the github project and sample code for creating and getting an Office 365 OAuth Token for use in an Office Add-in. This was an improvement on the previously accepted method for getting a token which required additional services and knowledge of C#. The biggest issue encountered was that the normal OAuth Token process when you log into Office365 takes you through multiple domains. When this happens in the Office Client Add-ins the user is thrown into a separate Internet Explorer. The generated token can then no longer be passed to the Add-in for programmatic use.

This article described how the issue has been overcome and the release of the new simplified code.

The same approach, but a new approach

As discussed in this article it is possible to access more than one domain within an Add-in by adding the additional domains to the Add-In manifest.

If we follow the OAuth process for Office 365 authorization we can see that there are two domains which are used:

We initially request access from “https://login.windows.net/common/oauth2/authorize? ” and then get redirected to “https://login.microsoftonline.com ” before getting sent back to the original.

To solve the issue at hand we add those two domains to the manifest in the following manner

  <AppDomains>
    <AppDomain>https://login.windows.net</AppDomain>
	<AppDomain>https://login.microsoftonline.com</AppDomain>
  </AppDomains>

In the github repo I have actually posted a complete sample manifest file for you to see.

The code 

d3

The code for the Authorization is relatively simple. The Home.js code is triggered when the page loads. If the location.href of the Add-In contains the access_token then we move to app.returnToken(). if not then we “getToken”.

//Home.js
(function () {
    'use strict';

    // The Office initialize function must be run each time a new page is loaded in the Add-In
    if (location.href.split("access_token").length < 2){
        Office.initialize = function (reason) {
            $(document).ready(function () {
                //check to see if there is an OAuth Token cached in the cookie
                //app.addinName will need to be different for every Add-In
                var token = app.getCookie(app.addinName)
                if (!token) {
                    var tokenParams = {};
                    tokenParams.authServer = 'https://login.windows.net/common/oauth2/authorize?';
                    tokenParams.responseType = 'token';
                    tokenParams.replyUrl = location.href.split("?")[0];

                    //THESE tokenParams need to be changed for your application
                    tokenParams.clientId = 'Your-app-clientId-goes-here';
                    tokenParams.resource = "https://yoursite.sharepoint.com";

                    app.getToken(tokenParams);
                } else {
                    //we have a token therefore carry on
                    app.tokenCallback(token)
                }
            });
        };
    } else {
        //The window has the access_token in the URL
        $(document).ready(function () {
            app.returnToken();
        });
    }
})();

The important parts of the App.js code are the getToken and returnToken. Within getToken(tokenParams) we parse out the incoming object and redirect the user to the login screen part of the process using location.href. The reason for having a Home.js separate from App.js is really for clarify.

//App.js
//...
    app.getToken = function (tokenParams) {

        var url =   tokenParams.authServer +
                    "response_type=" + encodeURI(tokenParams.responseType) + "&" +
                    "client_id=" + encodeURI(tokenParams.clientId) + "&" +
                    "resource=" + encodeURI(tokenParams.resource) + "&" +
                    "redirect_uri=" + encodeURI(tokenParams.replyUrl);

       // var winObj = window.open(url);
       // winObj.focus();
        location.href=url;
    };
//...

Putting this all together, when accessing the Add-in for the first time, the user now sees the login screens within the Add-in


o1

o2

And then once logged in the user is sent back to the original screen but with the Authorization token appended to the URL

o3

The returnToken() part of the application parses the incoming URL, extracts the Token and then inserts it into the page for display. The token is then stored in a cookie for 1 hour. This is the length of time the Authentication token is valid. The next time the user opens the Add-in within the hour the token will be stored and accessible.

//App.js
//...
app.returnToken = function(){
        var urlParameterExtraction = new (function () {
            function splitQueryString(queryStringFormattedString) {
                var split = queryStringFormattedString.split('&');

                // If there are no parameters in URL, do nothing.
                if (split == "") {
                    return {};
                }

                var results = {};

                // If there are parameters in URL, extract key/value pairs.
                for (var i = 0; i < split.length; ++i) {
                    var p = split[i].split('=', 2);
                    if (p.length == 1)
                        results[p[0]] = "";
                    else
                        results[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
                }
                return results;
            }

            // Split the query string (after removing preceding '#').
            this.queryStringParameters = splitQueryString(window.location.hash.substr(1));
        })();

        var token = urlParameterExtraction.queryStringParameters['access_token'];

        if (token){
            app.tokenCallback(token)
        } else {
            document.write("Shame")
        }
        /*if (window.opener){
            window.opener.app.tokenCallback(token);
            window.close()
        } else {
            document.write("There appears to have been an error, please close the window and check with your administrator")
        }*/

    }

	app.tokenCallback = function(token){
		//this would then continue to do what you really need in the Add-In
        document.getElementById('tokenHere').innerHTML = token
	}
//...

Sample code only

The code displayed in this example is for example only. It is there to demonstrate the process and return the token. What you then do with the token is up to you 🙂

Conclusion

In this article we have seen how we can create an Office 365 OAuth token with the minimum of impact on the user. They have to log into the Add-in within the Outlook client and the disruption on the User Experience is minimal.

 

Advertisements

Using more than one domain inside of an Office Add-In

In this article I am going to introduce the  <AppDomains> parameter within an Office Add-In Manifest. Using this parameter we are going to see how you can change the URL within an Add-In and consider the possibilities that brings us.

Introduction

I was casually reading through the thrilling “Office Add-ins XML Manifest” (http://dev.office.com/docs/add-ins/overview/add-in-manifests) and I came across this casual comment:

By default, if your add-in tries to go to a URL in a domain other than the domain that hosts the start page (as specified in the SourceLocation element of the manifest file), that URL will open in a new browser window outside the add-in pane of the Office host application. This default behavior protects the user against unexpected page navigation within the add-in pane from embedded iframe elements.

To override this behavior, specify each domain you want to open in the add-in window in the list of domains specified in the AppDomainselement of the manifest file. If the add-in tries to go to a URL in a domain that isn’t in the list, that URL will open in a new browser window (outside the add-in pane).”

This was the exact problem I had when I came up with the O365Token solution on how to Authenticate an Add-in to O365 and ended up using a window.open() solution. When I tried to do the OAuth redirect it failed because it opened a whole new Internet Explorer instance which did not communicate with the Add-in parent.

The published solution works but is a somewhat poor user experience due to the Internet Explorer window opening up. But hey it worked so I went with it.

The problem demonstrated
I am demonstrating this issue using firebuglite in one of my existing Add-ins. I change the location.href of the Add-in (in Outlook) and the requested website opens up in a fresh Internet Explorer window.

d1

d2

Proof of concept

I created a simple addition to my manifest file:

  <AppDomains>
    <AppDomain>https://login.windows.net</AppDomain>
	<AppDomain>https://login.microsoftonline.com</AppDomain>
  </AppDomains>

I uploaded the new file through the Exchange admin portal, refreshed it for the user and tested it again

d3

d4

and look at that – it opened within the Add-in without issue.

Conclusion

In this article I have demonstrated how using the  <AppDomains> parameter within the manifest file we are able to change the website loaded within the Add-in

Next – how do we re-write the O365Token to load nicely in this window?

How to create Dynamic Workflow functionality in Outlook Add-Ins based on unique keys

In this article I will demonstrate how to use a regular expression to provide dynamic contexual assignment of an Outlook add-in. Using that regular expression we will be able to identify the necessary information to link the Add-In to some external dynamic workflow functionality.

Introduction

During the Collab365 presentation I demonstrated a workflow application which was a simple vacation request approval. In that demonstration I showed how we are able to detect a unique key inside of an email and then use that value to open the workflow within the add in (https://youtu.be/t6kRFV09TYs?t=1950).

In previous articles I have demonstrated how to create a contextual add-in and in this article we will look at how we can take that up a notch and make the context dynamic and useful.

I am going to demonstrate the capability in the context of a napacloud add-in so that you are able to work along.

Messing with RegEx

Regular Expressions are a weird an wonderfully powerful capability, generally reserved for people way smarter than me to figure out. Fortunately there are many example sites which can be used to help you figure out how you should build your regular expression.

I used http://scriptular.com/ which allowed me to test my regular expression until I made it work.

We need to create a unique key within out email so that it can be picked up by Outlook. We cannot use an existing URL though because there is already functionality associated with that.

r2

Using regular expressions in an Office Add-in

Inside of the napacloud tooling we are able to play with adding a regular expression to the context of the Add-In.

r1

So I insert my regular expression into the box, save and run. In this case (for demonstration I make the number of characters fixed to be 6)

r3

Test Email

I created a simple test email with a few expressions which COULD match……and when the Add-In runs – only only of the links is highlighted

r4

So now what?

Well what we want to happen is when the user clock on that Workflow Id: Ac9sXP link we want to take them to the right page within our Application (surfaced through the Add-In).

Within the Office.initialize we are able to determine functionality which happens when the user selects the Add-In. I used the same regular expression to match the desired Workflow Id

Office.initialize = function (reason) {
        $(document).ready(function () {
            Office.context.mailbox.item.body.getAsync(
		  "text",
		  { asyncContext:"This is passed to the callback" },
		  function callback(result) {
		    // Do something with the result
			var str = result.value; 
			var res = str.match(/Workflow\sId:\s[0-9|a-z|A-Z]{6}/g).toString();      				
			$("#content-main").html("The RegEx matched is---> "+res)
		  });
        });
    };

When you run the sample in the browser you get this

r5

More advanced

Once you have this string in JavaScript you can do a number of things with it, the two most obvious to me are:

  • Create an iFrame within the application and add the WorkflowID to the Query String
  • If you have an angular application you can then route the user to the correct document using the WorkflowID

Conclusion

In this article I showed how to create a contextual addin using a semi-complex Regular Expression. Then using that exposed value from the email we can surface dynamic functionality for the user.

The Code

I have posted the code from this sample napacloud out on GitHub for anyone who wants to download it an play with it

You can find it here:

https://github.com/markyroden/RegExInOutlookAddIn

 

Combining Blogs – Office 365 content incoming

As some of you are no doubt aware, 7 months ago I started a new blog at https://www.xomino365.com and I have been posting there about my experiences and what I have learned about Office 365 and integrating it with Domino and other applications. I created a separate blog to keep my IBM and MS lives separate because I initially saw them as separate aspects of my work life. I called the xomino365 blog the “taking my skills on tour” blog because I was very stubborn and refused to learn C#. What I found was that Microsoft has created a suite of tools which you would frankly not believe were Microsoft. In Redmond they have embraced the web and open source technologies, something which would have been unheard of years ago. I was able to write everything I needed to in the MS world using JavaScript, CSS and HTML.

It has been quite the success for me. Over 30 blog posts since November 2015. While it has not exactly got recognized in overall number of reads (1300), the exposure has been excellent. Creating the blog and learning the examples has given me the ability to speak at ICONUS and Collab365 for which I am very grateful.

It has become abundantly clear to me that there is really no need to separate both halves of my work life and therefore I am bringing them together into what is the older, more high profile blog (this one). I will continue to reblog O365 articles to the xomino365.com site but will not be posting any more unique content there.

I will continue to post IBM related blogs here as well, it is not as if my life is not full of XPages applications on a daily basis as well. I took my skills on tour and I found them very applicable, so I am bringing it back home and we will see where this goes next.

 

 

“Office 365 Add-Ins – a web developer’s playground” – presentation from Collab365 conference now live

Last week I presented at my first non-IBM conference and it was a total blast. At PSC, we see a number of customers who are doing mail migrations who still need to integrate their remaining business critical systems with Office 365. Office Add-Ins, especially in the context of mail and workflow are a great way to look at this integration problem.

The collab365 conference required me to prerecord the presentation and it was streamed at the agenda time. This allowed me to sit in the side chat and talk to the people watching the presentation. This increased interaction and with hindsight I should have worked it more.

This recording is similar to the presentation I gave at ICONUS and Engage.ug this year, but not specifically focused on XPages/Domino integration. The XPages/Domino examples are all in here though and also an example of integration with Watson Tone analysis.

All the presentation from the Collab365 conference are now available and can be accessed here – you will need to create a free registration to get at them all.

https://collab365.conferencehosts.com/confs/Summit2016

Hope you enjoy, there is a lot to learn and a lot of interesting possibilities with the new Office Add-In model.

 

Having trouble logging into whatever.IBM.com – Could be Cookie overload…

Recently I have been having significant issues getting into IBM websites (Connections Cloud, Bluemix, PartnerWorld etc) and it seems to be because of too many cookies. I am just leaving this here for anyone who thinks they might have a similar issue. I have heard of multiple people also having the same issue recently.

  1. If you can’t get in but all your friends can
  2. If you get unauthorized messages but you don’t get a log in screen

c3

Solution

Check in Incognito mode / Private mode / Porno Mode (or whatever you want to call it) and see if your link works. If it does then it is probably cookies.

From an IBM.com webpage,

  • in Chrome hit F12 and open developer tools
  • Resources
  • view all the cookies

c2

  • select the top one and start hitting DELETE DELETE DELETE and get rid of them all
  • F5 / refresh
  • and you are working again

c1

 

There are resources/tool for clearing cookies in browsers but this is pretty quick.

In Internet Explorer

F12

c4

 

Update

Thanks Eric !

Blisk – a web developer’s browser – first impressions

xomino to 365

On the twitternet last Friday afternoon I saw this thing called “Blisk – a web developer’s dream come true” and frankly that sounds like fun !

http://mashable.com/2016/05/13/blisk-web-browser

and that lead me to “https://blisk.io/“. This is a record of my first interaction with it and see how it goes. This is not a review – this is just a record of OOOO shiney in action !!

Installation

I downloaded it – I am not entirely sure that is asked me if I wanted do anything after I ran the installer…..Windows only right now apparently.

Start up

I loaded it up and started to type in the addressbar and it already knew my Chrome browser history 😱

b1

A nice handy start screen shows me the rapidly approaching features…

b2

b2b3b4b5b6b7b8b9b10

Loading up a responsive website

I loaded up one of my demo sites and was able to display it Real site, side by side with mobile iPhone

bb1

and  iPad

View original post 167 more words