47

I'd like to implement authentication on a single page web app with Angular.js. The official Angular documentation recommends the using of interceptors:

$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
  return {

    // ...

    'responseError': function(rejection) {
      // do something on error
      if (canRecover(rejection)) {
        return responseOrNewPromise
      }
      return $q.reject(rejection);
    }
  };
});

The problem is when the server sends 401 error, the browser immediately stops with "Unauthorized" message, or with login pop-up window (when authentication HTTP header is sent by the server), but Angular can't capture with it's interceptor the HTTP error to handle, as recommended. Am I misunderstanding something? I tried more examples found on web (this, this and this for example), but none of them worked.

3
  • Did you ever get this figured out? I'm having the exact same issue Commented Sep 25, 2014 at 7:16
  • Same here, none of the answer works, the interceptor does work, but the exception still throws before the interceptor. Is this weird ? Commented Jan 6, 2015 at 23:08
  • I have tried so many things, I still cannot catch a 401. Where you able to do it with just an interceptor? (for some reason, it gets translated to a 404) @windmaomao Commented Jan 9, 2015 at 21:52

4 Answers 4

65

For AngularJS >1.3 use $httpProvider.interceptors.push('myHttpInterceptor');

.service('authInterceptor', function($q) {
    var service = this;

    service.responseError = function(response) {
        if (response.status == 401){
            window.location = "/login";
        }
        return $q.reject(response);
    };
})
.config(['$httpProvider', function($httpProvider) {
    $httpProvider.interceptors.push('authInterceptor');
}])
Sign up to request clarification or add additional context in comments.

3 Comments

'responseError' is the thing to do. For good measure, note that there is also 'requestError'.
wonderful answer! its a generic functionality, once you unauthorized it'll redirect to login.
Finally, this works!!! I was originally using "response" instead of "responseError" which was causing my interceptor functionality to not be executed.
29

in app config block:

var interceptor = ['$rootScope', '$q', "Base64", function(scope, $q, Base64) {
  function success(response) {
    return response;
  }

  function error(response) {
    var status = response.status;
    if (status == 401) {
      //AuthFactory.clearUser();
      window.location = "/account/login?redirectUrl=" + Base64.encode(document.URL);
      return;
    }
    // otherwise
    return $q.reject(response);
  }
  return function(promise) {
    return promise.then(success, error);
  }
}];

4 Comments

responseInterceptor no longer supported in 1.3
In 1.3 it is bound as follows: $httpProvider.interceptors.push('interceptor');
It didn't work for me on Angular 1.5. I had to use Igor S. approach below
8

I don't know why, but response with 401 error goes into success function.

'responseError': function(rejection)
                {
                    // do something on error

                    if (rejection.status == 401)
                    {
                        $rootScope.signOut();
                    }

                    return $q.reject(rejection);
                },
                'response': function (response) {
                    // do something on error
                    if (response.status == 401) {
                        $rootScope.signOut();
                    };
                    return response || $q.when(response);
                }

2 Comments

'responseError' was very helpful :-)
I also have found 401s ending up in response rather than responseError. Angular 1.5.3. EDIT: Looks like it may be due to a 3rd party lib I'm using, http-auth-interceptor. even though I've specified this particular request should be ignored by that lib, it seems it's still causing the 401 to not pipe through responseError.
7

AngularJS interceptors only work for calls made with the $http service; if you navigate to a page that returns a 401, AngularJS never even runs.

3 Comments

This depends on what you call navigation. A full load of a page (window.location) will indeed not trigger the interceptor. But a navigation to another route in the app will, because the route templates are fetched using the $http service.
In that case you can use: .$on("$locationChangeStart", function (event, next, current) { And .$on("$locationChangeSuccess", function (event, next, current) {
If you make a $http request to a server and returns 401, Angular has nothing to do with it, and developer should decide what to do; In the case of this question, he might want to redirect the user to a new route or even maybe remove auth token on both sides.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.