Skip to content
This repository has been archived by the owner on Jun 26, 2021. It is now read-only.

Digest iterations infinite loop in HTML5 mode #42

Closed
ruddles opened this issue Nov 18, 2014 · 58 comments
Closed

Digest iterations infinite loop in HTML5 mode #42

ruddles opened this issue Nov 18, 2014 · 58 comments

Comments

@ruddles
Copy link

ruddles commented Nov 18, 2014

If I add the library to a project that uses html5mode and enter a URL with a # on the end (e.g. http://localhost:9000# or http://localhost:9000/# ) the developer console is battered with errors:

Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []

If I turn off html5mode or remove the adalAuthenticationServiceProvider.init call in app.js then everything is fine. I've had a quick look through but I cannot see what's causing it. I've added a sample at https://github.com/ruddles/ADALIssue which you can clone, npm install && bower install, grunt serve and then test the app by opening the developer console, and add a # to the end of the URL.

I've tested this in both chrome and firefox on a mac.

@omercs
Copy link
Contributor

omercs commented Nov 18, 2014

Did you try to add $locationProvider.hashPrefix('!');
We will look into repro. Thank you for sharing that.

@ruddles
Copy link
Author

ruddles commented Nov 19, 2014

Unfortunately the hashprefix doesn't fix the issue, I've just given it a go.

@omercs omercs self-assigned this Nov 25, 2014
@brphelps
Copy link

brphelps commented Dec 1, 2014

Can we get an update on this? it seems to interfere with the token renewal portions of ADAL as well, so it's next to impossible to get a token for, say, AD graph. A workaround or ETA would be swell.

@omercs
Copy link
Contributor

omercs commented Dec 1, 2014

Angular is triggering endless redirects if you specify your default route to be "/". Related angular issue: angular/angular.js#1417

