[Vuejs]-Adal.js not setting props in localStorage

0๐Ÿ‘

Active Directory Authentication Library for JavaScript (ADAL JS) helps you to use Azure AD for handling authentication in your single page applications. This library is optimized for working together with AngularJS.

It will not save the tokens into the cache unless we code it. You can check the relative code from adal-angular.js. Here is a piece of code for your reference:

The saveTokenFromHash method will also save the tokens into cache and this function will execute after the page redirect back to the Angular app.

adal.js:

AuthenticationContext.prototype.saveTokenFromHash = function (requestInfo) {
    this._logstatus('State status:' + requestInfo.stateMatch);
    this._saveItem(this.CONSTANTS.STORAGE.ERROR, '');
    this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, '');

    // Record error
    if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION)) {
        this._logstatus('Error :' + requestInfo.parameters.error);
        this._logstatus('Error description:' + requestInfo.parameters[this.CONSTANTS.ERROR_DESCRIPTION]);
        this._saveItem(this.CONSTANTS.STORAGE.FAILED_RENEW, requestInfo.parameters[this.CONSTANTS.ERROR_DESCRIPTION]);
        this._saveItem(this.CONSTANTS.STORAGE.ERROR, requestInfo.parameters.error);
        this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, requestInfo.parameters[this.CONSTANTS.ERROR_DESCRIPTION]);

        if (requestInfo.requestType === this.REQUEST_TYPE.LOGIN) {
            this._loginInProgress = false;
            this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR, requestInfo.parameters.errorDescription);
        } else {
            this._renewActive = false;
        }
    } else {

        // It must verify the state from redirect
        if (requestInfo.stateMatch) {
            // record tokens to storage if exists
            this._logstatus('State is right');
            if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.SESSION_STATE)) {
                this._saveItem(this.CONSTANTS.STORAGE.SESSION_STATE, requestInfo.parameters[this.CONSTANTS.SESSION_STATE]);
            }

            var keys, resource;

            if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.ACCESS_TOKEN)) {
                this._logstatus('Fragment has access token');
                // default resource
                this._renewActive = false;
                resource = this.config.loginResource;
                if (!this._hasResource(resource)) {
                    keys = this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS) || '';
                    this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS, keys + resource + this.CONSTANTS.RESOURCE_DELIMETER);
                }

                if (requestInfo.requestType === this.REQUEST_TYPE.RENEW_TOKEN) {
                    resource = this._getResourceFromState(requestInfo.stateResponse);
                }

                // save token with related resource
                this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + resource, requestInfo.parameters[this.CONSTANTS.ACCESS_TOKEN]);
                this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource, this._expiresIn(requestInfo.parameters[this.CONSTANTS.EXPIRES_IN]));
            }

            if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.ID_TOKEN)) {
                this._loginInProgress = false;
                this._user = this._createUser(requestInfo.parameters[this.CONSTANTS.ID_TOKEN]);
                if (this._user && this._user.profile) {
                    if (this._user.profile.nonce !== this._getItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN)) {
                        this._user = null;
                        this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR, 'Nonce is not same as ' + this._idTokenNonce);
                    } else {
                        this._saveItem(this.CONSTANTS.STORAGE.IDTOKEN, requestInfo.parameters[this.CONSTANTS.ID_TOKEN]);

                        // Save idtoken as access token for app itself
                        resource = this.config.clientId;
                        if (!this._hasResource(resource)) {
                            keys = this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS) || '';
                            this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS, keys + resource + this.CONSTANTS.RESOURCE_DELIMETER);
                        }
                        this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + resource, requestInfo.parameters[this.CONSTANTS.ID_TOKEN]);
                        this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource, this._user.profile.exp);
                    }
                }
            }
        } else {
            this._saveItem(this.CONSTANTS.STORAGE.ERROR, 'Invalid_state');
            this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, 'Invalid_state');
            if (requestInfo.requestType === this.REQUEST_TYPE.LOGIN) {
                this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR, 'State is not same as ' + requestInfo.stateResponse);
            }
        }
    }
};

And this function will be called in this.$get like below:

