401 unauthorized error handling in AngularJS

29.2k views Asked by At

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.

4

There are 4 answers

1
Nery Jr On

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);
});
1
Pedro Paulo Nery On

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);
  };
});
0
DrogoNevets On

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

0
Joel Duckworth On

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