In your app, you can fix this issue with using a name for default route. Following change works for your app(https://github.com/ruddles/ADALIssue )

$routeProvider
      .when('/home', {
        templateUrl: 'views/main.html',
        controller: 'MainCtrl'
      })
      .when('/about', {
        templateUrl: 'views/about.html',
        controller: 'AboutCtrl'
      }).        
    otherwise({ redirectTo: '/home' });
     ;

instead of using "/" as default path.

@brphelps, @ruddles Let me know if this works for you.

@vibronet
Copy link
Contributor

vibronet commented Dec 1, 2014

also note, today getting a token for the graph not have much use given that the graph does not support CORS. I believe it is in their roadmap, but they did not share times.

@brphelps
Copy link

brphelps commented Dec 9, 2014

I experimented with some of the suggested solutions, and wasn't seeing success. Relatively speaking, I'm an angular newbie and had an existing project dropped on me. However, I did spend some time debugging and found the culprit:
$window.location.hash = '';
in adal.js.
If I comment this line out, the problem dissipates. Maybe the timing of the hash = '' operation or the transport mechanism for the token should be different?

@omercs
Copy link
Contributor

omercs commented Dec 9, 2014

@brphelps : what is the main page address? Is default path "/"?

@omercs
Copy link
Contributor

omercs commented Jan 8, 2015

I will close this. If you repro after following the suggestions, please open again.

@omercs omercs closed this as completed Jan 8, 2015
@brphelps
Copy link

brphelps commented Apr 6, 2015

Any chance this issue could be revisited? It looks like there are some strong assumptions about how routing is done to fix, it would be nicer to just have a real fix that didn't involve ng-route specific stuff.

@gkiely
Copy link

gkiely commented May 15, 2015

@omercs I've experienced this same issue.

@bpatra
Copy link
Contributor

bpatra commented May 22, 2015

@omercs same issue for me, thus the '.otherwise' workaround worked. Thanks.

@drGarbinsky
Copy link

I am still experiencing a similar issue. Any guidance on how to resolve this would be very helpful.

http://stackoverflow.com/questions/30768562/app-is-re-initializing-the-first-time-adal-protected-url-is-accessed-via-http

The mitigation steps mentioned above to use a named default route have no impact on the issue.

@absqueued
Copy link

I too tried with the default route way, didn't work. Anyway I am not using HTML5 mode yet I have this issue. As soon as office returns after loggin in - I see this error.

Strange thing is, when I reload (F5), this issue goes away.

image

@barisbikmaz
Copy link

The problem still exists in html5Mode when adal tries to get the tokens for the first time. All methods in my constructors are excuted 10 times because of the infinite digest loop. You can reproduce the issue if you clear all adal stuff from localStorage and load the page

$routeProvider .when('/', { templateUrl: 'main/main.html', requireADLogin: true }) .otherwise( { redirectTo: '/' });

@martellaj
Copy link
Contributor

Y'all should open this issue back up for awareness, given that it's a work item for someone now.

@venkateshappala
Copy link

Any fix is available for this?

@tushargupta51 tushargupta51 self-assigned this Mar 4, 2016
@tushargupta51 tushargupta51 reopened this Mar 4, 2016
@martellaj
Copy link
Contributor

@venkateshappala Don't rely on it... look at when this issue was opened.

@PavelPikat
Copy link

We did something like this to address the issue:

$rootScope.$on('$locationChangeStart', function (e) {
                if ($location.path().indexOf('access_token') > -1 ||
                    $location.path().indexOf('id_token') > -1) {
                    e.preventDefault();
                }
            });

We've also added similar checks for id_token and access_token in our $urlRouterProvider.otherwise function

@nigel-dewar
Copy link

I am having this issue too. Cannot solve it. Tried LOTS of different things. I am using ui-router.

cheers

@gabbsmo
Copy link

gabbsmo commented Mar 31, 2016

Was this solved with this PR? It is currently merged to dev. 60b6639

@jonfreberg
Copy link

jonfreberg commented May 2, 2016

@tushargupta51
Values from before the endless loop starts:

userInfo.profile.nonce: 2cce876e-fc24-4afc-9acf-0b5fa2cda89b
adal.nonce.idtoken: 2cce876e-fc24-4afc-9acf-0b5fa2cda89b

I will provide those two after the loop starts as well. So thats the two nonce's adal checks that are equal? And if not, the adal.login.error gets set in the session storage?

No, I'm not using an .otherwise route for now, just to exclude that. This is my setup:

$stateProvider
.state("private", {
abstract: true,
template: ""
}).state("private.utility", {
url: "/utility",
templateUrl: "app/views/utility.html",
requireADLogin: true
});

@jonfreberg
Copy link

Because of the endless loop, the developer tools refreshes so I cant get too the userinfo object to see the nonce value.

@gabbsmo
Copy link

gabbsmo commented May 2, 2016

@jonfreberg You can check "preserve log" in the Chrome console and console.log(userinfo) from your code.

@talismax
Copy link

talismax commented May 3, 2016

I have the same issue. I have basically the simplest possible Angular/ADAL app with no routing:

'use strict';
angular.module('app', ['AdalAngular', 'wj'])
.config(['$httpProvider', 'adalAuthenticationServiceProvider', function ($httpProvider, adalProvider) {

    var endpoints = {
        "https://localhost:44347": "https://something.com/myapi"
    }
    adalProvider.init({
        instance: 'https://login.microsoftonline.com/',
        tenant: 'something.onmicrosoft.com',
        clientId: '[my client id],
        endpoints: endpoints
    }, $httpProvider);
}]);

'use strict';
angular.module('app')
.controller('appCtrl', ['$scope', '$http', 'adalAuthenticationService', function ($scope, $http, adalService ) {

    $scope.login = function () {
        adalService.login(); 
    }

    $scope.logout = function () {
        adalService.logOut(); 
    }
}]);

As soon as I login I get the errors:
image

@adamauckland
Copy link

adamauckland commented May 4, 2016

Jumping in because I've managed to solve the "Nonce is not the same as" problem with a workaround:

Looking in the DOM inspector, I can see that there are multiple ADAL renew token iframes nested. I believe what is happening is that the iFrame is renewing the token and ending up back at index.html therefore starting a new version of the app.

This new app then periodically tries to renew the token out of sync with the parent. Because they share the same context the GUIDS are overwriting in sessionstorage.

I have worked around this problem by detecting if the app is inside an iframe as part of the bootstrap process, then ONLY starting up angular-adal and not loading any of my other app modules. It seems to solve the infinite looping problem.

HOWEVER: this does not solve the infdig issue on a brand new instance of the app which happens consistently unless I comment out $window.location.hash = ''; on line 88 of adal-angular.js

  if ($location.$$html5) {
                            $window.location = $window.location.origin + $window.location.pathname;
                        } else {
                            //$window.location.hash = '';
                        }

oddly, if I set the token store to localstorage, this also fixes it, but I don't want to use localStorage for security reasons.

@jonfreberg
Copy link

Thanks for the reply @adamauckland !

Could you give a little more details on how you only start up angular-adal if the app is inside an iFrame in the bootstrap process?

@adamauckland
Copy link

Yep, @jonfreberg. It's really not anything clever. Conceptually, we just create the primary module differently depending on if we're the top frame or not like this:

if (window.self === window.top) {
    angular.module('app', [
        // the full list of all modules goes here
    ]);
} else {
    angular.module('app', [
         'AdalAngular',
    ]);
}

Obviously the actual implementation has a bit more checking around it, but that's the principle.

@jonfreberg
Copy link

jonfreberg commented May 10, 2016

Thanks @adamauckland . I'll give it a go.
What version of angular, adal and adal-angular are you using?

My versions:
angular: 1.3.15
adal-angular: 1.0.9

I've updated all my packages now, so I'm at this moment testing with versions:
angular: 1.5.5
adal-angular: 1.0.10

@adamauckland
Copy link

@jonfreberg

Angular 1.4.7
AdalJS v1.0.10
adal-angular v1.0.10

@fairmutex
Copy link

fairmutex commented Jun 6, 2016

Can someone put an example together that works? Since I am having big trouble with these bugs

@tushargupta51
Copy link
Contributor

We have Pull Requests submitted that will address the issues mentioned here:

  1. App reloading on token renewal. Please see Page reloads 3 or 4 times after log-in #151 for more details.
  2. Digest iterations: This issue can be caused due to multiple reasons in an angular app. One of the main reasons, adal users were hitting this was the update to location.hash using $window.location. I have updated that to use $location.hash for both html5 and non-html5 modes. That should fix the locationChangeStart digest iterations.

These PRs will be merged soon. I will the close the issue then. If you still run into this issue, let us know, we can re-visit this.

@fairmutex
Copy link

I have tried all the work arounds suggested here and nothing is working. Can someone put together a sample app that works? It will help me and new comers to the problem as well.

@jjalfaro
Copy link

Hi, I'm also having same issues here I already try all the possible sugestions that I found and nothing works. Someone was able to male this work fine, that can give me some hints to see if I can make it work.

thanks!

@jjalfaro
Copy link

Yes I try it out it is giving me the same error, this is if I run it on IE
11, if I run it on Chrome it blocks completely the browser

[image: Inline image 1]

On Wed, Jul 13, 2016 at 12:31 PM, tushar gupta notifications@github.com
wrote:

@jjalfaro https://github.com/jjalfaro have you tried this:
https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/FAQs#q2-my-app-gets-into-an-infinite-loop-sometimes-leading-to-digest-iterations-error


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#42 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AB8PN3yI0Y8YClpL8afOoKxWNhX_pux1ks5qVRLvgaJpZM4C9Kuw
.

@tushargupta51
Copy link
Contributor

We have released 1.0.11 with fixes to some of the digest iterations issue. Please use 1.0.11 and have a look here if you are still running into this issue: https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/FAQs#q2-my-app-gets-into-an-infinite-loop-sometimes-leading-to-digest-iterations-error

@jjalfaro I am closing this issue for now but feel free to open a new issue with the details: logs, traces if you still experience the loop with the new release.

@dgodwin1175
Copy link

dgodwin1175 commented Apr 7, 2017

I was facing this digest iterations issue with version 1.0.0.
I worked around it by setting the $window.location.hash = '' as already mentioned, however this meant that my token would only renew on route changes, but I need it to renew as required.
So I decided to update to the latest version (1.0.14), but now, I'm in a different kind of infinite loop.
When launching my app, Chrome locks up and then runs out of memory. This actually starts happening for me from v1.0.9 onwards. Has anyone seen this before? All I've done is swap out the two js files!

@nigel-dewar
Copy link

nigel-dewar commented Apr 7, 2017 via email

@dgodwin1175
Copy link

Yes I certainly am, and I'd really prefer not to have to rip it out. Have you managed to resolve or at least find the root cause?

@nigel-dewar
Copy link

nigel-dewar commented Apr 7, 2017 via email

@dgodwin1175
Copy link

Pls post when you can. No need to do it on your Friday night! Thanks so much.

@nigel-dewar
Copy link

Ok mate, managed to fire up laptop inbetween dinner.

Here is what you need to do

In your Angular run block you need to do this.

$rootScope.$state = $state;
var isAdalFrame = window !== window.parent;
    $rootScope.$on('$locationChangeStart', function (e) {
        if ($location.path().indexOf('access_token') > -1 ||
            $location.path().indexOf('id_token') > -1 ||
            $location.path().indexOf('/error=') === 0 ||
            isAdalFrame
        ) {
            e.preventDefault();
        }
    });

so if your angular run might look like this

angular.module('app').run('runBlock');

function runBlock($rootScope, $location, $state) {
$rootScope.$state = $state;
var isAdalFrame = window !== window.parent;
$rootScope.$on('$locationChangeStart', function (e) {
if ($location.path().indexOf('access_token') > -1 ||
$location.path().indexOf('id_token') > -1 ||
$location.path().indexOf('/error=') === 0 ||
isAdalFrame
) {
e.preventDefault();
}
});
}

Secondly you will need to do this

In your route code, (most likely in your routeConfig class), instead of doing this $urlRouterProvider.otherwise('/');

You will need to do this

$urlRouterProvider.otherwise(
function ($injector, $stateParams) {
var isAdalFrame = window !== window.parent;
var $state = $injector.get('$state'),
$$path = $stateParams.$$path,
$$url = $stateParams.$$url,
$log = $injector.get('$log');

               if ($$path) {
                   if (($$path.indexOf('id_token') !== -1 &&
                       $$url.indexOf('id_token') !== -1) ||
                       ($$path.indexOf('access_token') !== -1 &&
                       $$url.indexOf('access_token') !== -1) ||
                       $$path.indexOf('/error=') !== -1) {
                       // Do nothing if we have adal's token in the url
                   } else if (!isAdalFrame) {
                       $state.go('home');
                   }
               }
               else if (!isAdalFrame) {
                   $state.go('home');
               }
           });

Make your default route 'home' or something like that.

What is happening, is ui-router does not play nice with adal.js. I have found no version of adal.js does.
Without these changes, things get thrown into a nasty loop like you have found.
I did spend some time trying to identify exactly what it was, but in the end I found the code just work and so I settled with it.

Give it a shot and let me know how you go! Hope it works for you mate. I have found it works ok.

@dgodwin1175
Copy link

It doesn't appear to work, the browser hangs on this piece of code from angular.js, before my .otherwise() function is called:
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
function bootstrapApply(scope, element, compile, injector) {
scope.$apply(function() {
element.data('$injector', injector);
compile(element)(scope);
});
}]
);
return injector;
};

@nigel-dewar
Copy link

nigel-dewar commented Apr 10, 2017 via email

@dgodwin1175
Copy link

I'm using angular 1.5.8
ui-router 2.18
adal.js/adal-angular 1.0.14

@nigel-dewar
Copy link

nigel-dewar commented Apr 10, 2017 via email

@dgodwin1175
Copy link

Hi Nigel,
I decided to update to latest, but it didn't help. I'm still caught in an infinite loop, before the initial login redirection even takes place. Any luck with your sample using the above versions?

I'm now using these.
angular 1.6.4
ui-router 0.4.2

I'm tempted to try swapping out the ui-router for the angular-router.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests