AngularJS Interceptors for secure page management

I recently started working with AngularJS and I'm facing an issue with my interceptor that catches 401 errors from server responses.

When a 401 status is detected, it triggers a "loginRequired" message broadcast and redirects to the login page. However, there's a brief moment where the restricted page flashes before the redirection occurs. I'm still learning about asynchronous operations and promises, so I'd appreciate any guidance on what I might be doing wrong.

Here's the simplified version of my interceptor code:

var app = angular.module('app', []);

app.factory('myInterceptor', ['$q', '$rootScope',
  function($q, $rootScope) {

    var myInterceptor = {

      'responseError': function(rejection) {
        $rootScope.$broadcast('event:loginRequired');
        return $q.reject(rejection);
      }
    };

    return myInterceptor;
  }
]);

Injecting my interceptor:

app.config(['$httpProvider', function($httpProvider) {
  $httpProvider.interceptors.push('myInterceptor');
}]);

Restricted page route:

.when('/restrictedPage', {
  templateUrl: 'partials/restrictedPage.html',
  controller: 'RestrictedPageController'
}).

Restricted page controller:

app.controller('RestrictedPageController', function($scope) {

  //Alert message sometimes appears, sometimes not
  alert("Oops, shouldn't be here");

});

$rootScope event listener:

$rootScope.$on('event:loginRequired', function() {

  //Only redirect if we aren't on the free access page
  if ($location.path() == "/freeAccess")
    return;

  //Redirect to the login page otherwise
  $location.path('/home').replace();

});

The flashing issue seems to be related to how I handle the interceptor and promises. I came across another approach on GitHub, but it deviates from the official documentation method. While it works without the page flash, I prefer using the factory approach for cleanliness. Any insights on resolving this would be greatly appreciated!

Alternative approach found on GitHub:

var interceptor = ['$rootScope', '$q', '$log',
  function(scope, $q, $log) {

    function success(response) {
      return response;
    }

    function error(response) {
      var status = response.status;

      if (status == 401) {
        var deferred = $q.defer();
        var req = {
          config: response.config,
          deferred: deferred
        };
        scope.$broadcast('event:loginRequired');
        return deferred.promise;
      }
      // Otherwise
      return $q.reject(response);

    }

    return function(promise) {
      return promise.then(success, error);
    };

  }
];
$httpProvider.responseInterceptors.push(interceptor);

My goal isn't just to find a quick fix; I want to understand and improve my code. Thank you for your help!

Answer №1

To avoid sending a broadcast for 'event:loginRequired' from your interceptor, consider handling the location path change directly within the interceptor. Broadcasting may introduce a delay between receiving the 401 error and changing the location, potentially causing a screen 'flash' effect.

services.factory('myInterceptor', ['$q', '$rootScope', '$location',
  function($q, $rootScope, $location) {

    var myInterceptor = {

      'responseError': function(rejection) {
         if (rejection.status === 401 && $location.path() !== '/freeAccess') {
           // Redirect to login page
           $location.path('/home').replace();
         }
         // Otherwise
         return $q.reject(rejection);
      }
    };

    return myInterceptor;
  }
]);

Another approach is to make an HTTP request when your app module initializes to immediately check if the user is authorized:

myApp.config(['$httpProvider', function($httpProvider) {
  $httpProvider.interceptors.push('myInterceptor');
}])
.run(function($http) {
  // If this returns 401, your interceptor will be triggered
  $http.get('some-endpoint-to-determine-auth'); 
});

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

What are the steps for running app.js deployed on a remote server using the local bash terminal?

After launching my web application on GoDaddy, which is built in Node.js, I have encountered a dilemma. In order to run app.js, I currently rely on my computer's bash command prompt. However, this poses an issue - if I were to shut down my laptop, the ...

Any suggestions on how to incorporate the variable into the inline JavaScript [[]] API path?

I have a query regarding creating a URL in JavaScript, but I'm unsure how to include variables within th:inline="javascript". Below is my code snippet: <script th:inline="javascript"> $(function() { $('#querySubmit').click(queryS ...

What is the best choice for UI design framework when creating an ERP web application?

I am in the process of creating a web-based ERP application using Angular Material. However, I've noticed that each input element takes up a significant amount of vertical space on the page. This means if I have 15 input elements, I have to scroll dow ...

Requesting data asynchronously using AJAX and displaying the filtered results on a webpage using JSON

When I send a request to my node.js server for a .json file containing person information (first name, last name), I want the data to be filtered based on user input. For example: When I request the .json file from the server, it gives me a list of people ...

Intranet User Interface Developed with AngularJS

When utilizing ASP.Net Web API service, I am able to retrieve the current Windows user using the code snippet below. public class UserController : ApiController { public string Get() { var id = WindowsIdentity.GetCurrent(); retu ...

When the value is removed, it does not revert back to the initial filtered choices

After clearing the input, I want to display all the original li's again. The issue is that even though .value = '' clears the input, the filter remains active. I could really use some help with this as it's starting to get on my nerves ...

Error encountered while building with Next.js using TypeScript: SyntaxError - Unexpected token 'export' in data export

For access to the code, click here => https://codesandbox.io/s/sweet-mcclintock-dhczx?file=/pages/index.js The initial issue arises when attempting to use @iconify-icons/cryptocurrency with next.js and typescript (specifically in typescript). SyntaxErr ...

Tips for implementing X-XSS-Protection: 1; mode=block in HTML

I'm struggling with where to place this piece of code in my existing code. Should it be added to the header section? <head> <meta content="text/html; charset=UTF-8; X-Content-Type-Options=nosniff" http-equiv="Content-Type" /> <title> ...

Initiate and terminate server using supertest

I've developed a server class that looks like this: import express, { Request, Response } from 'express'; export default class Server { server: any; exp: any; constructor() { this.exp = express(); this.exp.get('/' ...

Control the HTML button's state according to the information received from the server

I am currently working with datatable Jquery and using an ajax call to retrieve data from the server. Let's assume that the database consists of three attributes: "Attribute1, Attribute2, Status". Depending on the Status attribute, I need to enable or ...

Although there may be some issues with tslint, the functionality is operating smoothly

I am in the process of learning tslint and typescript. Currently, I am facing an issue that I need help with. Could you provide guidance on how to resolve it? Despite conducting some research, I have been unable to find a solution. The relevant code snippe ...

A groundbreaking algorithm engineered to launch a sequence of distinct hyperlinks upon each button press

I have a unique script that allows me to open links randomly, but now I want to create a new script that opens links sequentially and goes back to the initial one. For example, clicking a button will open link1, then clicking it again will open link2, an ...

Node.js console and endpoint are returning an object, but the JSON object cannot be fetched

Currently, I am working on a project for an online course where I am utilizing an NLP sentiment analysis API. Although I have made significant progress, I seem to be stuck at the final step. When I send the URL for analysis via the API call, I can see the ...

The ExpressJS Req.method TypeError occurs when attempting to read the 'method' property of an undefined object

My node express server is throwing an error: Error in index.js. const bodyParser = require('body-parser'), express = require('express'), path = require('path'); const config = require('./config'); con ...

Is there a way to trigger a function with the onclick event in NextJs?

Working on my NestJS project, I am still a beginner in the field. My current task involves creating a web application that displays a leaflet map with clickable tiles. Each tile should have a button that triggers a specific function when clicked. However, ...

Sending a JSON object from JSP to JavaScript using AJAX

Is there a way to transfer JSON values from JSP to JavaScript as an object using AJAX without resorting to global JavaScript variables, which can expose the JSON content in the page's source? The desired scenario is as follows: The JSP URL is opene ...

Utilizing Facebook's JavaScript SDK to transmit variables to PHP using ajax

Thank you in advance for your attention. I am trying to utilize the Facebook js SDK to retrieve the user's name and id, and then send them to PHP on the same page (index.php). After successfully obtaining the username and id and storing them in two Ja ...

Using EJS to Render a Function Expression?

Has anyone been able to successfully render a function call in express using EJS? Here's what I've tried so far: res.render("page", { test: test() }); Can someone confirm if this is possible, or provide guidance on how to call a function fr ...

Find the variance between the initial time and the present time, as well as the final time and the current time

If a user logs in before the start time of a game, they will receive a message indicating that the game will start in 01h:10m:23s. If the user logs in after the start time but before the end time, they will see a message stating that the game closes in 0 ...

Running multiple web applications with different base directories on a single Express server

I am currently working on serving a website that requires different static directories for various routes. When a GET request is sent to the /tools* route, I want to utilize the /dist/toolsApp/ directory as the base directory for my frontend code. If ...