angular 4 not send cookie to server - javascript

When I use withCredentials I can see that cookies are sent to the server. But are send anything to the server. I use laravel as backend and angular 4 as frontend.
also, the cookie not shown on chrome developer tools and I can't access them using.
also, I used Cors middleware in laravel like:
<?php
namespace App\Http\Middleware;
use Closure;
class Cors
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$response->headers->set('Access-Control-Allow-Origin', 'http://localhost:4200');
$response->headers->set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
$response->headers->set('Access-Control-Allow-Headers', 'Content-Type, Accept, Authorization, X-Request-With');
$response->headers->set('Access-Control-Expose-Headers', 'Content-Disposition, x-total-count, x-filename');
$response->headers->set('Access-Control-Allow-Credentials', 'true');
return $response;
}
}
and when I request first time to the server for set cookie, these below response show:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type, Accept, Authorization, X-Request-With
Access-Control-Allow-Methods:GET, POST, OPTIONS, PUT, PATCH, DELETE
Access-Control-Allow-Origin:http://localhost:4200
Access-Control-Expose-Headers:Content-Disposition, x-total-count, x-filename
Cache-Control:no-cache, private
Connection:keep-alive
Content-Type:application/json
Date:Tue, 02 Jan 2018 09:04:32 GMT
Server:nginx/1.11.9
Set-Cookie:refreshToken=def502005a2ccf60eafdee2137df25a628d49f70c4571bedde628d50e45c0fe4b73f84f86bb469f0f77247dc2abc13c0c5c938027beb13fe534eb7bb41f4aed99faf49ebf2a238a007ce9514108951366db45a311d70d17d65dd48f5df6aa50f257c828cce16e589983c1e06c9e8d7d52806a1a9401569f87b3a394469e938c4ddbfcc7985e257d8f0d0df416e7b8a5bbd19e86050db3be5b90953c515934f529489f4e0ba62fb66ab883d1689349bbfb962332bceb322d978b7d20fa7e32bb94eb0050d8f94bfd3a780c4edfeea8eaa6954222b57c30229c2494fec38ee5292396400b25fadee04cad1729f9e9b9ccf12d21a6ed3f9663d41c5423536e64f83542df19fcede28247bfc12accf354e035182c3e019e4a2b55c807924cc50a12fa187b2f655fb19c1b42a1ae526763dd08dbd0d288b3a9c649216ab1abc60cd51bb97dfb0cb7b7b020ff270cf5c81bc94f2acd40f92edeefaf585d46d0750bf; expires=Sun, 25-Aug-2019 09:04:32 GMT; Max-Age=51840000; path=/; HttpOnly
Transfer-Encoding:chunked
X-RateLimit-Limit:60
X-RateLimit-Remaining:58
and when I request from frontend:
refreshToken(){
const headers = new Headers({ 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.getToken()})
let options = new RequestOptions({ headers: headers, withCredentials: true });
return this.http.post(API_DOMAIN + 'refresh', JSON.stringify({}), options)
.map(
(response) => {
console.log(response);
return response.json()
},
)
.do(
tokenData =>{
localStorage.setItem('token', tokenData.access_token)
localStorage.setItem('expires_in', tokenData.expires_in)
}
)
}
chrome develope:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type, Accept, Authorization, X-Request-With
Access-Control-Allow-Methods:GET, POST, OPTIONS, PUT, PATCH, DELETE
Access-Control-Allow-Origin:http://localhost:4200
Access-Control-Expose-Headers:Content-Disposition, x-total-count, x-filename
Cache-Control:no-cache, private
Connection:keep-alive
Content-Type:application/json
Date:Tue, 02 Jan 2018 08:57:28 GMT
Server:nginx/1.11.9
Transfer-Encoding:chunked
X-RateLimit-Limit:60
X-RateLimit-Remaining:59
Front and back servers use different ports.

