We want to send authentication token and signature during GET/POST request. We are not preferring to send security information through body Or parameter. So we decided to send through headers in request.
When we googled we got to know that we can do this using ajax post request. But we want to move to next pages with headers.
How we can implement this?
Edited:
We had plan to store these information on cookies. But in iPhone if cookies is disabled will change behaviour of our website. So to overcome we are planning to send through headers.
You can set X-AUTHENTICATION-TOKEN in ajax request something as below which I am using for a real time REST API call via ajax requests.
$.ajax({
type: "GET",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-AUTHENTICATION-TOKEN', 'token string');
},
The server side must set the header something as
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, X_AUTHENTICATION_TOKEN');
And to retrieve the data on server side you may have
if (isset($_SERVER['HTTP_X_AUTHENTICATION_TOKEN'])) {
$request_header = $_SERVER['HTTP_X_AUTHENTICATION_TOKEN'];
} else {
if (function_exists('getallheaders')) {
foreach (getallheaders() as $header_name => $header_value) {
if ($header_name == 'X_AUTHENTICATION_TOKEN') {
$request_header = $header_value;
}
}
}
}
So here $request_header will be the token and you can use this in the server side script for validation.
Related
Even though I set the headers in the file functions.php, the error keeps appearing, I tried with several different hooks:
function add_cors_http_header()
{
if (isset($_SERVER['HTTP_ORIGIN'])) {
// Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
// you want to allow, and if so:
// header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400'); // cache for 1 day
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
// may also be using PUT, PATCH, HEAD etc
header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT");
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
exit(0);
}
}
add_action('init', 'add_cors_http_header');
add_action('send_headers', 'add_cors_http_header');
add_action('rest_pre_serve_request', 'add_cors_http_header');
(Not all add_action at the same time)
And I also tried without the isset and in the header.php
EDIT ---
As requested, the client that is running is Vanilla Javascript, I made the same fetch on Postman and it worked, it's about joining a user to a guild in discord, hre is the code:
const args = JSON.stringify({
access_token: token,
});
const response = await fetch(
`https://discord.com/api/guilds/${this.guildID}/members/${userID}`,
{
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `BOT ${this.bot_token}`,
},
body: args,
}
);
Access-Control-Allow-Origin (and similar headers) are for the server to define, and not the client. In this case, the server is the Discord API.
I'm guessing the confusion here is that your client is JavaScript, but you're trying to modify the headers in PHP. I think you should try to add the headers in JavaScript directly. Perhaps there's an Origin header you need?
I suggest looking at your Postman headers being sent and add them right in your JavaScript. For example:
headers: {
"Content-Type": "application/json",
Authorization: `BOT ${this.bot_token}`,
Origin: "http://localhost",
},
If that doesn't work, open your Chrome Dev Tools, open the Network tab, and look at the outgoing request, and see what headers it is sending and compare them with Postman. If Postman can work, just repeat what it is doing.
Regarding the WordPress function, I think you can remove it entirely as JavaScript is the client, not PHP/WordPress.
I'm trying to send some HTTP requests from my angular.js application to my server, but I need to solve some CORS errors.
The HTTP request is made using the following code:
functions.test = function(foo, bar) {
return $http({
method: 'POST',
url: api_endpoint + 'test',
headers: {
'foo': 'value',
'content-type': 'application/json'
},
data: {
bar:'value'
}
});
};
The first try ended up with some CORS errors. So I've added the following lines to my PHP script:
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT');
header('Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding, X-Auth-Token, content-type');
The first error is now eliminated.
Now the Chrome's developer console shows me the following errors:
angular.js:12011 OPTIONS http://localhost:8000/test (anonymous
function)
423ef03a:1 XMLHttpRequest cannot load
http://localhost:8000/test. Response for preflight has invalid HTTP
status code 400
and the network request looks like I expected (HTTP status 400 is also expected):
I can't imagine how to solve the thing (and how to understand) why the request will send on localhost as OPTIONS and to remote servers as POST. Is there a solution how to fix this strange issue?
TL;DR answer
Explanation
The OPTIONS request is so called pre-flight request, which is part of Cross-origin resource sharing (CORS). Browsers use it to check if a request is allowed from a particular domain as follows:
The browser wants to send a request to a particular URL, let's say a POST request with the application/json content type
First, it sends the pre-flight OPTIONS request to the same URL
What follows depends on the pre-flight request's response HTTP status code:
If the server replies with a non-2XX status response, the browser won't send the actual request (because he knows now that it would be refused anyway)
If the server replies with a HTTP 200 OK (or any other 2XX) response, the browser will send the actual request, POST in your case
Solution
So, in your case, the proper header is present, you just have to make sure the pre-flight request's response HTTP status code is 200 OK or some other successful one (2XX).
Detailed Explanation
Simple requests
Browsers are not sending the pre-flight requests in some cases, those are so-called simple requests and are used in the following conditions:
One of the allowed methods:
- GET
- HEAD
- POST
Apart from the headers automatically set by the user agent (for example, Connection, User-Agent, etc.), the only headers which are allowed to be manually set are the following:
Accept
Accept-Language
Content-Language
Content-Type (but note the additional requirements below)
DPR
Downlink
Save-Data
Viewport-Width
Width
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded
multipart/form-data
text/plain
No event listeners are registered on any XMLHttpRequestUpload object used in the request; these are accessed using the XMLHttpRequest.upload property.
No ReadableStream object is used in the request.
Such requests are sent directly and the server simply successfully processes the request or replies with an error in case it didn't match the CORS rules. In any case, the response will contain the CORS headers Access-Control-Allow-*.
Pre-flighted requests
Browsers are sending the pre-flight requests if the actual request doesn't meet the simple request conditions, the most usually:
custom content types like application/xml or application/json, etc., are used
the request method is other than GET, HEAD or POST
the POST method is of an another content type than application/x-www-form-urlencoded, multipart/form-data or text/plain
You need to make sure that the response to the pre-flight request has the following attributes:
successful HTTP status code, i.e. 200 OK
header Access-Control-Allow-Origin: * (a wildcard * allows a request from any domain, you can use any specific domain to restrict the access here of course)
From the other side, the server may refuse the CORS request simply by sending a response to the pre-flight request with the following attributes:
non-success HTTP code (i.e. other than 2XX)
success HTTP code (e.g. 200 OK), but without any CORS header (i.e. Access-Control-Allow-*)
See the documentation on Mozilla Developer Network or for example HTML5Rocks' CORS tutorial for details.
I ran into a very similar problem writing an Angular 2 app - that uses a NODE server for the API.
Since I am developing on my local machine, I kept getting Cross Origin Header problems, when I would try to POST to the API from my Angular app.
Setting the Headers (in the node server) as below worked for GET requests, but my PUT requests kept posting empty objects to the database.
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT');
header('Access-Control-Allow-Headers: X-Requested-With, Content-Type,
Origin, Authorization, Accept, Client-Security-Token, Accept-
Encoding, X-Auth-Token, content-type');
After reading Dawid Ferenczy's post, I realized that the PREFLIGHT request was sending blank data to my server, and that's why my DB entries were empty, so I added this line in the NODE JS server:
if (req.method == "OPTIONS")
{
res.writeHead(200, {"Content-Type": "application/json"});
res.end();
}
So now my server ignores the PREFLIGHT request, (and returns status 200, to let the browser know everything is groovy...) and that way, the real request can go through and I get real data posted to my DB!
Just put
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header("HTTP/1.1 200 ");
exit;}
at the beginning of your serverside app and you should be fine.
For spring boot application, to enable cors request, use #CrossOrigin(origins = "*", maxAge = 3600) on your respective controller.
Refer this doc
The best is to :
have proxy.conf.json set:
{
"/api": {
"target": "http://localhost:8080",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
}
}
And then to make sure that URL that you are using in angular to send a request is relative (/api/something) and not absolute (localhost:8080/api/something). Because in that case the proxy won't work.
From Chrome v79+, OPTIONS Check(pre-flight request) will no longer appear in the network tab-Source
I'm building an API, for training purposes. I now have to send a POST request containing information. I'm using React JS and PHP, the problem is that everytime I send a request, the CORS error still shows up on the browser.
My JS file that sends the POST is, I changed the URL, because it's on my personal server:
axios.post('https://myurl/api/book/create.php', {
data: JSON.stringify(values, 0, 2)
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
and on the server side, I have the following
<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
With postman the request goes smoothly, but every single time sending through the browser
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://myurl/api/book/create.php. (Reason: CORS request did not succeed
Please make sure that you allow CORS in backend server. Then, you need send header for axios like following example
axios.defaults.headers.post['Content-Type'] = 'application/json';
axios.defaults.withCredentials = true;
axios.defaults.crossDomain = true;
(Or setting it in third paramenter after data)
You have to use either localhost or 127.0.0.1 for all the requests. In general in your code you should make calls to the server by just appending the URI to the current host, without re-adding the host and port in the URI string.
Answer based on: CORS request did not succeed
I have bookmarklet. If I open a random page (not mine) and click the bookmarklet, I would like to check if the user is logged in on my page.
I am already doing Cross-Domain AJAX Request using Access-Control-Allow-Origin, but it looks like there is not Session ID or cookie send here.
Is there a way to do this?
Alex is right! Here the full solution. (It does not work with IE8 and IE9!)
You need to set withCredentials on the client side. Since jQuery 1.5.1 you can do it like shown below (Source). For older Version follow the white rabbit.
$.ajax({
url: a_cross_domain_url,
xhrFields: {
withCredentials: true
}
});
On the server side you have to allow setting options, allow the credentials and allow to origin. Wildcard origin is not allowed! But you can read out the origin from the request header :)
// auto adapted Access Control to origin from request header.
$headers = apache_request_headers();
foreach ($headers as $header => $value) {
if ($header == 'Origin')
header('Access-Control-Allow-Origin: ' . $value, true);
}
// send cookies from client
header('Access-Control-Allow-Credentials: true', true);
// allow all methods
header('Access-Control-Allow-Methods: GET, POST, OPTIONS', true);
You have to set the credentials flag to true and also the header Access-Control-Allow-Credentials
See also here: Firefox: Cross-domain requests with credentials return empty
I am trying to request JSON from Google Places API, but I am still getting the cross-domain request error after firstly including:
<?php
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Methods: POST, GET");
header("Access-Control-Allow-Headers: x-requested-with");
?>
The JSON request I am using is standard JQuery:
function load() {
var url = 'https://maps.googleapis.com/maps/api/place/details/json?reference=CnRhAAAARMUGgu2CeASdhvnbS40Y5y5wwMIqXKfL-n90TSsPvtkdYinuMQfA2gZTjFGuQ85AMx8HTV7axABS7XQgFKyzudGd7JgAeY0iFAUsG5Up64R5LviFkKMMAc2yhrZ1lTh9GqcYCOhfk2b7k8RPGAaPxBIQDRhqoKjsWjPJhSb_6u2tIxoUsGJsEjYhdRiKIo6eow2CQFw5W58&sensor=true&key=xxxxxxxxxxxxxx';
$.ajax(url, {
async: true,
success: function(data, textStatus, jqXHR) {
dump(data);
}
});
}
I would use a JSONP query instead, but the Google Places API doesn't support JSONP...how can I solve this? With a proxy server? I am not sure how to go about this or what I'm doing wrong.
The URL you are requesting data from has to grant permission with access control headers. It would defeat the object of the same origin policy is a remote origin could grant permission to itself!
If the API you are using doesn't provide a JSON-P API, and doesn't set access control headers itself, then you need to use a proxy. Either one you run yourself, or a third party one that will convert to JSON-P (such as YQL).