I am implementing token based authentication with AngularJS. The token is created on server and returned to client. After authentication, the token will be added to header of every rest call. I created a authInterceptor:
ristoreApp.factory('authInterceptor', function ($rootScope, $q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.localStorage.getItem("access_token")) {
config.headers.Authorization = 'Bearer ' + $window.localStorage.getItem("access_token");
}
return config;
},
response: function (response) {
if (response.status === 401) {
// handle the case where the user is not authenticated
}
return response || $q.when(response);
}
};
});
Then injected it in my config.js as follows:
ristoreApp
.config(function ($httpProvider, authInterceptor, $routeProvider) {
$httpProvider.interceptors.push('authInterceptor');
$routeProvider
.......
})
However I got the following error:
Failed to instantiate module ristoreApp due to: Unknown provider: authInterceptor
What is wrong with my way to inject the interceptor?
this Failed to Instantiate module happens when you have NOT defined
ristoreApp
in your Routing file.
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 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;
});
}])
I have make a POST request to an API and they have basic authentication, how can I tell angular $http POST service to pass my credential while making the post requestion?
You can add auth interceptor as follows
angular.module('interceptors.authInterceptor',[])
.factory('authInterceptor', ['$q', function ( $q) {
return {
request: function (config) {
config.headers = config.headers || {};
config.headers['Authorization'] = 'Bearer ' + YOUR_AUTH_TOKEN;
return config;
},
response: function (response) {
return response || $q.when(response);
},
responseError: function(rejection) {
}
};
}])
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
}]);
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 :)
I'm trying to configure the $http service of Angular, to redirect to an URL when the status code is 403.
No problems so far but the URL to redirect to is coming from the server, through a service which is using $http (obiously).
Here's a piece of code:
angular
.module('app')
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(['$q', 'URLs',
function($q, Redirect) {
return {
request: function(config) {
return config || $q.when(config);
},
responseError: function(response) {
if(response.status === 403) {
// redirect to URLs.login
}
return $q.reject(response);
}
};
}
]);
}])
.factory('URLs', ['$http', function($http) {
var URLs;
$http.get('/urls').then(function(response) {
URLs = response.data;
});
return URLs;
}]);
This code is creating a circular dependency (error) in Angular.
Is there a way that I can do this, having dynamic URLs that are coming from a server and based on this to redirect the user to one of them when the response.status is 403?
Use $injector service to lazily load the URLs service:
angular
.module('app')
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(['$q', '$injector',
function($q, $injector) {
return {
request: function(config) {
return config || $q.when(config);
},
responseError: function(response) {
var Redirect = $injector.get('URLs');
if(response.status === 403) {
// redirect to URLs.login
}
return $q.reject(response);
}
};
}
]);
}])
You can also break this circular dependency in the URLs service by injecting the $injector there.