You can's save cookies because your development node.js server and your Laravel Vagrant box are on different domains. What you can do is to proxy calls from node.js to the the Laravel server.
Create proxy.conf.json in the root of Angular app. Put an object with routes inside:
{
"/api": {
"target": "http://mydomian.test/",
"secure": false
}
}
I just have /api defined here because all my backend URIs are inside api.php. All calls that look like http://localhost:4200/api/someitems/1 will be proxied to http://mydomian.test/api/someitems/1.
Then edit package.json and change the value of start inside scripts to ng serve --proxy-config proxy.conf.json. Now npm run start will start with proxy. The problem I had with this proxy is that it resolves your URL (http://mydomian.test/) to an IP. When it calls Laravel with just an IP the nginx server does not know what to do because it must receive a domain name. nginx allows multiple website on the same IP so it must receive a domain name or to have a default website to which it redirects all calls those have no domain name. In case this is still not fixed in Angular's proxy go to /etc/nginx/sites-available on the Laravel machine, you'll have a mydomian.test config file there. It has listen 80; line there, change it to listen 80 default;.
Now you can change the API_DOMAIN variable to http://localhost:4200 (or remove it all together) and disable the CORS.

Related

Why is the CORS Response Cookie not stored in Browser?

The Frontend JavaScript sends a CORS fetch POST with login credentials to the backend. However the Set-Cookie (for authentication) in the response from the backend is not stored in the browser, why is that the case?
The Set-Cookie is shown in the fetch response and gets recognized as a http Cookie from the browser, however it doesn't get saved.
I've been through a lot of entries on this issue and checked things like "credentials: 'include'", the correct Response Headers and SameSite properties of the cookie.
Would really appreciate someone's expert opinion, since I couldn't resolve the issue for days now. ;)
This is the webpage for login:
https://www.evs-media.com/tests/t5
For the backend I'm using a Rest API No-Code Tool: https://www.xano.com
Domain Frontend: https://www.evs-media.com
Domain Backend API: https://x8ki-letl-twmt.n7.xano.io/api:s900chrT
On the backend server-side this is what the Request Header looks like:
"Sec-Fetch-Site: cross-site",
"Sec-Fetch-Mode: cors"
"Sec-Fetch-Dest: empty"
"Dnt: 1","Origin: https://www.evs-media.com"
"Content-Type: multipart/form-databoundary=---------------------------32748419764181237672921298736"
"Referer: https://www.evs-media.com/"
"Accept-Encoding: gzip, deflate, br"
"Accept-Language: en-US,en;q=0.5"
"Accept: */*","User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Firefox/102.0"
"Content-Length: 295"
"X-Scheme: https"
"X-Forwarded-Scheme: https"
"X-Forwarded-Proto: https"
"X-Forwarded-Port: 443"
"X-Forwarded-Host: x8ki-letl-twmt.n7.xano.io"
"X-Forwarded-For: 79.242.71.235"
"X-Real-Ip: 79.242.71.235"
"X-Request-Id: c459f42dad416f9b5d0d53df307632e9"
"Host: x8ki-letl-twmt.n7.xano.io"
This is the Response Header on the backend server-side:
"Accept-Ranges: none"
"X-XSS-Protection: 1; mode=block"
"X-Frame-Options: deny"
"Access-Control-Allow-Methods: GET, POST, DELETE, PUT, PATCH, OPTIONS, HEAD"
"Access-Control-Allow-Headers: Cache-Control, Content-Type, Content-Length, Authorization, Accept, Accept-Encoding, User-Agent, X-Requested-With, X-APP-KEY, X-Data-Source, X-Branch"
"Access-Control-Allow-Credentials: true"
"Access-Control-Max-Age: 86400"
"X-App: hit"
"set-cookie: myfirstcookie= Bearer eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiemlwIjoiREVGIn0.jowMcpyEUJZPSxDuIWbGRT2IMabWHfYkBX9tr0_t0agn8wkAKFlc5tUPGpAdKf-9Rhgo8IE5oCwKTNJ0hL1VqZv2D4Vl2XJC.614vZOklc-w9tlAcpxf8Sw.d1OGC6ownAZid1q0XwbGOVP_AKTCMuPG9ehcCbG2iklLHzAeela9r_78t5IN30FwcgHkxNPlh0opQuw5t1DXqjosVTWwgdFzOhv_Add4vznjo_Gd6bv-tnFOLeQVlcfLb3CNzGvHcC8rII9rEy_HjcNx9Xv9DqXIM7i2KPYf33Q.mLjsCPzAUINdZLPydsJyaHNI8v6AISAU8mvz0pRrLw4; Expires=Wed 20 Jul 2022 07:28:00 GMT; Max-Age=2592000; Domain=.x8ki-letl-twmt.n7.xano.io/api:s900chrT; path=/; SameSite=None; Secure; HttpOnly;"
"Access-Control-Allow-Origin: https://www.evs-media.com"
"Access-Control-Expose-Headers: Set-Cookie"
"Content-Type: application/json; charset=UTF-8"
This is what the Request Headers look like on the frontend client-side:
Screeenshot of Request Headers
This is the fetch JavaScript on the frontend:
const myForm = document.getElementById('myForm');
myForm.addEventListener('submit', function (e) {
e.preventDefault();
const formData = new FormData(this);
fetch('https://x8ki-letl-twmt.n7.xano.io/api:s900chrT/auth/logintest', {
method: 'POST',
credentials: 'include' ,
body: formData
}).then(function (response) {
return response.text();
}).then(function (text) {
console.log(text);
}).catch(function (error) {
console.error(error);
})
})

