User authentication on AngularJs is only initiated on the second interaction

My personally built AngularJs user authentication system is experiencing an unusual issue. While everything seems to be working fine - I can login, check access for specific pages, etc. - there is a strange behavior with the token authentication. It seems to only run properly on the second interaction with the WebApp.

For instance, if I modify some data in localStorage (where user data is stored) and then try to access an admin page, it allows me to enter. But during the next interaction, I suddenly get redirected back to the login process.

I'm puzzled by this situation. The code I am using is as follows:

app.js

function getUser() {
    userinfo = JSON.parse(localStorageService.get("user")); //convert string to json
    $scope.userData = userinfo; //Display purpose only;
};
function checkToken() {
    var userCheckToken = JSON.parse(localStorageService.get("user"));
    $http.post('dist/php/db.php?action=token', userCheckToken)
    .success(function(res){
        userToken = res;
    }).error(function(err){
        alert(feedbackError);
    });
};

$rootScope.$on('$stateChangeStart', function(e, to) {
    if (to.data && to.data.requireLogin) {
        getUser();
        checkToken();
        if (!userinfo) {
            e.preventDefault();
            $state.go('login');
            alert("You need to be logged in");
        }
        else if (userinfo && !userToken) {
            e.preventDefault();
            userInfo = false;
            $state.go('login');
            localStorageService.clearAll();
            alert('Authentication failed');
        }
    }
});

The same issue also arises with individual functions. For example, when trying to execute an important function that requires admin privileges, the authentication process behaves similarly, failing on the first attempt.

Function:

$scope.debugTk = function() {
    checkToken();
    if (!userToken) {
        alert('Authentication failed');
    } else {
        $http.get('dist/php/db.php?action=debugTk')
        .success(function(res){
            $scope.resultDebug = res;
        }).error(function(err){
            alert(feedbackError);
        });
    }
}

Answer №1

It has been mentioned by charlieftl that your checkToken function relies on an asynchronous XHR request by default. To ensure proper execution of checkToken, you must encapsulate it within a callback function like this:

function retrieveUserData() {
    userInfo = JSON.parse(localStorageService.get("user")); //converting string to JSON
    $scope.userData = userInfo; //For display purposes only;
}
function verifyToken() {
    var userCheckToken = JSON.parse(localStorageService.get("user"));
    $http.post('dist/php/db.php?action=token', userCheckToken)
    .success(function(response){
        return response; //Making them chainable inside a promise.
    }).error(function(error){
        return errorMessage;
    });
}

$rootScope.$on('$stateChangeStart', function(event, destinationState) {
    if (destinationState.data && destinationState.data.requireLogin) {
        retrieveUserData();
        if (!userInfo) {
            event.preventDefault();
            $state.go('login');
            alert("You must be logged in");
        } else {
            verifyToken().then(function(userToken){ 

                if (!userToken) {
                    userInfo = false;
                    $state.go('login');
                    localStorageService.clearAll();
                    alert('Authentication failed');
                }
            }, function(error){
                
            });
        }
    }
});

Your debugTk function should then appear as follows: $scope.debugTk = function() { verifyToken().then(function(){ // success }, function(){ // error

        if (!userToken) {
            alert('Authentication failed');
        } else {
            $http.get('dist/php/db.php?action=debugTk')
            .success(function(response){
                $scope.resultDebug = response;
            }).error(function(error){
                alert(errorMessage);
            });
        }
    });
}

To learn more about promises, visit: https://github.com/wbinnssmith/awesome-promises

Edit: The e.preventDefault() method will not work within the promise, prompting the need to adjust your code for promises. It is advised not to include such code within a $stateChangeStart event; instead, utilize a service to manage authentication tasks.

Answer №2

As per the AngularJS documentation:

The previously used legacy promise methods success and error in $http have now been deprecated. It is recommended to utilize the standard then method instead. If $httpProvider.useLegacyPromiseExtensions is set to false, calling these methods will result in a $http/legacy error.

In relation to your query, it has been mentioned that the checkToken function operates asynchronously, hence requiring the use of promises each time this function is invoked. The $http.post result from the checkToken function should be returned:

function checkToken() {
  var userCheckToken = JSON.parse(localStorageService.get("user"));
  return $http.post('dist/php/db.php?action=token', userCheckToken).then(
    function (res) {
      userToken = res;
    },
    function (err) {
      alert(feedbackError);
    });
};

This can then be utilized as a regular promise:

