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;
Related
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 route in my API app:
router.get('/users', auth, function(req, res) {
User.find({}, function(err, users) {
res.json(users);
});
});
In postman I do the api call like this:
URL + users?token=token
But this returns:
Format is Authorization: Bearer [token]
How can I properly do the api call with a token in postman?
The error you got indicates the right format you need to use for the header:
Format is Authorization: Bearer [token]
You can try this in Postman
You need to add the header to the http
module.run(function($http) {
$http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
});
after doing this your requests will be sent with this header
take a look at https://docs.angularjs.org/api/ng/service/$http
You can create a http interceptor service like this
app.factory('authInterceptor', function($rootScope, $q, $cookieStore, $location) {
return {
// Add authorization token to headers
request: function(config) {
config.headers = config.headers || {};
if ($cookieStore.get('token')) {
config.headers.Authorization = 'Bearer ' + $cookieStore.get('token');
}
return config;
},
// Intercept 401s and redirect you to login
responseError: function(response) {
if (response.status === 401) {
$location.path('/login');
// remove any stale tokens
$cookieStore.remove('token');
return $q.reject(response);
} else {
return $q.reject(response);
}
}
};
})
And then add the service into the interceptors like this
app.config(function($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
})
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 :)
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.