One of my SharePoint add-in single page application had some interesting behavior when using a direct link to a specific page. After authentication, the URL fragment (hash) has been completely removed from the URL. Which caused the app to open the default page.
This was not the behavior I was looking for and I was also curios why this was happening. This behavior was only happening when I’m logging-in onto Windows Azure/Office 365 for the first time. When the user is already authenticated, the direct URL to the App where working like expected.
Looking deeper into the authentication process that Office365 is using, I now understand why this is happening. Office365 (and many others) are using OpenID Connect which is based on OAuth2. This is a widely used authentication method used by Microsoft, Google, Facebook, �.
More in-depth information about OpenID Connect can be found in the FAQ on the openid website.
The reason why in this case the URL fragments are removed has all to do with the authentication flow. When the user is accessing the App and needs to be authenticated, the App sends the user to the authentication server. After you authenticated, the authentication server sends the user back to the App URL including the access token in the URL fragment. And this is why your own URL fragment is lost.
Sending the access token in the URL fragment is done on purpose and in fact a security mechanism (Implicit Flow Threats?). As you know the changing of a URL fragment is not causing a request back to the webserver. Even better, the complete URL fragment is never send by the browser to the webserver. The client access token is never written into the webserver logs. So this is a secure place to communicate the access token back to the browser. And client side scripting can use this token for communicating directly with the secure services.
Getting things to work
Now we know this, we need to somehow provide the URL data to the App. A few option you have:
- The most obvious is not using the URL fragments for page routing. But not in all cases this is a solution. Definitely when you are using the single page application technique;
- Send the state of the App with the request for authentication (recommended by OpenID Connect); After authentication read the state from the response; and go where you have left off (You could do a page refresh to get the preferred URL);
- Change the URL. When the user is not authenticated, change the callback URL to include a value in the query string. After authenticated read the response URL query string and go where you have left off (You could do a page refresh to get the preferred URL).????