Angular.js http GET request, CORS issue while sending cookies - node.js

I'm working on a project using node.js and express.js on server side, and angular.js on client side. I've set up authentication on server side using passport.js. So when I login the session cookie is set up and I can access the api via browser with no problem. But when I try to request the url of the api in angular.js with http, I get "cors blocked" (yeah, I made that up). Server allows credentials, client sends withCredentials: true. What is the problem?
Funny thing is server and client are not even in different domains. They are both in localhost. But since server "cors blocked" me in the very beginning, I've enabled cors.
So I have server and client in the same domain. Corse is enabled in server and I still can't send my cookies.
Response Headers
Access-Control-Allow-Orig... *
Connection keep-alive
Content-Length 33101
Content-Type application/json
Date Sun, 18 May 2014 15:02:41 GMT
Etag "-796401813"
X-Powered-By Express
access-control-allow-cred... true
Request Headers
Accept application/json, text/plain, */*
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Cookie prgck=s%3AGb1ZXuD0uXHoBbFWIcrmkSFt.%2BNt0pdVa1%2BNhUNITAPOzPjmQxklPpDrdvQz%2BACj084o
Host localhost:1212
Origin http://localhost:8000
Referer http://localhost:8000/app/
User-Agent Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:29.0) Gecko/20100101 Firefox/29.0

It is not clear what you did on your Express server, but looking at the headers you posted it seems you enabled Access-Control-Allow-Credentials but you did not define the Access-Control-Allow-Origin.
This latter is necessary to actually enable CORS. So your Express server must set both:
Access-Control-Allow-Origin: http://my.domain.com:8080
Access-Control-Allow-Credentials: true;

Related

Express JS/ Node JS : Browsers are not setting cookie when secure=true, sameSite: 'none'

it sets the cookie if I run the server locally, but when it is hosted online :
If secure=false, sameSite: 'none' then I get the following error
Cookie “connect.sid” will be soon rejected because it has the
“sameSite” attribute set to “none” or an invalid value, without the
“secure” attribute. To know more about the “sameSite“ attribute, read
https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie/SameSite
then I tried with secure=true
if secure=true, sameSite: 'none' then I know it's supposed to work,
it works and the cookies are set when the server is hosted locally.
But when it is hosted in heroku the cookie are not set, and I get no
error.
It seems as if the client website is not secure but it shows https in the url box
What am I doing wrong here?
session config:
router.use(
session({
cookie: {
secure: true,
maxAge: 86400,
sameSite: "none",
},
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
})
);
note : I have already enabled cors with credentials set to true
The cookies tab was empty in the XHR cookies tab
Front-end and Back-end are hosted separately in heroku
XMLHttpRequest is used to send post request with withCredentials set to true.
XHRPOSThttps://sih-drs-prototype-backend-2.herokuapp.com/api/outrages/login
[HTTP/1.1 200 OK 1625ms]
POST
https://sih-drs-prototype-backend-2.herokuapp.com/api/outrages/login
Status200
OK
VersionHTTP/1.1
Transferred367 B (2 B size)
Access-Control-Allow-Credentials
true
Access-Control-Allow-Origin
https://tempautocomplete.herokuapp.com
Connection
keep-alive
Content-Length
2
Content-Type
application/json; charset=utf-8
Date
Sun, 12 Jul 2020 14:06:42 GMT
Etag
W/"2-vyGp6PvFo4RvsFtPoIWeCReyIC8"
Server
Cowboy
Vary
Origin
Via
1.1 vegur
X-Powered-By
Express
Accept
*/*
Accept-Encoding
gzip, deflate, br
Accept-Language
en-US,en;q=0.5
Connection
keep-alive
Content-Length
46
Content-Type
application/json;charset=UTF-8
Host
sih-drs-prototype-backend-2.herokuapp.com
Origin
https://tempautocomplete.herokuapp.com
Referer
https://tempautocomplete.herokuapp.com/static/
User-Agent
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0
The problem is not with expres-session, It does its job.
The browsers are not allowing cookies when the response comes from a 3rd party domain.
if you are looking for a workaround try this npm package :
should-send-same-site-none
https://www.npmjs.com/package/should-send-same-site-none
to be clear, the browser is not rejecting the cookies. Instead the cookies are stored in the name of the 3rd party domain name from which the response is sent.
It works perfectly fine when hosting locally since the request and the response would be from the same domain (localhost)
The settings, as posted in the original question are OK, only one thing was missing since Heroku might be using a proxy. I ran into the same problem and when I added:
app.set('trust proxy', 1);
The Set-Cookie header was finally sent from the Express server, hosted on Heroku to the browser.

