401 unauthorized error handling in AngularJS
Asked Answered
E

4

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.

Eruptive answered 6/9, 2013 at 22:52 Comment(7)
if you navigate to your URL in the browser, what happens?Shaquana
What version of angular are you using? This is important because the responseInterceptors changed in 1.2Livonia
@Livonia my version is v1.0.6. is it the reason?Eruptive
@Shaquana it catches any ajax error except 200 or 300. what I'm sufferfing is why it can't catch 401 status code.Eruptive
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.Eruptive
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?Eruptive
Possible duplicate of Capture HTTP 401 with Angular.js interceptorRespective
P
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

Phenobarbitone answered 30/6, 2016 at 6:47 Comment(0)
D
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

Dactylogram answered 30/4, 2014 at 14:33 Comment(0)
S
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);
  };
});
Sinusitis answered 27/1, 2015 at 8:47 Comment(1)
how do you show the user when redirecting to location.path(/login) the reason why he was logged out?Erlina
O
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);
});
Oversight answered 27/1, 2015 at 8:35 Comment(1)
$httpProvider.interceptors.push("HttpErrorInterceptorModule");Humes

© 2022 - 2024 — McMap. All rights reserved.