Error Description

“Response to the preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘https://<<yourazureWebApp.net>>” is therefore not allowed access “

Application Landscape

The application landscape where I have experienced this error is,

Issue

How to fix the Error

The process to fix the error was a bit tricky but not that complicated. The process to fix this issue involved a JavaScript implementation within a Partial View within an Iframe with a sequence of Activities which was

Implementation of the Partial View’s Iframe

  1. Invoke a specific controller to get the current Token Expiry Time
  2. Convert the specific time to UTC
  3. Call another JavaScript function to pass the Token Expiry time to calculate the Refresh time (Refresh Time = Current Token Expiry Time – 15 minutes) considering that the token had to be renewed 15 minutes before the expiry
  4. Ensure to call another controller to force the sign in and issue a new access token
  5. Ensure that the Iframe is refreshed as per the Refresh Time
  6. Utilize the Partial View across various other generic views which require silent token refresh based on Iframe within them

The implementation within the Partial View is as below,

  1. <iframe id="renewSessionIFrameImplementation" hidden></iframe>
  2. <script>
  3. GetTokenExpiryFunction();
  4. //Function that will retreive the current token expiry time
  5. function GetTokenExpiryFunction () {
  6. $.ajax({
  7. type: "POST",
  8. traditional: true,
  9. async: true,
  10. //Invoke the specific controller to retrieve the current issued tokens expiry time
  11. url: "/<<Controller>>/GetCurrentTokenExpirySchedule",
  12. context: document.body,
  13. success: function (result) {
  14. if (result) {
  15. //convert the result from controller to UTC format
  16. var tokenExpiresOnSchedule = ConvertUTCtoLocalTime(result);
  17. //Retrieve the actual refresh interval by passing the current expiry time
  18. RefresIframeImplementation(tokenExpiresOnSchedule);
  19. }
  20. },
  21. error: function (xhr) {
  22. console.log("Error :" + xhr);
  23. }
  24. });
  25. }
  26. function ConvertUTCtoLocalTime(UTCString) {
  27. var newDate = new Date(UTCString);
  28. newDate.setMinutes(newDate.getMinutes() - newDate.getTimezoneOffset());
  29. return newDate;
  30. }
  31. //Function which will renew the token based on refresh interval
  32. function RefresIframeImplementation(CurrentTokenExpiryTime) {
  33. //calculate the refresh interval, in this case will be -15 minutes before token expiry
  34. var refreshTimeIntervel = moment(CurrentTokenExpiryTime).subtract(15, 'minutes').toDate();
  35. //arrive at the time in milliseconds to refresh the Iframe
  36. var milliSecondstoRefresh = refreshTimeIntervel - new Date();
  37. //Invoke the SetInterval function to refresh the IFrame within this view to refresh the token by
  38. //Forecefully signing in
  39. var refreshIframeInterval = setInterval(function () {
  40. @if (Request.IsAuthenticated) {
  41. <text>
  42. //Clear existing refresh interval
  43. clearInterval(refreshIframeInterval);
  44. //Get teh Iframe ID to refresh the current Iframe
  45. var element = window.parent.document.getElementById("renewSessionIFrameImplementation");
  46. //Invoke the controller to renew access token
  47. var renewUrl = "/<<Controller>>/EnsureForcedSignIn";
  48. console.log("sending request to: " + renewUrl);
  49. element.src = renewUrl;
  50. </text>
  51. }
  52. else {
  53. <text>
  54. console.log("No renewal attempt without a valid session");
  55. </text>
  56. }
  57. }, milliSecondstoRefresh);
  58. }
  59. </script>

The Controller (GetCurrentTokenExpirySchedule) Implementation to Get the Current Access Token’s Refresh Time is as below,

  1. public static async Task<string> GetAppUserTokenExpiryDate(string resourceID)
  2. {
  3. string currentTenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
  4. string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
  5. AuthenticationContext authContext = new AuthenticationContext("Azure AD instance & Tenant", new NaiveSessionCache(userObjectID));
  6. ClientCredential credential = new ClientCredential("Your Client ID", "<<Your App Key");
  7. var result = await authContext.AcquireTokenSilentAsync(resourceID, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
  8. if (result == null)
  9. {
  10. return null;
  11. }
  12. return result.ExpiresOn.UtcDateTime.ToString();
  13. }

Note that the resourceID is the Microsoft Graph API URL - https://graph.microsoft.com

The Controller Implementation (EnsureForcedSignIn) to Force issue of new Access Tokens is as below,

  1. public void EnsureForcedSignIn()
  2. {
  3. // Send an OpenID Connect sign-in request.
  4. HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" },OpenIdConnectAuthenticationDefaults.AuthenticationType);
  5. }