Dukeatcoding
Dukeatcoding

Reputation: 1393

Angularjs handling 401 Errors application wide

I am struggling a little bit with handling 401 errors application wide.

Some other posts where not really helping me: Angularjs - handling 401's for entire app 401 unauthorized error handling in AngularJS

I have to send an authentication token, if it is defined on every request, thats why I need a request part in the Interceptor.

My current approach looks like:

module.factory('authInterceptor', function ($rootScope, $q, $window, $location) {
  return {
    request: function (config) {
      config.headers = config.headers || {};
      if ($window.sessionStorage.token) {
        config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
      }
      else{
          console.log("authInterceptor: No Token to send")
      }
      return config;
    },
    response: function (response) {
      if (response.status == 401) {
          console.log("No Logged In");
         $location.path('/login');
      }
      return response || $q.when(response);
    },
    responseError: function(rejection){

                var defer = $q.defer();

                if(rejection.status == 401){
                    console.log("401 Rejection");
                    console.dir(rejection);
                }

                defer.reject(rejection);

                return defer.promise;

            }

  };
});

As far as my debugging goes if a 401 happens after request, it will be handled in the repsonse function. Which itself gives way a promise to the original caller.

If i comment out $q.when(response) and only return the repsonse there is no change.

Response is called even before the original caller gets .error

Thx for any ideas. Hopefully I am not to far away from a solution.

Upvotes: 2

Views: 3726

Answers (4)

Benny
Benny

Reputation: 4321

If you have Devise in the stack; it's most likely failing because Warden takes precedence over anything else. The headers won't be inserted; even though you use a before_action instead of after_action.

Check out this question instead: ttp://stackoverflow.com/questions/11177079/how-to-send-cors-headers-with-devise-if-user-not-authorized-401-response

Upvotes: 0

kns
kns

Reputation: 23

@frankmt thanks a lot! Not enough rep to upvote or comment your solution, anyways it is exactly what I had missed. With Express and CORS it would be..

//   THE CORS BLOCK HAS TO GO BEFORE THE JWT BLOCK
app.options('*', cors());
app.use(cors());


//protect  routes with JWT - Token based auth
var secret = 'env.SECRET';
var publicPaths = [ '/apply', '/login'];

app.use('/', expressJwt({secret: secret}).unless({path: publicPaths}));

Upvotes: 0

frankmt
frankmt

Reputation: 133

I had the same issue, and in my case the problem was that I was adding the CORS headers as an after filter in the response, which meant that they weren't being sent when a 401 was issued.

Not sure what type of server you are using, but this is the rails version that works for me (changing it to a before_filter:

before_filter :allow_cors

def allow_cors
  headers['Access-Control-Allow-Origin'] = '*'
  headers['Access-Control-Allow-Methods'] = 'POST, PUT, GET, OPTIONS'
  headers['Access-Control-Allow-Headers'] = 'Accept, Cache-Control, Referer, User-Agent, Origin, X-Requested-With, X-Prototype-Version, Content-Type, accept, autho
  headers['Access-Control-Allow-Credentials'] = 'true'
  headers['Access-Control-Request-Method'] = '*'
  headers['Access-Control-Max-Age'] = '1728000'
end

(Clearly these are quite permissive settings, so please adjust them before using it in production)

They way I've managed to find this out was by testing the request locally with CURL, so this might help you:

curl -H "Origin: http://example.com" --verbose http://localhost:3000/

This way you will be able to see if the headers are being returned correctly even when the request is not authorized.

Upvotes: 2

Jscti
Jscti

Reputation: 14450

Your approach is good.

I think you don't need the "response" interceptor, only "request" to inject token and "responseError" to handle 401 response error :

return {

    'responseError': function(response) {

        if (response && response.status === 401) {
            //DO WHAT YOU WANT HERE
            console.log("There was a 401 error");
        }

        return $q.reject(response);
    },

    'request': function(config) {
        config.headers = config.headers || {};
        // ADD YOUR HEADER HERE
        return config || $q.when(config);
    }
};

Upvotes: 0

Related Questions