Ajax calling 401 unauthorized from backend in html - javascript

I have a problem with my AJAX. Using Insomnia, I was able to get in with a successful response of 200 using the API token.
However, when I implement it in the HTML, I get a 401 response of access denied.
$.ajax({
url: "https://ecoexchange.dscloud.me:8080/api/get",
method: "GET",
apikey: sessionStorage.getItem("apikey"),
dataType: 'json',
success: function(result) {
$('#infoTable tr').empty();
var header = $('#infoTable thead');
var body = $('#infoTable tbody');
var hTr;
$('#infoTable thead').append(hTr = $('<tr>'));
// Headers
for (var h = 0; h < result.headers.length; h++) {
hTr.append($('<th>', {
text: result.headers[h]
}))
}
// Body
for (var d in result.data) {
var data = result.data[d];
$('#infoTable tbody').append($('<tr>')
.append($('<td>', {
text: data.RecyclableID
}))
.append($('<td>', {
text: data.Name
}))
.append($('<td>', {
text: data.RecyclableType
}))
)
}
}
})
I am not sure how to put in the token or user name or password.
How can I improve the code so I don't get the error?

What is this apikey parameter you're using? That's not in the documentation.
apikey: sessionStorage.getItem("apikey"),
Did you mean to pass it as a header instead? For example:
headers: {"apikey": sessionStorage.getItem("apikey")},
The documentation for the service you're using should specify how to include the API key. Presumably you have that information, because:
Using Insomnia, I was able to get in with a successful response
So you'll need to include the value in your AJAX request wherever it belongs. Most likely as either a header value or a query string value. But the jQuery .ajax() function isn't going to know how to pass the value, you have to specify.

I think your problem is with passing queries which can be solved here
As it's been said on David's answer , You must know where your apikey is required on the server-side, in header or queries(parameters).
If your apikey is required on queries based on the docs you can use :
$.get('/api/get' , {'apikey' : 'YOUR-KEY'}).done((res) => {
console.log(res)
})
Or if your apikey is required in headers:
$.ajax({
url: '/api/get',
type: 'GET',
headers: {'apikey' : 'YOUR-KEY'},
success : (res) =>{
console.log(res);
}
})
jQuery.ajax() docs can be found here
And jQuery.get() docs here

Related

Using HTTP in NativeScript to send Post-data to a TYPO3-Webservice

I'm trying to send form data from a NativeScript app to a TYPO3-Webservice.
This is the JavaScript I'm using:
httpModule.request({
url: "https://my.domain.tld/webservice?action=login",
method: "POST",
headers: { "Content-Type": "application/json" },
content: JSON.stringify({
username:username,
password:password
})
}).then((response) => {
console.log("got response");
console.log(response.content);
//result = response.content.toJSON();
callback(response.content.toJSON());
}, (e) => {
console.log("error");
console.log(e);
});
But I can't read this data in the controller. Even with this:
$rest_json = file_get_contents("php://input");
$postvars = json_decode($rest_json, true);
$postvars is empty. $_POST is empty, too (which is - according to some docs - because the data is sent as JSON and thus the $_POST-Array isn't populated.
Whatever I do, whatever I try, I can't get those variables into my controller.
I tried it with fetch as well as with formData instead of JSON.stringify, same result.
I might have to add, that when I add the PHP-part in the index.php of TYPO3, $postvars is being populated. So I guess something goes missing, until the controller is called.
Any ideas?
the nativescript part seems ok, your problem must be corrected in the server side.
i use similare call and its works
// send POST request
httpModule.request({
method: "POST",
url: appSettings.getString("SERVER") + '/product/list',
content: JSON.stringify(data),
headers: {"Content-Type": "application/json"},
timeout: 5000,
}).then(response => { // handle replay
const responseAsJson = response.content.toJSON();
console.log('dispatchAsync\n\tresponse:', responseAsJson);
}, reason => {
console.error(`[ERROR] httpModule, msg: ${reason.message}`);
});

understanding a http request and nested function in ajax

I am referencing this code to build a twitch viewer app, which I'm having difficulties in understanding:
$(document).ready(function() {
let usernames = ["user1", "user2", "user3", "user4"];
usernames.forEach(function(user) {
let http = "https://api.twitch.tv/kraken/streams/" + user;
function getAjax(getdata) {
$.ajax({
url: http,
headers: {
'Client-ID': 'myclientid'
},
success: function(data) {
getdata(data)
}
});
}
});
})
What does 'headers' do exactly? I looked it up on twitch and couldn't find a detailed description. It doesn't look like it gives/adds anything to my http request. Twitch says the header "securely identify my application." but wasn't sure what that mean. I thought if it works similar to an API key it should be included in the request.
What does the 'getdata' function in this code do? does it simply store the data i receive from the ajax request?
1) Headers are included in the request. You should be able to see them in the developer tools; this is what it looks like in Firefox
2) getdata is a callback function that is passed into getAjax by consumers, which can then act on the data as necessary, for example...
getAjax(function(data) {
// do something with data
})
Note also, you're redeclaring the function in each iteration of the loop, but not actually calling it anywhere. You probably want something more like this...
$(document).ready(function() {
let usernames = ["user1", "user2", "user3", "user4"];
function getAjax(url, getdata) {
$.ajax({
url: url,
headers: {
'Client-ID': 'myclientid'
},
success: function(data) {
getdata(data)
}
});
}
usernames.forEach(function(user) {
let http = "https://api.twitch.tv/kraken/streams/" + user;
getAjax(http, function(data) {
// do something with data
})
});
})