$scope.debugTk = function() {
  checkToken().then(function(){
    if (!userToken) {
      alert('Authentication failed');
    } else {
      //.....
    }
  });
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

AngularJS employs the identical service as the model but with distinct data

As I develop a factory service that offers several functions, here's an example of how it could be structured: var myApp = angular.module('panelServices', ['ngResource']); myApp.factory('myService', [...]{ function m ...

Incorporating PHP in JS/jQuery AJAX for creating unique odd and even conditional layouts

My PHP code includes a loop that changes the layout of elements based on whether the $count variable is odd or even. For odd counts, an image appears on the left and text on the right. For even counts, it's the other way around. To load content dynam ...

Does the notion of "Execution context and the stack" only pertain to web browsers?

Does the concept of "Execution context and the stack" only apply to browsers, or is it also utilized in other environments such as NodeJS? I've crafted 2 statements but unsure if they are accurate: 1- "The environment for JavaScript is not solely the ...

Decorating AngularJS' ExceptionHandler with TypeScript is not feasible because a function is not identified as such

Scenario: In the project I am currently involved in, there has been a transition from utilizing AngularJS (1.6.2) with JavaScript to TypeScript 2.1.5. We had implemented a decorator on the $exceptionHandler service which would trigger a call to a common ...

Withdrawal of answer from AJAX request

Is there a way to create a function that specifically removes the response from an AJAX call that is added to the inner HTML of an ID? function remove_chat_response(name){ var name = name; $.ajax({ type: 'post', url: 'removechat.php ...

How can I effectively display a blank menu item for the SelectField component in Material-UI within a React application?

I am using the select-field component from the material-ui framework version 0.15.4 with React version 15.4.0. I am attempting to add a blank menu-item to the select-field in order to allow for deselecting a value in the dropdown field when clicked. Howeve ...

Create a JavaScript function without attaching it to the global window object

Can someone please help me with defining a function and using it inside Jquery within the $(document).ready block? function addLeadingZero(number) { return (number < 10 ? '0' : '') + number } I'm not confident that I ha ...

Retrieving decimal value from a given string

Currently, I am working with Google Maps and encountering an issue with distance values being returned as strings like 1,230.6 km. My goal is to extract the floating number 1230.6 from this string. Below is my attempted solution: var t = '1,234.04 km ...

Enable autocomplete feature in a PHP form once the user starts typing their name

After searching for similar questions, I couldn't find any with the same "variables," so here's my dilemma: I have a basic form where I input a name and I want the rest of the form to be filled in automatically (ID). Retrieving data from the da ...

Ways to revert all modifications to styles implemented using JavaScript

Hey there, just checking in to see how you're doing. I was wondering if there's a way to reset all the styles that have been changed using JavaScript? I'm referring to the styles shown in this photo: Thanks in advance. ...

Prevent the occurrence of endless looping in serializer (angularjs) by avoiding infinite recursion

Currently, I am working on a RESTful application that involves @OneToMany relationships. The entities in question are Team and Player (where one Team can have many Players, and each Player belongs to only one Team). To prevent infinite recursion, I decid ...

Unable to locate additional elements following javascript append utilizing Chrome WebDriver

I have a simple HTML code generated from a C# dotnet core ASP application. I am working on a webdriver test to count the number of input boxes inside the colorList div. Initially, the count is two which is correct, but when I click the button labeled "+", ...

Tips for Repurposing a React Table

I am in the process of developing my own react component library to be used across my entire application. At the moment, I have started with a table component which is currently undergoing testing. However, I am facing the challenge of calling the componen ...

Capybara with Angular Material Select

Is it possible to use select in RoR RSpec + Capybara? I typically use: select 'something', from: 'select_name' However, this method does not work for Angular's md-select. Capybara displays the following error message: Capybara:: ...

Receiving no communication from Express Router

Having trouble receiving a response from the server after making get/post requests. I've tried adjusting the order of functions in index.js without success. I also attempted to send a post request using Postman to localhost:8080/register, but the requ ...

What steps are involved in integrating QuickBlox on your website?

I am completely new to web development and have a question about integrating QuickBlox into my website using JavaScript. I have included the necessary JavaScript files in my website and set up the QuickBlox admin application, but I'm not sure how to p ...

JavaScript not redirecting to HTML page as expected

I have developed a basic login page that makes an Ajax request to the backend. However, I am experiencing difficulties with redirecting the page upon successful login. The redirect function only seems to work 1 in 15 times, and I'm unsure of the reaso ...

Is it possible for a prop to change dynamically?

I am currently developing a component that is responsible for receiving data through a prop, making modifications to that data, and then emitting it back to the parent (as well as watching for changes). Is it possible for a prop to be reactive? If not, wh ...

javascript - substitute the dash (hyphen) with a blank space

For quite some time now, I've been on the lookout for a solution that can transform a dash (hyphen) into a space. Surprisingly, despite finding numerous responses for changing a space into a dash, there seems to be a scarcity of information going in t ...

The error message received is: "mongoose TypeError: Schema is not defined as

Encountering a curious issue here. I have multiple mongoose models, and oddly enough, only one of them is throwing this error: TypeError: Schema is not a constructor This situation strikes me as quite odd because all my other schemas are functioning prop ...