I have an $http service that make an API call and I have a transformResponse and error interceptor both attached to every call. In case of errors I can see that transform response gets called first, then followed by an interceptor. I do not want the transformation method to be called for error responses, I want it to skip right to the interceptor. How can I achieve that?
I know that I can put if (response.status != 200) into every transformation method, but I have a lot of these methods and I do not want to do that in each of them.
You probably need to go for Interceptors to play with request response in general.
myApp.factory('authInterceptor', function ($rootScope, $q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
}
return config;
},
response: function (response) {
if (response.status === 401) {
// handle the case where the user is not authenticated
}
return response || $q.when(response);
}
};
});
myApp.config(function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
});
Perhaps it will also be useful
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.transformResponse.unshift(
function (data, headers) {
/* some code*/
return data;
});
}])
Related
I have written an auth interceptor that adds auth token to the request and handles auth errors if the user is not logged in.
var storeApp = angular.module('storeApp');
storeApp.factory('authInterceptor', function ($q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
}
return config;
},
response: function (response) {
return response || $q.when(response);
},
responseError: function (response) {
if (response.status === 401 || response.data.error === 'token_not_provided') {
console.log('auth error');
}
return $q.reject(response);
}
};
});
storeApp.config(function ($httpProvider) {
$httpProvider.defaults.withCredentials = true;
$httpProvider.interceptors.push('authInterceptor');
});
The issue is the auth interceptor is added to every request, regardless the request requires authentication or not. What is the best way to create an auth interceptor that only intercepts when the route requires authentication?
You need the filter out the requests you want in the authInterceptor factory methods
['/whatever/1', '/whatever/2', '/whatever/3'].forEach(function(value){
if (response.config.url.startsWith(value)) {
// do something
}
})
return response;
I implemented jwt stateless in backend , so except login and signup all other method has to intercept in angularjs and sending auth token to server in request header .But token is not sending mean not seeing in reqest header in console(developer tools).
This is my interceptor.js :
/**
*
*/
/* Interceptor declaration */
rootApp.factory('authInterceptor', function ($rootScope, $q, $sessionStorage, $location,$window) {
return {
request: function (config) {
//config.headers['Content-Type'] = 'application/json';
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
//config.headers['x-auth-token'] ='Bearer ' + $window.sessionStorage.token;
}
return config;
},
response: function (response) {
if(response.status === 200){
if(response.data && response.data.success === false){
if($rootScope.authFailureReasons.indexOf(response.data.reason) !== -1){
$location.path('/login');
}
}
}
if (response.status === 401) {
$location.path('/');
}
return response || $q.when(response);
},
'responseError': function (rejection) {
return $q.reject(rejection);
}
};
});
rootApp.config(['$httpProvider', function ($httpProvider) {
// $httpProvider.interceptors.push('headerInterceptor');
$httpProvider.interceptors.push('authInterceptor');
}]);
And service.js file is:
rootApp.service('adminService', function ($rootScope, $http, $q,$window) {
return {
inviteUser: function (user) {
var deferred = $q.defer();
$http({
method: 'POST',
url:$rootScope.baseUrl+'api/v1/admin/user/add',
data:user
}).success(function (response, status, headers, config) {
deferred.resolve(response);
}).error(function () {
// Something went wrong.
deferred.reject({'success': false, 'msg': 'Oops! Something went wrong. Please try again later.'});
});
return deferred.promise;
}
};
});
In server side X-AUTH-TOKEN is allowed in headers too.Where i am going wrong
Please help.
hey I have recently made my first token authentication in my Ionic app .. yeah it is an easy step but implementation may take some time if you are not a language PRO..
you can try this.
https://devdactic.com/user-auth-angularjs-ionic/
this is one of the finest and tested tutorial on the web for token based AUTH..
Maybe that may help you to find the error !
I have this $http call after a user has logged in that get's the users' details. When the user logs in I store the token in user.token which looks like this:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1laWQiOiIzZGMwM2FiOC0wZGFiLTQ1ZGYtYjEwNS03Y2VmNDA4ZjQ4YWQiLCJ1bmlxdWVfbmFtZSI6InIzcGxpY2EiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL2FjY2Vzc2NvbnRyb2xzZXJ2aWNlLzIwMTAvMDcvY2xhaW1zL2lkZW50aXR5cHJvdmlkZXIiOiJBU1AuTkVUIElkZW50aXR5IiwiQXNwTmV0LklkZW50aXR5LlNlY3VyaXR5U3RhbXAiOiI4NGIyMjMzMi1jOTkyLTQ1YjItYWI0Yi1mYzU1YzkzYWU3NjIiLCJyb2xlIjoiQWRtaW5pc3RyYXRvciIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTgxMjciLCJhdWQiOiJkM2U3OWM4MS0xNjNmLTQwMTMtODA2NC0zMDc1OTBhOWMwYmYiLCJleHAiOjE0MzMyNzc2NDIsIm5iZiI6MTQzMzE5MTI0Mn0.erNou7AjihJrp2glS89zNYYFc65mREscGwl45wVUSYA
I then take this token and pass it to an $http call like this:
$http.get('api/users', { headers: { 'Authorization': 'Bearer ' + user.token }, params: { username: model.userName } });
But in fiddler if I examine this call, it changes my token. The request in fiddler looks like this:
Authorization: Bearer cF9xV4hw3psCq2of-wRDn-cRE_IifwzCYyoS-c5Njdk4dGu7EGGQ8Bl_XOr8uEGMAFkxR0paqfCI4Aq17VWP6BDxMZN2Nkk7WIfPLVrilKkMybmGxbOqAKqwl3F1qnEvtlvdgQtdpAqgR6-s1oFU0QemRVaQiyOPbmJwEyfh5mYrNVLuZniPPCvpZvOKKBSpinpCY-vNINI3SYvbZyVpRza18aFJfXy-JgUSN3YZBmg1T4JFjMucCueqAWlulGaDGRc8hAXp7RYnxeUtDO7yOhPzQehjVVxl59Lz461DpsXcZjuEILhlFXbyC4yn24DHIFfLs0_x9DCZwodXaaAwoCmRI_vx8yLpjfoPcmnOR_20lLlWp0pOODOqoKSRxZldnRZO8pbilo_AcYHSCQlyeMPOevvO1bP8yggGdCe_LVQiTNJgzhMccKRcziZqZjPCMw0Kz_OLkR5w2ayS5JTdfA
which is not the token that I passed. Does anyone know why this might be happening?
As Kevin rightly said, I was setting it on my http interceptor. It looked like this:
.factory('AuthInterceptorService', ['$rootScope', '$q', '$location', function ($rootScope, $q, $location) {
// Function to handle a request
var request = function (config) {
// Get the current user
var user = $rootScope.user;
// Get the current headers or an empty object
config.headers = config.headers || {};
// If we have a user
if (user && user.token) {
// Then set the authorization header
config.headers.Authorization = 'Bearer ' + user.token;
}
// Return our config
return config;
};
// Function to handle errors
var responseError = function (rejection) {
// If we have unauthorized access
if (rejection.status === 401) {
// Redirect to our login page
$location.path('/account/login');
}
// Return our rejected promise
return $q.reject(rejection);
};
return {
request: request,
responseError: responseError
};
}])
to fix the issue I just simply put an if statement checking to see if the Authorization header had already been set like this:
.factory('AuthInterceptorService', ['$rootScope', '$q', '$location', function ($rootScope, $q, $location) {
// Function to handle a request
var request = function (config) {
// Get the current user
var user = $rootScope.user;
// Get the current headers or an empty object
config.headers = config.headers || {};
// If we have a user
if (user && user.token) {
// If we don't already have the authorization header set
if (!config.headers.Authorization) {
// Then set the authorization header
config.headers.Authorization = 'Bearer ' + user.token;
}
}
// Return our config
return config;
};
// Function to handle errors
var responseError = function (rejection) {
// If we have unauthorized access
if (rejection.status === 401) {
// Redirect to our login page
$location.path('/account/login');
}
// Return our rejected promise
return $q.reject(rejection);
};
return {
request: request,
responseError: responseError
};
}])
simples :)
Why is the success callback fired here when the response is 500?
$scope.submit = function() {
var user = $scope.user;
// provide username and password to obtain a token which will be used for api calls
$http.post('/authenticate', user).
success(function(data, status, headers, config) {
$window.sessionStorage.token = data.token;
$location.path('/');
}).
error(function(data, status, headers, config) {
$scope.errors = data.errors;
$scope.message = 'Invalid JSON format, see guidelines for correct format';
$scope.uploadError = true;
console.log('ERROR TRUE');
});
};
And the interceptor:
angular.module('uploadApp')
.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;
}
return config;
},
response: function (response) {
return response || $q.when(response);
},
responseError: function(response) {
if (response.status === 401) {
$location.path('/login');
}
return response || $q.when(response);
}
};
});
The way angular $q promises work is that errors need to be unhandled to continue down the error path - otherwise it assumes that you have corrected the issue or handled the error. So the easiest way is to throw the response from your error path, until you get to the point you actually want to handle it.
angular.module('uploadApp')
.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;
}
return config;
},
response: function (response) {
return response || $q.when(response);
},
responseError: function(response) {
if (response.status === 401) {
$location.path('/login');
}
// instead of returning, you should throw,
// and when you throw you don't need to wrap, as it will
// handle it for you.
//return response || $q.when(response);
throw response;
}
};
});
$q will ensure that the thrown object is wrapped in the promise call-chain. Note that whenever you return in a $q promise it will assume you have handled any issues, unless you throw instead of return. This allows you to have errors in resolvers further down the call-chain that can then be treated as an error.
If throwing isn't your style, you can defer a new promise and return that, then reject it - but that is way less efficient than using the current call-chain.
Why angular $resources not have a request and request error interceptor?
Theres any way to do that?
Doc content:
interceptor - {Object=} - The interceptor object has two optional methods - response and responseError. Both response and responseError interceptors get called with http response object. See $http interceptors.
You can implement your own interceptors as follows.
app.config(function ($httpProvider) {
$httpProvider.interceptors.push('myInterceptor');
});
app.factory('myInterceptor', ['$q', function ($q) {
return {
request: function (config) {
config.headers = config.headers || {};
// insert code to populate your request header for instance
return config;
},
response: function (response) {
if (response.status === 403 || response.status === 401) {
// insert code to redirect to custom unauthorized page
}
return response || $q.when(response);
}
};
}]);
I hope this will help you out.