Not Receiving Set-Cookie Header with axios post request

I have a PHP Script which successfully returns some simple Headers as well as a set-cookie header if called directly in the browser (or by postman). I can read the response-headers like that from chrome devTools. But as soon as I call it by Axios, the set-cookie header doesn't show up and there's no cookie saved in the browser.
I tried diffrent things like changing the response-headers server-side and using "withCredentials: true" with axios, but nothing worked. I don't even get an error or any cors-related problems.
PHP:
header("Access-Control-Allow-Origin: http://localhost:8080");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST, GET");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
header("Access-Control-Max-Age: 99999999");
setcookie("TestCookie", "Testing", time() + 3600, "/", "localhost", 0);
die();
JS:
Vue.prototype.$http = axios.create({
baseURL: XYZ,
withCredentials: true
})
So my first question is why does the header appear when calling the php script directly? And how can I archive to get the header through axios too?
probably cookie is 'httpOnly', which means client side javascript can not read it.
Therefore it is not showing in chrome cookie section.
test the same request in mozilla, header will show up.
This may not apply to your situation, but I had the same problem using axios in this standalone nodejs script.
const config = {
url: 'https://remote.url/login',
method: 'post',
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
data: qs.stringify({
'email': username,
'password': pwd
})
}
axios(config).then(res => {
console.log(res.headers);
}).catch(err => {
console.log(err);
})
This returned http status 200 without set-cookie in the headers. With curl the header was correctly retrieved, but the status code was 302
After adding the following config options to axios:
maxRedirects: 0,
validateStatus: function (status) {
return status <= 302; // Reject only if the status code is greater than 302
},
I received the set-cookie in axios in the response.header.
{
server: 'nginx/1.16.1',
date: 'Fri, 27 Dec 2019 16:03:16 GMT',
'content-length': '74',
connection: 'close',
location: '/',
'set-cookie': [
'cookiename=xxxxxxxxxxxxxxxxxxxxx; path=/; expires=Sat, 26-Dec-2020 16:03:16 GMT'
],
status: '302',
'x-frame-options': 'DENY'
}
Without maxRedirects: 0 I received the html of the homepage of the remote url I used.
Without validateStatus I received the set-cookie header in the err.response.headers object.
In my case, the network panel showed that the response had the 'Set-Cookie' header, but in axios the header wouldn't show up, and the cookie was being set.
For me, the resolution was setting the Access-Control-Expose-Headers header.
Explanation:
From this comment on an issue in the axios repository I was directed to this person's notes which led me to set the Access-Control-Expose-Headers header -- and now the cookie is properly setting in the client.
So, in Express.js, I had to add the exposedHeaders option to my cors middleware:
const corsOptions = {
//To allow requests from client
origin: [
"http://localhost:3001",
"http://127.0.0.1",
"http://104.142.122.231",
],
credentials: true,
exposedHeaders: ["set-cookie"],
};
...
app.use("/", cors(corsOptions), router);
It was also important that on the axios side I use the withCredentials config in following axios requests that I wanted to include the cookies.
ex/
const { data } = await api.get("/workouts", { withCredentials: true });
For me is working adding {withCredentials: true} like this:
axios
.post(url, {
foo: foo,
baz: baz,
}, {withCredentials: true})
.then(.............

server responds with 405 error even with 'Access-Control-Allow-Origin': '*'?

SO my graphql api is at https://gpbaculio-tributeapp.herokuapp.com/graphql I configured the uploaded, headers like this:
const fetchQuery = (operation, variables) => {
return fetch('/graphql', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify({
query: operation.text,
variables,
}),
}).then(response => {
return response.json()
})
}
I have read from MDN.
For requests without credentials, the server may specify "*" as a
wildcard, thereby allowing any origin to access the resource.
So I am trying to publish the app in codepen, and this is my error:
Failed to load https://gpbaculio-tributeapp.herokuapp.com/graphql:
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'https://s.codepen.io'
Why is it telling me it doesn't pass 'Access-Control-Allow-Origin' headers?
Is there something wrong with my headers config?
You are setting the header in your request (in the client). The Access-Control-Allow-Origin header needs to be set on the server-side, and when you make a request, the response should contain that header.
The reason behind this header is that not every webpage can query every third-party domain. Being able to set this header from the request would defeat that whole point.
Try setting cors options and Access-Control-Allow-Origin headers in server side.
const graphQLServer = express();
const corsOptions = {
origin(origin, callback) {
callback(null, true);
},
credentials: true
};
graphQLServer.use(cors(corsOptions));
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
}
graphQLServer.use(allowCrossDomain);
This may help you
CORS specification states, that requests for resources are "preflighted" with HTTP OPTIONS request, and reply headers for that OPTIONS must contain header:
Access-Control-Allow-Origin: *
you might check it with curl:
$ curl -I -X OPTIONS https://gpbaculio-tributeapp.herokuapp.com/graphql
HTTP/1.1 405 Method Not Allowed
Server: Cowboy
Connection: keep-alive
X-Powered-By: Express
Allow: GET, POST
Content-Type: application/json; charset=utf-8
Content-Length: 97
Date: Sat, 23 Sep 2017 11:24:39 GMT
Via: 1.1 vegur
Add OPTION handler with needed header, so your server answers:
$ curl -I -X OPTIONS https://example.localhost/
HTTP/1.1 204 No Content
Server: nginx/1.4.7
Date: Sat, 23 Sep 2017 11:27:51 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range
Content-Type: text/plain; charset=utf-8
Content-Length: 0
The problem is the browser's cross-origin problem.
The Access-Control-Allow-Origin header should be return by the server's response, and the header means the origin domain that can access to the API.
The client's request often take a header Origin, it's value is the current host address, like, www.example.com.
The values of Access-Control-Allow-Origin must contain the value of Origin means that the origin can access this API service. And then the browser will continue the request. If not, the browser will cancel the request.
More infomation, refre to CORS https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