Sharepoint REST api returns Bad Request (400)

I am trying to create a ListItem using the Sharepoint REST Api (we just started with the Sharepoint Api so definitly no expert).
According to the Microsoft tutorial the post should look like this:
I implemented the following code
public addItemToList_Test(): void {
var listTitle: string = "DemoHomeWork";
var listItemType: string = "SP.Data." + listTitle + "ListItem";
var listItemTitle: string = "TestItem";
var postBody = { '__metadata': { 'type': listItemType }, 'Title': 'TestItem' };
var $: jQuery = require("jquery");
var call = $.ajax({
url: listsUrl + "/GetByTitle('" + listTitle + "')/items",
method: "POST",
body: postBody,
headers: {
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
length: JSON.stringify(postBody).length
}
});
return call;
}
However, this keeps returning me Bad Request (400) and figuring out why this happens is tricky to find out. Is there anyone who can tell me what is wrong with the request?
How are you authenticating your request?
As given in documentation you need to pass access_token with your request to make API work. As in you headers, i am not seeing access_token being passed.
You need to first get access_token and then pass it with the request to make API work.
Also in
"'__metadata': { 'type': listItemType }" **listItemType** you are creating it manually but it can be different. Can you check getting it manually (`https://site_url/_api/web/lists/getbytitle(listtitle)`)
and check if ListItemEntityTypeFullName for this list is same as you have created listItemType.

Express.js http call inside route doesn't update variable

I'm building a REST api on top of express.js. I am having trouble updating variables inside my routes.
Example:
I'm calling app.get("/wp/page/create/:id", function(req, res)
Inside this route I start by calling a http request using request-promise library. The response of this call I use in a nested http call.
I use a global variable for the headers for the nested call, and it's to the header a i need to make changes by using the etag variable.
Code:
global.postHeaders = headers;
postHeaders['X-HTTP-Method'] = "MERGE";
postHeaders['Content-Type'] = 'application/json;odata=verbose';
postHeaders['X-RequestDigest'] = spContext;
request.get({
url: "xxx",
headers: headers,
json: true
}).then(function(response) {
var etag = response.d.__metadata.etag
postHeaders['If-Match'] = etag;
request.post({
url: "xxx",
type: "POST",
body: data,
headers: postHeaders,
json: true
}).then(function(data) {
res.send(data).end()
console.log("All done!");
})
})
When i start the server up and enter the route everything works fine. When i when try to hit it again the etag variables is still the same, even though it should be updated.
If I restart the server it works the again on the first attempt but fails on the second/third.
Any idea what I am doing wrong?
I have resolved the issues. The simple solution was to clear the headers containing the variable.
global.postHeaders = headers;
postHeaders['X-HTTP-Method'] = "MERGE";
postHeaders['Content-Type'] = 'application/json;odata=verbose';
postHeaders['X-RequestDigest'] = spContext;
request.get({
url: "xxx",
headers: headers,
json: true
}).then(function(response) {
var etag = response.d.__metadata.etag
postHeaders['If-Match'] = etag;
request.post({
url: "xxx",
type: "POST",
body: data,
headers: postHeaders,
json: true
}).then(function(data) {
postHeaders['If-Match'] = "";
res.send(data).end()
console.log("All done!");
})
})
postHeaders is a global variable. is headers in global.postHeaders = headers; also a global varaible ? Whatever you are trying to do here is grossly wrong. postHeaders variable will be shared across multiple request. so you will hit a scenario where postHeaders['If-Match'] value might be empty string or the etag .
Try this instead of the first line
var postHeaders = Object.assign({}, headers);
Not sure what you are trying, but at-least this statement will subside the huge error in the code. This will create a new header object for each request.

HttpClient PostAsync equivalent in JQuery with FormURLEncodedContent instead of JSON

