We are in the middle of converting our entire web infrastructure to use JWT as our Bearer auth tokens and I added a global interceptor on our $httpProvider that will read the token from a service that was previously (in a resolve for the root state of our app) fetched from our Auth server.
The problem is that I get a circular dependency because the initial call to GET /api/oauth/token uses the $http service which uses my interceptor. Therefore, the only way I think I can do this is to not use $http in that initial request, right?
What is the correct way to do this? It feels wrong to use jQuery here to make the AJAX call, but is that the best way?
app.factory('AuthProvider', function($http, $q){
var service = {};
var _token = null;
service.getToken = function(){
var deferred = $q.defer();
// the use of $http here is what causes this issue
$http({
method:'GET',
url:'/api/oauth/token'
}).then(function(res){
_token = res.result;
deferred.resolve(_token);
}, function(res){
deferred.reject(res);
});
return deferred.promise;
}
service.readToken = function(){
return _token;
}
return service;
});
Related
i have developed single page application in angularjs. i have implemented the refresh token mechanism. refresh token suppose to refresh every 30 minutes. I am trying to handle refresh token in responseError of interceptor. I m trying to hold request if it returns 401 unauthorised error. Is there any mechanism to hold all the request once it return 401 error then refresh token and resume all request with new token.
Is it right way to handle the refresh token, here is sample code
$provide.factory('httpTokenInterceptor', function ($q, $injector, $cookies) {
return {
// On request sending
request: function (config) {
config.headers = config.headers || {};
// get this data from $cookies
var globals = $cookies.getObject('globals') || {};
//console.log(globals);
if (globals.authData)
config.headers.Authorization = 'Bearer ' + globals.authData.access_token;
return config;
},
// On response failure
responseError: function (rejection) {
console.log('AuthTokenHttpInterceptor responseError');
console.log(rejection);
if (rejection.status === 401) {
//hold current and all pending request
var aService = $injector.get('authenticationService');
aService.getRefreshToken().then(function(response) {
//need to resume all the request here
deferred.resolve(response);
});
return deferred.promise;
}
return $q.reject(rejection);
}
};
});
In short, you don't want to hold up any of your HTTP calls like that.
Your solution will go and refresh your token after one of your HTTP calls already failed. Also, just to be clear, your code is adding Authorization header even on HTTP calls that are getting resources like HTML templates. If you don't want to do this, then you should restrict that as well.
For one solution, check out this link. It doesn't use any particular library for handling JWT tokens, but you will have to create a wrapper around this implementation to use it wherever you need to do a HTTP call.
My suggestion (and personal preference when handling JWT tokens) is using the angular-jwt library. It's really easy to set up and you can check it out here.
There more complex libraries like auth0, which can do a lot of other stuff, and can be used in conjuction with angular-jwt library. Check out this link to see how to handle token refreshing both prior to a HTTP call and on page refresh.
Hope this helps.
You can hold requests and resume them using AngularJS Interceptors.
authInterceptor.$inject = ['$q', '$rootScope'];
function authInterceptor($q, $rootScope) {
return {
request: function(config) {
var deferred = $q.defer();
$rootScope.$watch('continue', function(value) {
if(value === true)
deferred.resolve(config);
});
return deferred.promise;
}
};
}
In the above example all of the requests hold until $rootScope.continue becomes true. Otherwise they will wait forever.
According to CORS explained in here, a request with method OPTIONS must be performed in order for the browser to check the permissions of the server..
I am simply making request using $http service to a different server hosted in a different machine, just because it's in a different host than the page the request must be preflighted according to CORS.. but i am getting on the logs that this is not being performed somehow
app.js
var restful = angular.module("ngRestful", []);
restful.config(["$httpProvider", function($http){
$http.defaults.useXDomain = true;
delete $http.defaults.headers.common["X-Requested-With"];
}]);
restful.service("$rest", ["$http", function($http){
this.get = function(url){
return $http({
method: "GET",
url: url
});
};
}]);
controller.js
(function(){
var app = angular.module("test", ["ngRestful"]);
app.controller("testController", ["$rest", function($rest){
$rest.get("http://192.168.1.108/tree/server/accounts")
.then(function(response){
console.log(response);
})
.catch(function(err){
console.error(err);
});
}]);
})();
i have seen on other codes that $http.defaults.useXDomain must be set on true in order to enable CORS.. the server gives all CORS settings on method OPTIONS but yet the browser is not requesting a method OPTIONS, of course the browser ignores the body due to not having the CORS headers in the response
I'm trying to get a basic query going with the new V2 API and Angular in WordPress 4.4.1. Perhaps someone can help me understand why the URL, /wp-json/wp/v2/posts, gives a JSON response with a 404.
Browsing to that URL gives me JSON like this:
{"code":"rest_no_route","message":"No route was found matching the URL and request method","data":{"status":404}}
And here is the JavaScript I'm using to make that .GET
var base = 'http://localhost:8888/recruitler';
var posts = '/wp-json/wp/v2/posts';
var user = '/wp-json/wp/v2/users/'; // append user id
var s = '/wp-json/wp/v2/posts?filter[s]='; // append search term
// basic HTTP call with Angular
var app = angular.module('app', ['ngRoute'])
app.factory('myService', function($http) {
var myService = {
async: function() {
// $http returns a promise, which has a then function, which also returns a promise
var promise = $http.get( base+posts ).then(function (response) {
// The then function here is an opportunity to modify the response
console.log(response);
// The return value gets picked up by the then in the controller.
return response.data;
});
// Return the promise to the controller
return promise;
}
};
return myService;
});
app.controller('MainCtrl', function( myService, $scope ) {
// Call the async method and then do stuff with what is returned inside our own then function
myService.async().then(function(d) {
$scope.data = d;
});
});
UPDATE:
This must be a local environment issue. Live websites work just fine. I've tested and this issue persists on all my local WAMP and MAMP dev sites. Restarting the server and or checking this answer got it working.
the factory looks right, according to the rest-api docs you need pretty permalinks plugin as well in order to rest-api plugin use custom url rewrites https://wordpress.org/plugins/rest-api/installation/
I'm using Angular.js to build a client side application with Restangular.
The problem is, I implemented a digest authentication with a wsse header which i have to generate at each request to my REST Server.
I saw that Restangular provide a function : addFullRequestInterceptor().
So now, i'm trying to use it inside my RestangularProvider to configure it in this file restangular.js :
// Config Restangular
app.config(function(RestangularProvider) {
RestangularProvider.setBaseUrl(applicationConfig.SERVER_URL);
RestangularProvider.setDefaultHeaders({'Content-Type': 'application/json'});
RestangularProvider.addFullRequestInterceptor(
function (element, operation, route, url, headers, params, httpConfig) {
// Here is my header generation.
$http.defaults.headers.common['X-WSSE'] =
TokenHandler.getCredentials(
AuthHandler.authentication.user.username,
AuthHandler.authentication.secret);
return {
element: element,
headers: headers,
params: params,
httpConfig: httpConfig
};
});
});
But i have an injection problem and i can't find out how to inject my TokenHandler service & my AuthHandler service to be able to know if the user is already loggedin or not and if he has localstroage or not.
Thanks for the help ;)
The problem is that in the .config phase the services, like AuthHandler and TokenHandler are not yet instantiated, so you need to instantiate them (and their dependencies) manually with $injector (which is injectable into config blocks):
app.config(function(RestangularProvider,
$injector,
AuthHandlerProvider,
TokenHandlerProvider) {
var AuthHandler = $injector.instantiate(AuthHandlerProvider.$get);
var TokenHandler = $injector.instantiate(TokenHandlerProvider.$get);
//...
});
Is there a way to set the $httpProvider headers outside of angular.module('myApp', []).config()?
I'm getting an Auth-Token from the server after I login the user, and I need to add it as a HTTP Header to all following requests.
You can use default headers for angular 1.0.x:
$http.defaults.headers.common['Authentication'] = 'authentication';
or request interceptor for angular 1.1.x+:
myapp.factory('httpRequestInterceptor', function () {
return {
request: function (config) {
// use this to destroying other existing headers
config.headers = {'Authentication':'authentication'}
// use this to prevent destroying other existing headers
// config.headers['Authorization'] = 'authentication';
return config;
}
};
});
myapp.config(function ($httpProvider) {
$httpProvider.interceptors.push('httpRequestInterceptor');
});
Since factories/services are singletons, this works as long as you do not need to dynamically change your 'authentication' value after the service has been instantiated.
$http.defaults.headers.common['Auth-Token'] = 'token';
It seems headers() normalizes the key names.
Adding to above responses of #Guria and #Panga
config.headers['X-Access-Token'] = $window.sessionStorage.token;
One can use x-access-token in header as JWT(jsonwebtoken).
I store JWT in the session storage when a user authenticate first time.