Error HTTP GET object list

I get an error when I try to retrieve a list of objects from a link (php server).
Blocking of a multi-origin request (cross-origin request): the "same
source" policy does not allow access to the remote resource located at
http: //localhost/eReport/index.php. Reason:
"Access-control-authorization-origin" token missing in the CORS
"Access-Control-Allow-Headers" CORS header.
I added a header like this tuto that is recommended on this link but I still have this error.
Can you help me please ?
My Service page:
#Injectable()
export class ReportService{
private baseUrl: string = 'http://localhost/report/reports.php';
constructor(private http : Http){}
getAll(): Observable<Report[]>{
let report$ = this.http
.get(`${this.baseUrl}`, { headers: this.getHeaders()})
.map(mapReports);
return report$;
}
private getHeaders(){
// I included these headers because otherwise FireFox
// will request text/html
let headers = new Headers();
headers.append('Accept', 'application/json');
headers.append('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8');
return headers;
}
get(id: number): Observable<Report> {
let report$ = this.http
.get(`${this.baseUrl}/report/${id}`, {headers: this.getHeaders()})
.map(mapReport);
return report$;
}
My php page
header("Access-Control-Allow-Origin: *");
$tab = array(
array('id'=> '12', 'name'=> 'test','description' => '2018-04-01','url'=>'../../../assets/img/chat1.png' ),
array('id'=> '13', 'name'=> 'test','description' => '2018-04-01','url'=>'../../../assets/img/highcharts.png' )
);
echo json_encode($tab);
?>
Perhaps the quickest fix is to change your base url in the Angular app to /report/reports.php if the requests are going to the same server that served the app.
Your request is not working because when the client sends content of type application/json, the browser doesn't send the request right away. If you restart your browser then observe the network tab you will notice that instead of your GET, an OPTIONS request is first send, that includes headers similar to these:
Origin: yourserver
Access-Control-Request-Method: GET
Access-Control-Request-Headers: Content-Type, Accept
In this scenario, the browser expects the server to return not just the Access-Control-Allow-Origin header (which you're already doing), but all of these:
Access-Control-Allow-Origin: yourserver (or *)
Access-Control-Allow-Methods: GET (or a list eg: GET, POST, OPTIONS)
Access-Control-Allow-Headers: Content-Type, Accept (the same headers from above)
So you need to read the request headers from the previous block, and use their values when setting the response headers. If you have the apache_request_headers() method it's pretty easy. You can also get them from the $_SERVER superglobal.
// set required headers:
header("Access-Control-Allow-Origin: $_SERVER[HTTP_ORIGIN]");
header("Access-Control-Allow-Methods: $_SERVER[HTTP_ACCESS_CONTROL_REQUEST_METHOD]");
header("Access-Control-Allow-Headers: $_SERVER[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]");
See this helpful article

Cross-Origin Request Blocked Angular JS Put request

I'm developing a REST-ful application using Yii framework for the server side and Angular JS for the client side
I'm using the restfulyii extension to generate the api
:And I'm facing a problem when I'm sending a PUT request.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ..... This can be fixed by moving the resource to the same domain or enabling CORS.
But it's working for post + get requests
I saw different solutions but none of them worked.
I tried to put those is server side
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: x-requested-with, Content-Type, origin, authorization, accept, client-security-token");
header("Access-Control-Max-Age: 1000");
and tried to put this code in the angular js module:
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
and also I tried to put
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
The request converted into OPTIONS request
and the response from the server became as following:
Access-Control-Allow-Headers:x-requested-with, Content-Type, origin, authorization, accept, client-security-token
Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-
Origin:http://localhost:8383
Access-Control-Max-Age:1000
Connection:close
Content-Type:text/html Date:Fri, 24 Oct 2014 06:49:32 GMT
Server:Apache/2.4.7 (Win32) OpenSSL/1.0.1e PHP/5.5.9 X-Powered-By:PHP/5.5.9
I have a base controller for all my rest controllers that use restangular which has the following events.
public function restEvents()
{
$this->onRest('req.cors.access.control.allow.origin', function() {
return ['*']; //List of sites allowed to make CORS requests
});
$this->onRest('req.cors.access.control.allow.methods', function() {
return ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']; //List of allowed http methods (verbs)
});
$this->onRest('req.auth.cors', function ($allowed_origins) {
if (in_array('*', $allowed_origins)) {
return true;
}
if((isset($_SERVER['HTTP_ORIGIN'])) && (( array_search($_SERVER['HTTP_ORIGIN'], $allowed_origins)) !== false )) {
return true;
}
return false;
});
$this->onRest('req.cors.access.control.allow.headers', function($application_id) {
return ["X_{$application_id}_CORS", "Content-Type", "Authorization", "X_REST_REQUEST"];
});
}
Client side I am using restangular with the following options:
RestangularProvider.setDefaultHttpFields({withCredentials: true});
RestangularProvider.setDefaultHeaders({X_REST_CORS: 'Yes'});
RestangularProvider.setDefaultHttpFields({cache: false});
I hope this helps....

Categories