So I am trying around with an application that I did not code, and I am quite new to REST APIs etc, so I am having some issues with that.
From my front-end Next.js application I am sending an Axios request to the backend with a Bearer token header
const config: AxiosRequestConfig = {
method,
url: `${BASE_URL}${url}`,
headers: isFormData ? { 'Content-Type': 'multipart/form-data' } : {},
data: isFormData ? params : ( params ? { ...params } : null ),
validateStatus: function (status) {
return status >= 200 && status < 300 // default
}
}
config.headers['Authorization'] = `Bearer ${userStore.token}`
Everything works, so if a user is authenticated and has the token in the userStore the request is successful and the backend responds with the given json data for a certain api route.
Postman Image
Though when I try to fetch the json data directly from the API route in Postman, and provide the Authorization header for this request, I get an error not authorized response from the backend. What am I missing here?
try selecting 'bearer token' under authorization and give the token directly.
Related
I am developing an ionic app that makes a rest call to a backend to send an email, when I make the rest call I get the following error, what can be due to (the rest call in postman works, I use chrome with the cors disabled)
Error:
POST http://172.16.50.92/send 500 (Internal Server Error)
Code Angular:
const params = {
'type': 'mail',
'attributes[to_recipients]': mail,
'attributes[body]': body,
'attributes[subject]': subject,
'attributes[attachments]': attachments
};
endpoint = url + '/send';
var headers_object = new HttpHeaders();
headers_object.append('contentType', 'application/json');
headers_object.append('Authorization', `Basic ${window.btoa(username + ':' + password)}`);
return this.http.post(endpoint, params, [headers_object]);
return this.http.post(endpoint, params, [headers_object]);
You put your headers into an array. But the signature is supposed to be
post(url: string, body: any, options: { headers: HttpHeaders })
for your usecase.
Please change to below and try again.
return this.http.post(endpoint, params, { headers: headers_object });
I can't figure out how to make a request with an access token from JS. I have the API documentation here: https://littlesis.org/api
I'm using P5.js as well
this.url = 'https://littlesis.org/api/entities/search?q=' + this.name;
httpDo(
this.url, {
method: 'GET',
// Other Request options, like special headers for apis
headers: {
'Littlesis-Api-Token': 'xxxxx'
}
},
function(res) {
println("!");
}
);
This doesn't seem to work, and it gives me the following error: "NetworkError when attempting to fetch resource."
Is there a way to simply place the access token in the URL? That way I can retrieve the JSON the old fashion way.
Try adding a no-cors option to your request:
this.url = 'https://littlesis.org/api/entities/search?q=' + this.name;
httpDo(
this.url, {
method: 'GET',
mode: 'no-cors',
// Other Request options, like special headers for apis
headers: {
'Littlesis-Api-Token': 'xxxxx'
}
},
function(res) {
println("!");
}
);
At least for me, this changes the error from a 422 unproccessable entity error to a 401 unauthorized error, which I assume your actual API key will resolve.
I have published an app script publicly (Anyone, even anonymous) with a doPost method as follow,
function doPost(e){
var sheet = SpreadsheetApp.getActiveSheet();
var length = e.contentLength;
var body = e.postData.contents;
var jsonString = e.postData.getDataAsString();
var jsonData = JSON.parse(jsonString);
sheet.appendRow([jsonData.title, length]);
var MyResponse = "works";
return ContentService.createTextOutput(MyResponse).setMimeType(ContentService.MimeType.JAVASCRIPT);
}
When I sent a Post request with a JSON object with Advanced Rest Client it all works and return a 200 OK response. But when I try to send a post request with the react axios from a locally hosted react app it sends a 405 Response.
XMLHttpRequest cannot load https://script.google.com/macros/s/AKfycbzyc2CG9xLM-igL3zuslSmNY2GewL5seTWpMpDIQr_5eCod7_U/exec. Response for preflight has invalid HTTP status code 405
I have enabled cross origin resource sharing in the browser as well. The function that sends the POST request is as follow,
axios({
method:'post',
url:'https://script.google.com/macros/s/AKfycbzyc2CG9xLM-igL3zuslSmNY2GewL5seTWpMpDIQr_5eCod7_U/exec',
data: {
"title": 'Fred',
"lastName": 'Flintstone'
}
}).then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
You missed the important part:
Response for preflight has invalid HTTP status code 405.
Your browser is making a preflight request, which uses the OPTIONS HTTP method. This is to check whether the server will allow the POST request – the 405 status code is sent in the response to the OPTIONS request, not your POST request.
A CORS preflight request is a CORS request that checks to see if the CORS protocol is understood. Source
Additionally, for HTTP request methods that can cause side-effects on server's data (in particular, for HTTP methods other than GET, or for POST usage with certain MIME types), the specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTP OPTIONS request method, and then, upon "approval" from the server, sending the actual request with the actual HTTP request method. Source
Some requests don’t trigger a CORS preflight. Those are called "simple requests" in this article [...] Source
This article section details the conditions a request has to meet to be considered a "simple request".
[...] "preflighted" requests first send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. Source
This article section details the conditions which cause a request to be preflighted.
In this case, the following is causing the request to be preflighted:
[...] if the Content-Type header has a value other than the following:
application/x-www-form-urlencoded
multipart/form-data
text/plain
The value for the Content-Type header is set to application/json;charset=utf-8 by axios. Using text/plain;charset=utf-8 or text/plain fixes the problem:
axios({
method: 'post',
url: 'https://script.google.com/macros/s/AKfycbzyc2CG9xLM-igL3zuslSmNY2GewL5seTWpMpDIQr_5eCod7_U/exec',
data: {
title: 'Fred',
lastName: 'Flintstone',
},
headers: {
'Content-Type': 'text/plain;charset=utf-8',
},
}).then(function (response) {
console.log(response);
}).catch(function (error) {
console.log(error);
});
Another way for someone who has this problem in the future:
(in my case, using 'Content-Type': 'text/plain;charset=utf-8' doesn't work)
According to this doc https://github.com/axios/axios#using-applicationx-www-form-urlencoded-format
Instead of using text/plain;charset=utf-8 as the accepted answer, you can use application/x-www-form-urlencoded:
const axios = require('axios')
const qs = require('qs')
const url = 'https://script.google.com/macros/s/AKfycbzyc2CG9xLM-igL3zuslSmNY2GewL5seTWpMpDIQr_5eCod7_U/exec'
const data = {
"title": 'Fred',
"lastName": 'Flintstone'
}
const options = {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
url
}
axios(options)
.then(function(response) {
console.log(response.data)
})
.catch(function(error) {
console.log(error)
})
I think you need to return JSON data. It is possible that you need to return JSONP to a request from a browser, but here is what I think you need to do:
return ContentService.createTextOutput(JSON.stringify({message: MyResponse})).setMimeType(ContentService.MimeType.JSON);
If that doesn't work, it is probably that you need to return JSONP to run in the browser. Here is some documentation to help you out: https://developers.google.com/apps-script/guides/content#serving_jsonp_in_web_pages
I'm playing with Google Apps Script utilizing the ActiveCollab HTTPS API as a way to link Google Forms to specific projects. I can't figure out where to use the access token in the HTTP request when creating a Task in a project.
Maybe I'm missing it, but which API calls in the documentation require the access token as part of the POST request?
The most basic POST request I've sent was:
var token = // token from authentication
{
"name": "Test task",
"token": token
}
...and it returned a 401 error, saying I wasn't authenticated.
So, I tried:
var token = // token from authentication
{
"name": "Test task",
"username": // my username,
"password": // my password,
"token": token
}
...with the same result. So, which calls require a token and does the token go in the POST payload? Or should it be in the POST options?
Update 3/10/2016
I have added the Authorization parameter to the POST request and am now receiving an invalid token error in the response. I've cleared my cache and reauthorized successfully. My test function is below.
function postTicket() {
// Retrieve the stored token after a successful authorization
var token = PropertiesService.getScriptProperties().getProperty("token");
var data = {
"name": "Testing task"
}
var headers = {
Authorization: 'Bearer ' + token
};
var options = {
"method": "post",
"contentType": "application/json",
"headers": headers,
"payload": JSON.stringify(data)
}
try {
var url = BASE_URL + "/projects/8/tasks";
var response = UrlFetchApp.fetch(url, options);
var json = response.getContentText();
var data = JSON.stringify(json)
Logger.log(data);
} catch (e) {
Logger.log(e);
}
}
The logged error is:
returned code
500.{"type":"ActiveCollab\Authentication\Exception\InvalidTokenException","message":"Authorization
token is not valid","code":0
I had the same problem, but after checking Active Collab SDK code i figured out, that we should use these headers:
var headers = {
'X-Angie-AuthApiToken': token
};
By using this code i'm allowed to create tasks via API.
Token needs to be sent using Authorization HTTP header:
Authorization: Bearer TOKEN_THAT_YOU_GOT_FROM_ACTIVE_COLLAB
This means that you need to send the token as part of request header, not payload. Please check the Google Apps documentation for details (I see that fetch has headers object as one of the arguments, so there is support for this type of interaction built into the platform).
I am working on a React application and I am using fetch to send a request. I have made a Sign Up form recently and now I am integrating it with it's API. Previously the API accepted url encoded data and it was all working fine. but now that the requirement has changed and the API accepts data in JSON, I had to change the content-type header from 'application/x-www-form-urlencoded' to 'application/json'. But I get the following error:
Fetch API cannot load http://local.moberries.com/api/v1/candidate.
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access. If an opaque response serves your needs, set the request's
mode to 'no-cors' to fetch the resource with CORS disabled.
I have even set the 'Access-Control-Allow-Headers' in the API but it still doesn't work. Here is the relevant code for the client side:
sendFormData() {
let {user} = this.props;
var formData = {
first_name: ReactDOM.findDOMNode(this.refs.firstName).value,
last_name: ReactDOM.findDOMNode(this.refs.lastName).value,
city: ReactDOM.findDOMNode(this.refs.currentCity).value,
country: ReactDOM.findDOMNode(this.refs.currentCountry).value,
is_willing_to_relocate: user.selectedOption,
cities: relocateTo,
professions: opportunity,
skills: skills,
languages: language,
min_gross_salary: minSal,
max_gross_salary: maxSal,
email: ReactDOM.findDOMNode(this.refs.email).value,
password: ReactDOM.findDOMNode(this.refs.password).value
};
var request = new Request('http://local.moberries.com/api/v1/candidate', {
method: 'POST',
mode: 'cors',
headers: new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json'
})
});
var requestBody = JSON.stringify(formData);
console.log(requestBody);
fetch(request, {body: requestBody})
.then(
function (response) {
if (response.status == 200 || response.status == 201) {
return response.json();
} else {
console.log('Failure!', response.status);
}
}).then(function (json) {
var responseBody = json;
console.log(typeof responseBody, responseBody);
});
}
And here is the relevant API code:
class Cors
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
return $next($request)
->header('Access-Control-Allow-Origin', '*')
->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->header('Access-Control-Allow-Headers: Origin, Content-Type, application/json');
}
}
I really can't figure out the problem. Any kind of help will be appreciated.
It turns out that CORS only allows some specific content types.
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
To set the content type to be 'application/json', I had to set a custom content type header in the API. Just removed the last header and added this one:
->header('Access-Control-Allow-Headers', 'Content-Type');
and it is working all good.
You are violating the 'Same Origin Policy'. A website www.example.com may never be able to load resources from any website www.example.net other than from itself.
During development however, sometimes one needs to be able to do that. To bypass this:
either move your origin to http://local.moberries.com,
or move the api (which you are accessing) to your localhost.
Other than that, there are ways to temporarily turn off restrictions of these kinds in some browsers (esp. Chrome), methods of which usually require more and more effort in the subsequent updates of the browser. Search Google about how to turn on Cross-Origin Resource Sharing in your version of the browser.
Or, as the error prompt suggests, introduce a header allowing requests to be entertained from non-origins. More information is in the documentation for Access Control CORS