17

I'm very newbie in AngularJS, and now spending 3 days in finding a way to handle 401 status. I've tried interceptors, using $http, using $resource...but nothing is working. My app calls JSONP call on the same server. when error occurs it is caught in error callback function. but the status is always 0 and the response is undefined.

First, I tried this interceptor

app.config(['$httpProvider', function($httpProvider) {
$httpProvider.responseInterceptors.push(['$q', function($q) {
    return function(promise) {
        return promise.then(function(response) {
            console.log('success in interceptor');
            return response; 
        }, function(response) {
            console.log('error in interceptor');
            console.log(response);
            if (response.status === 401) {
                response.data = { 
                    status: false, 
                    description: 'Authentication required!'
                };
                return response;
            }
            return $q.reject(response);
        });
    }
}]);
}]);

Second, also tried in controllers using $resource

  $scope.fetchData = function(fromDate, toDate){
        Cancel.get({from: fromDate, to: toDate, perPage: 99999},
                    function(data){                            
                      $scope.cancels  = $scope.filteredCancels = data.data;
                      $scope.search();
                    },
                    function(response) {
                      $scope.errorMessage = '<h4>Error : '+response.status+'</h4>';
                      window.location = "/";
                    });              
      }; 

Third, tried using $http instead of $resource

  $scope.fetchData = function(fromDate, toDate){
     $http.jsonp('http://host:8900/api/cancellations?callback=JSON_CALLBACK')
         .success(function(data, status, headers, config) {
             console.log(status);
          })
         .error(function(data, status, headers, config) {
             console.log(status);              
          }; 

Here is header information for the JSONP call

Request URL:http://host:8900/api/cancellations?callback=angular.callbacks._0
Request Method:GET
Status Code:401 Unauthorized
Request Headersview source
Accept:*/*
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6
Cache-Control:max-age=0
Connection:keep-alive
Cookie:__utma=149207145.339724205.1374885003.1377550245.1378313049.3; __utmc=149207145; __utmz=149207145.1378313049.3.2.utmcsr=cyphersmart.qc3deva.electricmail.com:8900|utmccn=(referral)|utmcmd=referral|utmcct=/; remember_username=elie.kim%40electricmail.com; PHPSESSID=gdoemlp5jltqq62etc5gfuh653; cookie=cookiecheck; __utma=1.789184132.1378340585.1378499390.1378504453.10; __utmb=1.3.10.1378504453; __utmc=1; __utmz=1.1378340585.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Host:host:8900
Referer:http://host:8900/reports/cancels/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 Chrome/25.0.1364.160 Safari/537.22
Query String Parametersview sourceview URL encoded
callback:angular.callbacks._0
Response Headersview source
Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection:keep-alive
Content-Type:application/json; charset=utf-8
Date:Fri, 06 Sep 2013 22:02:13 GMT
Expires:Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive:timeout=20
Pragma:no-cache
Server:nginx/0.7.65
Transfer-Encoding:chunked

I couldn't find a way to handle the unauthorized status 401, I tied all the things though. It would be very appreciated if I can get a tip or kind advice.

Sam
  • 15,336
  • 25
  • 85
  • 148
Elie Kim
  • 171
  • 1
  • 1
  • 4
  • if you navigate to your URL in the browser, what happens? – akonsu Sep 07 '13 at 00:10
  • What version of angular are you using? This is important because the `responseInterceptors` changed in 1.2 – TheSharpieOne Sep 07 '13 at 02:14
  • @TheSharpieOne my version is v1.0.6. is it the reason? – Elie Kim Sep 09 '13 at 21:20
  • @akonsu it catches any ajax error except 200 or 300. what I'm sufferfing is why it can't catch 401 status code. – Elie Kim Sep 09 '13 at 21:26
  • Found the reason why AngularJs doesn't catch 401 status, it isn't supposed to catch 401 when it calls JSONP request. As soon as change the method to 'GET', it catches well. – Elie Kim Sep 18 '13 at 19:54
  • My Backbone experience with JQuery didn't have any issues in catching 401 status; it means $.ajaxSetup can catch 401, but AngularJs can't. Is it right? – Elie Kim Sep 18 '13 at 19:58
  • Possible duplicate of [Capture HTTP 401 with Angular.js interceptor](https://stackoverflow.com/questions/21230417/capture-http-401-with-angular-js-interceptor) – BlackICE Jan 09 '19 at 11:40

4 Answers4

9

The accepted answer doesn't work for later versions of angular. Using 1.5.x (and maybe even earlier) you need to write the interceptor differently:

// http interceptor to handle redirection to login on 401 response from API
app.factory('httpResponseInterceptor', ['$q', '$rootScope', '$location', function($q, $rootScope, $location) {
    return {
        responseError: function(rejection) {
            if (rejection.status === 401) {
                // Something like below:
                $location.path('signin/invalidSession');
            }
            return $q.reject(rejection);
        }
    };
}]);

Apply with:

app.config(function($httpProvider) {
    $httpProvider.interceptors.push('httpResponseInterceptor');
});

See here for further information https://docs.angularjs.org/api/ng/service/$http#interceptors

Joel Duckworth
  • 5,455
  • 3
  • 20
  • 21
4

i needed to do very similar recently, here is my interceptor

app.factory("HttpErrorInterceptorModule", ["$q", "$rootScope", "$location",
    function($q, $rootScope, $location) {
        var success = function(response) {
            // pass through
            return response;
        },
            error = function(response) {
                if(response.status === 401) {
                    // dostuff
                }

                return $q.reject(response);
            };

        return function(httpPromise) {
            return httpPromise.then(success, error);
        };
    }
]).config(["$httpProvider",
    function($httpProvider) {
        $httpProvider.responseInterceptors.push("HttpErrorInterceptorModule");
    }
]);

modified slight for your use case

DrogoNevets
  • 1,456
  • 3
  • 18
  • 34
3

In case of any API call returns 401 we have to redirect user to login page. Angular’s HTTP interceptor is great for that job. As you can see from app.js above, it’s been pushed to pipe here:

httpProvider.responseInterceptors.push('httpInterceptor');

The interceptor implementation itself,

'use strict';

angular.module('dashboardApp').factory('httpInterceptor', function httpInterceptor ($q, $window, $location) {
  return function (promise) {
      var success = function (response) {
          return response;
      };

      var error = function (response) {
          if (response.status === 401) {
              $location.url('/login');
          }

          return $q.reject(response);
      };

      return promise.then(success, error);
  };
});
2

Follows a similar solution ...

angular.module('myApp', ['myApp.services', 'myApp.directives'], function ($routeProvider, $locationProvider, $httpProvider, $location) {

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

        function success(response) {
            return response;
        }

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

            if (status == 401) {
                $location.url('/login');
                return;
            }

            return $q.reject(response);

        }

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

    }];
    $httpProvider.responseInterceptors.push(httpInterceptor);
});
Nery Jr
  • 3,849
  • 1
  • 26
  • 24