// special function that exposes methods in Angular controller
// $rootScope, $window, $q, $location, $timeout are injected by Angular
this.$get = ['$rootScope', '$window', '$q', '$location', '$timeout', function ($rootScope, $window, $q, $location, $timeout) {

    var locationChangeHandler = function () {
        var hash = $window.location.hash;

        if (_adal.isCallback(hash)) {
            // callback can come from login or iframe request

            var requestInfo = _adal.getRequestInfo(hash);
            _adal.saveTokenFromHash(requestInfo);
            $window.location.hash = '';

            if (requestInfo.requestType !== _adal.REQUEST_TYPE.LOGIN) {
                _adal.callback = $window.parent.AuthenticationContext().callback;
            }

            // Return to callback if it is send from iframe
            if (requestInfo.stateMatch) {
                if (typeof _adal.callback === 'function') {
                    // Call within the same context without full page redirect keeps the callback
                    if (requestInfo.requestType === _adal.REQUEST_TYPE.RENEW_TOKEN) {
                        // Idtoken or Accestoken can be renewed
                        if (requestInfo.parameters['access_token']) {
                            _adal.callback(_adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters['access_token']);
                            return;
                        } else if (requestInfo.parameters['id_token']) {
                            _adal.callback(_adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters['id_token']);
                            return;
                        }
                    }
                } else {
                    // normal full login redirect happened on the page
                    updateDataFromCache(_adal.config.loginResource);
                    if (_oauthData.userName) {
                        //IDtoken is added as token for the app
                        $timeout(function () {
                            updateDataFromCache(_adal.config.loginResource);
                            $rootScope.userInfo = _oauthData;
                            // redirect to login requested page
                            var loginStartPage = _adal._getItem(_adal.CONSTANTS.STORAGE.START_PAGE);
                            if (loginStartPage) {
                                $location.path(loginStartPage);
                            }
                        }, 1);
                        $rootScope.$broadcast('adal:loginSuccess');
                    } else {
                        $rootScope.$broadcast('adal:loginFailure', _adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION));
                    }
                }
            }
        } else {
            // No callback. App resumes after closing or moving to new page.
            // Check token and username             
            updateDataFromCache(_adal.config.loginResource);
            if (!_adal._renewActive && !_oauthData.isAuthenticated && _oauthData.userName) {
                if (!_adal._getItem(_adal.CONSTANTS.STORAGE.FAILED_RENEW)) {
                    // Idtoken is expired or not present
                    _adal.acquireToken(_adal.config.loginResource, function (error, tokenOut) {
                        if (error) {
                            $rootScope.$broadcast('adal:loginFailure', 'auto renew failure');
                        } else {
                            if (tokenOut) {
                                _oauthData.isAuthenticated = true;
                            }
                        }
                    });
                }
            }
        }

        $timeout(function () {
            updateDataFromCache(_adal.config.loginResource);
            $rootScope.userInfo = _oauthData;
        }, 1);
    }
...

And here is a sample code which could save the tokens into cache for your reference:

<html>
<head>
 <script src="https://unpkg.com/vue"></script>
 <script src="node_modules\adal-angular\lib\adal.js"> </script>
 <script src="config.js"> </script>
</head>

<body>
<div>
  <button onclick="login()" >Login</button>
</div>
   <script>

var authContext=new AuthenticationContext(config);
function login(){
authContext.login();

}

function init(configOptions){
  if (configOptions) {
                    // redirect and logout_redirect are set to current location by default
                    var existingHash = window.location.hash;
                    var pathDefault = window.location.href;
                    if (existingHash) {
                        pathDefault = pathDefault.replace(existingHash, '');
                    }
                    configOptions.redirectUri = configOptions.redirectUri || pathDefault;
                    configOptions.postLogoutRedirectUri = configOptions.postLogoutRedirectUri || pathDefault;


                    // create instance with given config                 
                } else {
                    throw new Error('You must set configOptions, when calling init');
                }

                // loginresource is used to set authenticated status
                updateDataFromCache(authContext.config.loginResource);

}

 var _oauthData = { isAuthenticated: false, userName: '', loginError: '', profile: '' };
   var updateDataFromCache = function (resource) {
                // only cache lookup here to not interrupt with events
                var token = authContext.getCachedToken(resource);
                _oauthData.isAuthenticated = token !== null && token.length > 0;
                var user = authContext.getCachedUser() || { userName: '' };
                _oauthData.userName = user.userName;
                _oauthData.profile = user.profile;
                _oauthData.loginError = authContext.getLoginError();
            };

init(config);

function saveTokenFromHash(){
    var hash = window.location.hash;
     var requestInfo = authContext.getRequestInfo(hash);
       if (authContext.isCallback(hash)) {
                        // callback can come from login or iframe request

                        var requestInfo = authContext.getRequestInfo(hash);
                        authContext.saveTokenFromHash(requestInfo);
                        window.location.hash = '';

                        if (requestInfo.requestType !== authContext.REQUEST_TYPE.LOGIN) {
                            authContext.callback = window.parent.AuthenticationContext().callback;
                        }                 
                    } 
}

saveTokenFromHash();
    </script>

</body>
</html>

Leave a comment