I keep hitting a 404 "user not found" error when trying to make a PUT request with auth0.
I'm trying to update a user and making this API call with the exact endpoint their docs told me to use.
When making the call from their docs (they have a built in test), everything works fine with the body I send and I receive a 200 success message.
When I try making the same call from my app, I keep getting a 404 user not found error.
However, when I use the same endpoint with the same user_id to GET from my app, everything works fine (proving my cliendID is configured correctly).
Why is this failing?
var updateAuthUser = function(){
var request = {
"user_metadata": {
"springboardID": 100055
}
}
var update = $http.put('https://app36591925.auth0.com/api/v2/users/auth0%7C5606b3c4b0c70b49698612fc', request);
update.then(function(response) {
console.log("update success", response);
}, function(response) {
console.log("update failure", response);
});
return update;
}
Working GET request:
var getAuthUser = function(){
$http.get('https://app36591925.auth0.com/api/v2/users/auth0|5606b3c4b0c70b49698612fc')
.then(function(response){
console.log("response", response);
var deferred = $q.defer();
deferred.resolve(response);
return deferred.promise;
});
}
The endpoint to update a user is to be called with PATCH, not PUT.
https://auth0.com/docs/api/v2#!/Users/patch_users_by_id
The correct response to return in this case would be 405 Method Not Allowed, but hapi does not yet support this. See https://github.com/hapijs/hapi/issues/1534.
Related
UPDATE: I tried another API: http://www.omdbapi.com/?t=Sherlock
And the GET works. However, I'm still unsure why my node.js server API does not work with this method.
I am currently working on the backend of an app of which I created an API similar to the tutorial: https://codeforgeek.com/2015/03/restful-api-node-and-express-4/.
However, I cannot seem to get my ionic angular app to retrieve my JSON result. When I put my get command on Postman, I get :
[{"floor":3}]
My controller is:
$http({url:"http://localhost:3000/api/fl",method:'GET'})
.then(function(response) {
$scope.status = response.status;
$scope.data = response.data;
$log.log("success");
$log.log("res:"+ response);
}, function(response) {
$scope.data = response.data || "Request failed";
$scope.status = response.status;
$log.log("failed");
$log.log("res:"+ response);
});
$log.log("status: "+$scope.status);
$log.log("data: "+$scope.data);
(my /fr references the JSON which has a GET method on my node server)
And always gives the result of "failed", "status: undefined" as well as "data: undefined". When I recurse this method, it gives me a "status:0".
I have also tried using $resource with no success.
Any guidance would be appreciated. My API does not have any auth and I don't think it has anything to do with CORS(unless you guys think it does).
EDIT:
this is the get method on my server.js:
//GET Floor
router.get("/fl",function(req,res){
var query = "SELECT floor FROM stor1 WHERE id=0";
connection.query(query,function(err,rows){
if(err) {
res.json({"Error" : true, "Message" : "Error executing MySQL query"});
} else {
res.json(rows);
}
});
});
EDIT2:
Well, i added more logs to display results and now i get an [object Object] from response. The object is:
{"data":null,"status":0,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"url":"http://localhost:3000/api/fl","headers":{"Accept":"application/json, text/plain,*/*"}},"statusText":""}
Your postman seems to get the response for the GET request which means your server side code is fine with routing. But your Angular App is unable to get any response with out throwing any error in the server side. Which seems to be the case of CORS
var cors = require('cors');
app.use(cors());
Note: Use this middleware before your first route.
There is one more way to make Access-Control-Allow-Origin
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
Try adding names for the success and error callback functions, like so:
$http({url:"http://localhost:3000/api/fl",method:'GET'})
.then(function successCallBack(response) { // Add 'successCallBack' function name
$scope.status = response.status;
$scope.data = response.data;
$log.log("success");
$log.log("res:"+ response);
}, function errorCallBack(response) { // Add 'errorCallBack' function name
$scope.data = response.data || "Request failed";
$scope.status = response.status;
$log.log("failed");
$log.log("res:"+ response);
});
$log.log("status: "+$scope.status);
$log.log("data: "+$scope.data);
I have an Angular application, currently an HTML file I open but it will soon be converted to a server/accessed through localhost. I use $http to access a 3rd party API (I have no control over its responses; most of the API calls work, but some don't and throw the error:
XMLHttpRequest cannot load http://api.nal.usda.gov/ndb/search/?format=json&api_key=RJEnADgGbCjfJYi0z8vuVnelYXn2Smud2Dfi2u2F&q=susage. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 404.
The API calls that throw that error are the searches that return 0 results (in the example, the database returns no results for "susage"). In the Network tab, the response can't be loaded and no response headers are listed; for other working API calls, under Response Headers, the necessary "Access-Control-Allow-Origin:*" is present.
The API definitely forms a response and tries to send it back, but fails for whatever reason. Visiting the posted url shows that response.
Why do only the empty searches throw the error when API understands and has a response for both calls, and how do I fix it? I would prefer that my frontend communicates with the API directly, as opposed to communicating with my backend which in turn communicates with the API.
For comparison, a search with results (spelling 'sausage' correctly) vs a search without results: http://imgur.com/a/ihhI1
The $http code:
return $http.get('http://api.nal.usda.gov/ndb/search/?format=json', {
params: {
api_key: usdaKey,
q: query
}
})
In order to expose the "-1" status (timeout) to the UI, I changed the service method to simply return the promise, like this:
var search = function(query) {
return $http.get('http://api.nal.usda.gov/ndb/search/?format=json', {
params: {
api_key: usdaKey,
q: query
}
});
};
Then you can handle the error in your controller, like this:
$scope.search = function(query) {
$scope.items = [];
$scope.err = null;
foodInfo.search(query).then(function(response) {
console.log(response);
$scope.items = response.data.list.item;
}, function(e) {
console.log('Error status: ' + e.status);
if (e.status === -1) {
$scope.err = 'No data found';
}
});
};
I have an angular front end with a webapi back end. I have implemented OAuth v2 security using OWIN/Identity and JWT tokens (thanks to Taiseer Joudeh's blogs). My burden is that we still have legacy pages that require a specific cookie. I have augmented the Http Response from WebApi to include that cookie when the JWT token is returned from a login request. I have verified the cookie is in the response header.
My problem is that I am unable to see the cookie inside my angular response handler where I will push it to the browser. I have tried each of the following based on suggestions I found elsewhere within StackOverflow but so far visibility of the cookie within the .js code has eluded me (alternate attempts have been commented out but left in for completeness). I have also made sure I set the appropriate "allow" fields on the server by adding "Access-Control-Allow-Headers" to "set-cookie" and "Access-Control-Allow-Credentials" to "true" at the end of my ValidateClientAuthenticationContext(..) method.
What do I need to do to see the attached cookie on my webapi response? Is this a problem on the server or client? both?
in my authService.js file:
var _login = function (loginData) {
// this makes the data "form data"
var data = "grant_type=password&client_id=ngAuthApp&username=" + loginData.userName + "&password=" + loginData.password;
var deferred = $q.defer();
$http.post(serviceBase + 'oauth/token', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } })
.success(function (response) {
localStorageService.set('authorizationData', { token: response.access_token, userName: loginData.userName });
_authentication.isAuth = true;
_authentication.userName = loginData.userName;
console.log($cookies);
//var xxx = $http.defaults.headers;
//var headers = $http.response.headers;
var ddc = $http.response.cookies;
$cookies.DDC = ddc;
deferred.resolve(response);
})
//.success(function (data, status, headers, config) {
// // any required additional processing here
// var results = [];
// results.data = data;
// results.headers = headers();
// results.status = status;
// results.config = config;
// deferred.resolve(results);
//})
.error(function (err, status) {
_logOut();
deferred.reject(err);
});
return deferred.promise;
};
in my custom OAuthProvider .cs file
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// skipping over lots of code here
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "authorization", "content-type", "set-cookie" });
context.Validated();
return Task.FromResult<object>(null);
}
According to the docs - see here
$http.post() method returns an HttpPromise future object. Your call to .post() returns a promise. Which according to the Deprecation Notice on the above referenced page :
The $http legacy promise methods success and error have been
deprecated. Use the standard then method instead. If
$httpProvider.useLegacyPromiseExtensions is set to false then these
methods will throw $http/legacy error.
So instead of .success() / error(), use this: (Copied from docs)
$http.post()
.then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Also, if you haven't already tried this (according to the .post() call it doesn't appear to) set the responseType property of your $http configuration object. This sets the datatype of the response object returned. Otherwise the default of a DOM string is returned. It may not fix it but it could be a start.
This could also need the help of withCredentials property set. Test them out and see how it goes. Idea comes from the suggestion of bastijn.
Your $http call should also set the withCredentials flag to true to explicitly allow cookie sharing.
$http.post(url, {withCredentials: true, ...})
The withCredentials flag allows javascript to access the authenticated session of the user.
//edit
Now that I read your question again this is probably not your issue. The withCredentials is to,communicate your session to the server on the next request you make that requires the authenticated session. From your question it seems you want to validate in the js code that the cookie you verified is there is also reachable by code.
It turns out the error was in my assumptions. I expected that a cookie sent via a web service directly from embedded js code would be ignored by the browser. However, the response header has the "Set-Cookie" value in the header and the browser IS already pushing it to be with the rest of the cookies. I really didn't expect that.
I must add this has been a very useful question for me because it taught me a lot about web programming and how the browser works with http header values. I appreciate everyone's time!
Marcus
I have an angular application making async requests to an API service. Since a lot of the resources are protected on the API Service, I need to intercept the HTTP requests made to the service. But as far as I can see, the interceptor I have defined only intercept page load requests.
Here is an experimental setup I have come up with to illustrate my problem:
myApp = angular.module('myApp', []);
myApp.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(function() {
return {
response: function(response) {
console.log(response);
return response;
}
};
});
});
What I am able to see is that, the interceptor intercepts all calls except the API call as you can see from the attached screen shot showing the console output.
The console output, as you can see from the screen shot below, contains the responses logged when the partial templates have been loaded but not when the GET request was made to the API service.
Why does this happen?
Update
I have changed my setup to include all possible combinations of requests and responses now:
$httpProvider.interceptors.push(function() {
return {
request: function(request) {
console.log(request);
return request;
},
requestError: function(request) {
console.log(request);
return config;
},
response: function(response) {
console.log(response);
return response;
},
responseError: function(response) {
console.log(response);
return response;
}
};
});
Now the interceptor intercepts the message but weirdly shows the status of the caught responseError as:
status: -1
although it clearly is a 401.
Update 2
As it turns out, even 401 responses require the CORS header to be added to it. The problem came up since the REST API I was calling used Spring-CORS library which does not include CORS headers on 401 and 403 responses.
It's a cross-site domain issue because although your using localhost your API call domain is different to the UI's (port 8080 & 8081), have a read of this article for more information. You will need add this header in your webserver:
Access-Control-Allow-Origin: http://foo.example
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
I am using ng-resource to do ajax request. I want to send extra info besides the data.
For example, I have an article entity on my server
exports.fetchArticle = function(req, res, next) {
var article = req.article
return res.json({data: article, message: 'success fetch article'})
}
The reason I wrap it is that, in the case of deletion, it makes no sense to send data, I can just return res.json({data: null, message: 'deleted successfully'})
on my client side, I have:
$scope.fetchArticle = function() {
Article.get({articleId: $routeParams.articleId}, function(response) {
$scope.article = response.data
$scope.ajaxSuccess = response.message
}, function(err) {
$scope.ajaxError = err.data.message
})
}
$scope.article is not an instance of ng-resource anymore, thus I can't do further request with $scope.article, i.e. this will cause error, since $scope.article is a plain json object:
$scope.article.$update(function(response) {...})
If I simply return res.json(article) from server, it works, but I can't send along the message.
The reason I dont generate the message from client but fetch from server is that, the error message is from server, I want to keep success message consistent with the error message.
Is there any other elegant way to send the message?
Assuming that all your servers responses follow this format:
{
data: {/*...*/},
message: 'some message'
}
You could use $http's transformResponse for that, so that you get an ngResource instance that is your returned object while still processing your message. For that, you need a transform-function:
function processMessage(data, message) {
//Do whatever you want with your message here, like displaying it
}
function transform(response) {
processMessage(response.data,response.message);
var data = response.data;
delete response.data;
delete response.message;
for(var attributeName in data) {
response[attributeName] = data[attributeName];
}
return response;
}
Then you can add this function to $http's default transfroms in the config of your app:
angular.module("yourApp",[/* ... */])
.config(function($httpProvider){
//....all your other config
$httpProvider.defaults.transformResponse.unshift(transform);
});
Now all repsonses from $http get transformed by this function, triggering processMessage and leaving you with a ngResource instance of the returned object.