Receiving webhook in express from local application

I have an application (headless CMS) running locally. It has an option to send a webhook to another application. I have been trying to interpret this webhook via express using posts. I have not been able to even get it to register a request coming in from the application. I tested this route using postman and found that it is working when I post to it.
router.post('/', (req, res) => {
console.log("Recieved");
console.log(req.body);
res.status(200).send('ok')
});
Thus, when I send a post to: http://localhost:3000/recall via postman. I get the following header back:
Access-Control-Allow-Credentials →true
Access-Control-Allow-Headers →X-Requested-With,content-type
Access-Control-Allow-Methods →GET, POST, OPTIONS, PUT, PATCH, DELETE
Access-Control-Allow-Origin →http://localhost:3000
Connection →keep-alive
Content-Length →2
Content-Type →text/html; charset=utf-8
Date →Mon, 03 Sep 2018 21:23:22 GMT
ETag →W/"2-eoX0dku9ba8cNUXvu/DyeabcC+s"
X-Powered-By →Express
With the body:
ok
My script also prints the body of the post.
I can verify the webhook is working by testing it with request bin. I get back the following:
FORM/POST PARAMETERS
None
HEADERS
Cloudfront-Forwarded-Proto: http
Cloudfront-Is-Mobile-Viewer: false
Cloudfront-Is-Desktop-Viewer: true
Connect-Time: 1
Via: 1.1 3566cbcd49f71967b52a565888e4d272.cloudfront.net (CloudFront), 1.1 vegur
Content-Length: 387
Connection: close
Accept: */*
Content-Type: application/json
Cloudfront-Viewer-Country: US
X-Amz-Cf-Id: dRe5CvkLFJZJNcpZbhmeEHo0ar_taj6guvN8utwkyVXM7ZMJc5BZTw==
Cloudfront-Is-Smarttv-Viewer: false
X-Request-Id: 4b6d2cdc-5c45-495b-b358-2e808e1bfeb4
Cloudfront-Is-Tablet-Viewer: false
Total-Route-Time: 0
Host: requestbin.fullcontact.com
BODY
{"event":"singleton.remove","hook":"Save After Sington","backend":1,"args":[{"name":"Wonder","label":"Wonder","_id":"Wonder5b8cef36a0097","fields":[{"name":"Best","label":"","type":"text","default":"","info":"","group":"","localize":false,"options":[],"width":"1-1","lst":true,"acl":[]}],"template":"","data":null,"_created":1535962934,"_modified":1535962934,"description":"","acl":[]}]}
I tried enabling cross-origin requests. How could I fix this problem? My thought is it has something to do with the fact this request is originating and ending locally.
For an application to consume webhooks it needs to have a publicly accessible URL. Basically, the rest of the world (internet) doesn't know your localhost:3000 endpoints exist.
An easy way to fix this is to use a lightweight tool like ngrok to expose your local server; in turn allowing other applications to communicate with yours.
You will need to define the specific callback route that you want to consume the webhook POST request. Examples below.
Run your node script
Turn on ngrok
send webhook POST requests to your endpoint using the NGROK https address
Now, instead of sending your webhook to localhost:8000/MyWebhookConsumingEndpoint
you send it to
https://95e26af4.ngrok.io/MyWebhookConsumingEndpoint

CORS Header Missing on Angular Resource Requests Only

I have a working node/express backend running on localhost. I'm building a project application that needs to fetch data from goodreads api. When I execute the request, I get:
Cross-Origin Request Blocked:
The Same Origin Policy disallows reading the remote resource at
https://www.goodreads.com/book/title.json?author=Arthur+Conan+Doyle&key=[my_key]&title=Hound+of+the+Baskervilles.
(Reason: CORS header 'Access-Control-Allow-Origin' missing).1 <unknown>
Server side, everything is working correctly. I have enabled CORS, and when I check the headers, 'Access-Control-Allow-Origin' is available on everything coming from my server after checking the header in Firefox and Chrome dev tools. When I make a request via $resource, however, 'Allow-Access...' is not present in my header. Here is the code for the resource:
.factory('goodReads', function($resource) {
return $resource('https://www.goodreads.com/book/title.json');
})
.controller('AddBookSelectorController', function($resource, goodReads) {
this.fetch = function() {
var key = '[my_key]';
var data = goodReads.query({author: 'Arthur Conan Doyle', key: key, title: 'Hound of the Baskervilles'});
console.log(data);
};
});
I'm calling fetch via ng-click, and everything executes fine except I get the CORS error. Can anyone point me in the right direction? I am new to angular, and my suspicion is there is a problem with my resource request or something in configuration, but I can't seem to find an answer to fix my problem in the documentation or other stackoverflow questions.
Update 3: It is not a localhost issue. I tried pushing it to my domain and using a simple button which ran an xhr request to the OpenBooks api, and the problem got worse. It is hosted via Openshift, and now the 'Allow-Control-Access-x' headers are gone even for other files on my server. Really beginning to bang my head against the wall here. I am removing the Angular tags, because it has nothing to do with Angular.
UPDATE 2: I got it working after installing 'Allow-Control-Allow-Origin' extension in Chrome. Has my problem been the fact that I'm running this on localhost? Or is there something else going on? The header is still not being set without the extension.
UPDATE: I've been working on this since 8am, and still no luck. I have tried rewriting the request using Angular's $http and also with Javascript's xhr following the example from HTML5 Rocks | Using Cors and I'm still having the same problem with each method. Like I said, the necessary header information is available from files on my server, but it breaks when I make requests to other sites.
I'm starting to think this might not be an Angular problem, but I really have no clue. Just to be safe, here is the code I added to Express to enable CORS, including app.use so you can get an idea for where I called it:
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization, Content-Length");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.header("Access-Control-Allow-Credentials", "true");
next();
});
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
Edit: Here are the headers from the API request:
Request Headers
Host: www.goodreads.com
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://localhost:3000/
Origin: http://localhost:3000
Connection: keep-alive
Response Headers
Cache-Control: max-age=0, private, must-revalidate
Content-Encoding: gzip
Content-Length: 686
Content-Type: application/json; charset=utf-8
Date: Wed, 02 Sep 2015 17:20:35 GMT
Etag: "a2be782f32638d2a435bbeaf4b01274a-gzip"
Server: Server
Set-Cookie: csid=BAhJIhg1MzgtNTk4NjMzNy0wNzQ4MTM5BjoGRVQ%3D--afed14b563e5a6eb7b3fa9005de3010474230702; path=/; expires=Sun, 02 Sep 2035 17:20:33 -0000
locale=en; path=/
_session_id2=fd45336b8ef86010d46c7d73adb5f004; path=/; expires=Wed, 02 Sep 2015 23:20:35 -0000; HttpOnly
Status: 200 OK
Vary: Accept-Encoding,User-Agent
X-Content-Type-Options: nosniff, nosniff
X-Frame-Options: ALLOWALL
X-Request-Id: 1K8EJWG30GWDE4MZ4R5K
X-Runtime: 2.277972
X-XSS-Protection: 1; mode=block
Headers for the .js file from my server:
Request
Host: localhost:3000
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://localhost:3000/
Cookie: _ga=GA1.1.1924088292.1439681064; connect.sid=s%3AB4O0Up9WF5iqkfky__I0XCiBD2aMATlq.gbJUC9GseqnJvRTEIbcwxD6cwFQeL7ljNScURCJ5As0
Connection: keep-alive
If-Modified-Since: Wed, 02 Sep 2015 17:08:40 GMT
If-None-Match: W/"886-14f8f0828c1"
Cache-Control: max-age=0
Response:
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=0
Connection: keep-alive
Date: Wed, 02 Sep 2015 17:20:30 GMT
Etag: W/"886-14f8f0828c1"
Last-Modified: Wed, 02 Sep 2015 17:08:40 GMT
X-Powered-By: Express
access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept
I guess this problem exposed my ignorance, but maybe this will help other newbies to CORs like me. I finally figured out the problem after getting a copy of CORs in Action and working through the first example using the Flickr API.
My problem had nothing to do with the backend, Angular, jQuery's .ajax method, or xhr. All of my requests were properly formatted. The problem was the APIs I attempted to use did not have CORs enabled on their server. O.o As soon as I changed the data type to jsonp, everything went through.
Anyway, for you newbs out there like me, here are some pointers to help you if you run into this problem:
1. Don't assume the API you are using has CORs enabled
I don't know why, but I blindly picked two APIs that don't have CORs enabled, which is what caused all the fuss for me. I have never run into this problem before because the work I have done with APIs have always been from big companies like Flickr that had CORs enabled. If they don't set Access-Control-Allow-Origin on their server, you can request them to enable it and use JSONP in the meantime.
If the API has an option for a callback at the end, that's a good sign you should use JSONP for your request. JSONP works by wrapping your request in a callback and exploiting a feature of the script tag. Scripts can pull other scripts from any domain, so it works as a hack to get the data. Here's a good link that helped me. Exactly What is JSONP? | CameronSpear.com
2. Check The Response Headers
I got tricked by this, but remember that the response header on your request to an external API is the response from their server, not yours. It doesn't matter if CORs is enabled on your server, you are making the request to someone else, and the browser automatically sends your information to them in the request header. Remember, all of this checking is done by the browser for security reasons, so its doing the heavy lifting for you on the request side based on your ajax call. If Access-Control-Whatever doesn't show up in the response header, they don't have CORs enabled. If you are working on the frontend and requesting someone else's data, you can't do anything about it. Use JSONP and your problems will disappear (probably).
This whole fiasco for me started because I was confusing responses coming from my server with responses coming for their server. I correctly enabled CORs on my own server, but I was thinking it wasn't attaching the origin information to the request header which is why it was absent in the response header. In reality, everything was working correctly, but the API server didn't have it enabled.
So a day spent, but many lessons learned. Hopefully my wasted time helps someone else with their CORs problems. Note that my issue was stack agnostic, so regardless of how you are making your request, checking the response header is the first course of action to take if you run into a problem with CORs. After that, I would suggest looking into the request itself for errors.
Check out that book above or this link from the same author for more help, especially when it comes to non-simple requests HTML5 Rocks | Using CORs.

Node Express Mongoose MongoDB CORS failure

I am using Node/Express/Mongoose/MongoDB on a Debian VPS webserver but for some reason the online CORS request is not firing. Let me just say that everything works perfectly on my local server.
When I upload it to my Debian VPS webserver however the cors request never goes through. I know this because the debug logs never fire. The MongoDB server is running AND the node/express server is running. I have npm reinstalled express/mongoose and even the cors addon MANY times and do not think it's an issue with those...
I have tested things on the server with cURL -H w/ the -origin flags. THE RESPONSES RETURN CORRECTLY in the console. This leads me to believe that the CORS requests are being blocked somehow (maybe by the browsers??) and the express servers are never even reached. I have tried starting browsers with no security flags to no avail also... ONE strange fact is that when the responses do return w/ cURL, they sometimes list different origins even though I specify one origin with the flag. Confusing...
I have tried changing access-origins MANY different times and ways. I have tried allowing all of them. I have tried allowing the ones specific to the requests... I have tried using the apache2 header mod and using an .htaccess file to allow cors. I have also tried the PHP header for it to no avail.
url: www.kensnote.com
Browser error responses are as follows:
Chromium-browser: "Failed to load resource"
Firefox: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:10005/threadpreview. (Reason: CORS request failed).
Firefox Firebug Request Headers:
Accept application/json, text/javascript, /; q=0.01
Accept-Encoding gzip, deflate Accept-Language en-US,en;q=0.5
Cache-Control max-age=0 Connection keep-alive DNT 1 Host
localhost:10005 If-None-Match W/"ssUy2L+Up13MCm2LISgPtQ==" Origin
http://www.kensnote.com Referer http://www.kensnote.com/
User-Agent Mozilla/5.0 (X11; Linux i686; rv:39.0) Gecko/20100101
Firefox/39.0
In a browser implementing CORS, each cross-origin GET or POST request
is preceded by an OPTIONS request that checks whether the GET or POST
is OK.
Basically, for CORS, Firefox will send a preflight options check before the real request.
In your server code, you should send an OK response to the OPTIONS request. Check the following example code that can be used in a route (or middleware):
res.header("Access-Control-Allow-Headers", "Authorization, Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods", "PATCH, POST, GET, PUT, DELETE, OPTIONS");
if ('OPTIONS' === req.method) {
return res.send(200);
}

Self-Coded Proxy cannot retrieve image from wikipedia

I'm trying to write a small proxy server in c#. It is working nicely for many webpages I tested (including google.com and microsoft.com). For testing I started my proxy server and configured IE 10 on Windows 8 to use it.
But when I try wikipedia.org it does only load the main page but no pictures. I tried to load a single picture (http://upload.wikimedia.org/wikipedia/commons/6/63/Wikipedia-logo.png). When I use IE without proxy it works, but with the proxy I get a 404 response.
This is the GET Request which IE (my proxy just forwards it) issues:
GET http://upload.wikimedia.org/wikipedia/commons/6/63/Wikipedia-logo.png HTTP/1.1
Accept: text/html, application/xhtml+xml, */*\
Accept-Language: de-CH\
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Accept-Encoding: gzip, deflate
Host: upload.wikimedia.org
DNT: 1
Proxy-Connection: Keep-Alive
IMHO it looks correct. This is the response I get (omited some html tags):
HTTP/1.1 404 Not Found
Content-Type: text/html; charset=UTF-8
X-Varnish: 1427845074 1427806476, 274786836, 3671934588
Via: 1.1 varnish, 1.1 varnish, 1.1 varnish
Content-Length: 262
Accept-Ranges: bytes
Date: Mon, 01 Jul 2013 21:30:54 GMT
Age: 28
Connection: keep-alive
X-Cache: cp1063 hit (1), cp3004 miss (0), cp3003 frontend miss (0)
Access-Control-Allow-Origin: *
...404 Not Found\n The resource could not be found.\nRegexp failed to match URI: "http:/upload.wikimedia.org/wikipedia/commons/6/63/Wikipedia-logo.png"
The strange part is here:
Regexp failed to match URI: "http:/upload.wikimedia.org/wikipedia/commons/6/63/Wikipedia-logo.png"
-> the URL starts with a http:/
In the code I connect to uploads.wikimedia.org like this:
// connect to uploads.wikimedia.org
ServerSocket.Connect(RemoteHost, 80);
byte[] SendBuffer = Request.ToArray();
// send the clients request to the server
ServerSocket.Send(SendBuffer);
I have no idea why it doesn't work. Any help is appreciated. My full code is located on Github: Proxy_C_Sharp
I just found out why.
According to the HTTP/1.1 specification (http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5) in Chapter 5.2.1:
"To allow for transition to absoluteURIs in all requests in future versions of HTTP, all HTTP/1.1 servers MUST accept the absoluteURI form in requests, even though HTTP/1.1 clients will only generate them in requests to proxies."
I tried it out with a small tool. if I make a request like this:
GET /wikipedia/commons/6/63/Wikipedia-logo.png HTTP/1.1
Host: upload.wikimedia.org
It works. So the reason is that Wikipedia is not conform to the standard. It should accept absolute urls. But it works if I visit the site without a proxy because the browser uses absolute URIs only with proxies. If there is no proxy configured it uses a relative one.

Resources