I wrote a JQuery script to do a user login POST (tried to do what I have done with C# in the additional information section, see below).
After firing a POST with the JQuery code from my html page, I found the following problems:
1 - I debugged into the server side code, and I know that the POST is received by the server (in ValidateClientAuthentication() function, but not in GrantResourceOwnerCredentials() function).
2 - Also, on the server side, I could not find any sign of the username and password, that should have been posted with postdata. Whereas, with the user-side C# code, when I debugged into the server-side C# code, I could see those values in the context variable. I think, this is the whole source of problems.
3 - The JQuery code calls function getFail().
? - I would like to know, what is this JQuery code doing differently than the C# user side code below, and how do I fix it, so they do the same job?
(My guess: is that JSON.stringify and FormURLEncodedContent do something different)
JQuery/Javascript code:
function logIn() {
var postdata = JSON.stringify(
{
"username": document.getElementById("username").value,
"password": document.getElementById("password").value
});
try {
jQuery.ajax({
type: "POST",
url: "http://localhost:8080/Token",
cache: false,
data: postdata,
dataType: "json",
success: getSuccess,
error: getFail
});
} catch (e) {
alert('Error in logIn');
alert(e);
}
function getSuccess(data, textStatus, jqXHR) {
alert('getSuccess in logIn');
alert(data.Response);
};
function getFail(jqXHR, textStatus, errorThrown) {
alert('getFail in logIn');
alert(jqXHR.status); // prints 0
alert(textStatus); // prints error
alert(errorThrown); // prints empty
};
};
Server-side handling POST (C#):
public override async Task ValidateClientAuthentication(
OAuthValidateClientAuthenticationContext context)
{
// after this line, GrantResourceOwnerCredentials should be called, but it is not.
await Task.FromResult(context.Validated());
}
public override async Task GrantResourceOwnerCredentials(
OAuthGrantResourceOwnerCredentialsContext context)
{
var manager = context.OwinContext.GetUserManager<ApplicationUserManager>();
var user = await manager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError(
"invalid_grant", "The user name or password is incorrect.");
context.Rejected();
return;
}
// Add claims associated with this user to the ClaimsIdentity object:
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
foreach (var userClaim in user.Claims)
{
identity.AddClaim(new Claim(userClaim.ClaimType, userClaim.ClaimValue));
}
context.Validated(identity);
}
Additional information: In a C# client-side test application for my C# Owin web server, I have the following code to do the POST (works correctly):
User-side POST (C#):
//...
HttpResponseMessage response;
var pairs = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>( "grant_type", "password"),
new KeyValuePair<string, string>( "username", userName ),
new KeyValuePair<string, string> ( "password", password )
};
var content = new FormUrlEncodedContent(pairs);
using (var client = new HttpClient())
{
var tokenEndpoint = new Uri(new Uri(_hostUri), "Token"); //_hostUri = http://localhost:8080/Token
response = await client.PostAsync(tokenEndpoint, content);
}
//...
Unfortunately, dataType controls what jQuery expects the returned data to be, not what data is. To set the content type of the request data (data), you use contentType: "json" instead. (More in the documentation.)
var postdata = JSON.stringify(
{
"username": document.getElementById("username").value,
"password": document.getElementById("password").value
});
jQuery.ajax({
type: "POST",
url: "http://localhost:8080/Token",
cache: false,
data: postdata,
dataType: "json",
contentType: "json", // <=== Added
success: getSuccess,
error: getFail
});
If you weren't trying to send JSON, but instead wanted to send the usual URI-encoded form data, you wouldn't use JSON.stringify at all and would just give the object to jQuery's ajax directly; jQuery will then create the URI-encoded form.
try {
jQuery.ajax({
type: "POST",
url: "http://localhost:8080/Token",
cache: false,
data: {
"username": document.getElementById("username").value,
"password": document.getElementById("password").value
},
dataType: "json",
success: getSuccess,
error: getFail
});
// ...
To add to T.J.'s answer just a bit, another reason that sending JSON to the /token endpoint didn't work is simply that it does not support JSON.
Even if you set $.ajax's contentType option to application/json, like you would to send JSON data to MVC or Web API, /token won't accept that payload. It only supports form URLencoded pairs (e.g. username=dave&password=hunter2). $.ajax does that encoding for you automatically if you pass an object to its data option, like your postdata variable if it hadn't been JSON stringified.
Also, you must remember to include the grant_type=password parameter along with your request (as your PostAsync() code does). The /token endpoint will respond with an "invalid grant type" error otherwise, even if the username and password are actually correct.
You should use jquery's $.param to urlencode the data when sending the form data . AngularJs' $http method currently does not do this.
Like
var loginData = {
grant_type: 'password',
username: $scope.loginForm.email,
password: $scope.loginForm.password
};
$auth.submitLogin($.param(loginData))
.then(function (resp) {
alert("Login Success"); // handle success response
})
.catch(function (resp) {
alert("Login Failed"); // handle error response
});
Since angularjs 1.4 this is pretty trivial with the $httpParamSerializerJQLike:
.controller('myCtrl', function($http, $httpParamSerializerJQLike) {
$http({
method: 'POST',
url: baseUrl,
data: $httpParamSerializerJQLike({
"user":{
"email":"wahxxx#gmail.com",
"password":"123456"
}
}),
headers:
'Content-Type': 'application/x-www-form-urlencoded'
})
})

Categories