Angular/Node/Express/Passport - Issues when connecting to facebook(CORS) - facebook

i'm trying to use facebook authentication on my NodeJs server. i came to the tutorial of http://scotch.io/ and have it working locally when using a REST client(Postman, etc).
To improve the UI i used Angular JS as a front end. but when i call a http.get to my specific route given on the NodeJs back-end i get the following error in chome and firefox:
XMLHttpRequest cannot load https://www.facebook.com/dialog/oauth?response_type=code&redirect_uri=http%…0%2Fapi%2Fauth%2Ffacebook%2Fcallback&scope=email&client_id=3000000000006. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'localhost:8080' is therefore not allowed access.
i've tried several solutions on StackOverflow but its still not working...
my NodeJs uses Express 4.* and a CORS middleware.
for Angular i found several ways to enable CORS, none working so far.
I hope you can help me:D Thanks in advance!

You can use 'window.location="http://localhost:3000/auth/facebook"'; in your Angular Controller from where you send the request to your Express Server which contains passport.authenticate stuff.
This will stop your angular to call facebook auth dialogue page as AJAX request.
It works for me!

I'm using Angular with Node/Express as well, and the following function works for me with my own backend services (I'm currently not using it with Facebook to be honest), so just check it out:
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, Authorization, Content-Length, X-Requested-With, Access-Control-Allow-Origin');
res.header("Access-Control-Max-Age", "86400"); // 24 hours
// intercept OPTIONS method
if ('OPTIONS' == req.method) {
res.send(200);
}
else {
next();
}
};
Then, you need to use it tin the app.confiure()method as follows:
// configure Express
app.configure(function() {
app.use(allowCrossDomain);
...
});
It's important to use it BEFORE all other directrives!

Related

Cross-Origin Request Blocked in any browser eventhough supported

I have already read a lot of other stackoverflow questions and github issues but none were able to resolve my issue so i decided to open a new one.
I am building a short application with Nextjs (frontend) and Express+Node (backend). Everytime the Frontend makes a get/post request to the backend via REST I get
"Cross-Origin Request Blocked: The Same Origin Policy disallows
reading the remote resource at DOMAIN. (Reason: CORS header
'Access-Control-Allow-Origin' missing)."
To fix this, i tried multiple things. First of all i added app.use(cors()) in my backend, but that didnt work. I added
const configcors = {
origin: true,
methods: 'GET,HEAD,POST,PUT,DELETE,CONNECT,OPTIONS,TRACE,PATCH',
allowedHeaders: 'X-Powered-By,Content-Type,Content-Length,ETag,Date,Connection,Keep-Alive',
exposedHeaders: 'X-Powered-By,Content-Type,Content-Length,ETag,Date,Connection,Keep-Alive',
credentials: true
}
app.use(cors(configcors))
to allow absolutely everything but that didnt work either. i tried to add the headers manually using
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');
next();
});
which - as you might expect - didnt work either.
Lastly i thought if maybe there was an error with the preflight, so i tried
app.options('*', cors(configcors))
which didnt work either. Furthermore, trying to solve the problem, i looked at the network tab, to identify the headers and whether the correct headers were send. In Firefox there appeared no Request in the Networking Tab at all.
Chrome:
On chrome tho, i can see the request but there are no response headers at all. This let me assume that maybe CORS wasnt the problem - To try this i installed the moesif CORS extension in chrome to allow all sorts of CORS. I was wrong: with the extension enabled, every request works perfectly fine - but i cant rely on an extension in production.
This means that the error definitely has something to do with CORS but I have no idea what I should do now.
if anyone had similiar troubles i would be very thankful for your advice.
Try this:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:3000");
res.header("Access-Control-Allow-Headers", "*");
next();
});

Accessing ArcGIS data over HTTP

I am attempting am building a map data React app using GIS data. I am accessing public GIS endpoints.
The endpoint is http://gis.infrastructure.gov.au/infrastructure/rest/services/KeyFreightRoute/KFR/MapServer/0
On local development, it is working fine. However, once pushed to live it returns the error: net::ERR_CONNECTION_REFUSED. Due to it being an HTTP endpoint.
The ArcGIS docs describe a solution using config, and I have included the following code:
esriConfig.request.interceptors.push({
// set the `urls` property to the URL of the FeatureLayer so that this
// interceptor only applies to requests made to the FeatureLayer URL
urls: featureLayerUrl,
// use the BeforeInterceptorCallback to check if the query of the
// FeatureLayer has a maxAllowableOffset property set.
// if so, then set the maxAllowableOffset to 0
before: function (params) {
if (params.requestOptions.query.maxAllowableOffset) {
params.requestOptions.query.maxAllowableOffset = 0;
}
},
// use the AfterInterceptorCallback to check if `ssl` is set to 'true'
// on the response to the request, if it's set to 'false', change
// the value to 'true' before returning the response
after: function (response) {
if (!response.ssl) {
console.log('not ssl');
response.ssl = true;
}
},
});
However, it still isn't working!? In fact, the console.log('not ssl') isn't even logging on the live site (but it is logging on localhost).
How do you access HTTP GIS endpoints?
This is more of a browser limitation than a GIS-specific problem. If your current URL bar has "HTTPS", the page is not allowed to access HTTP resources - the browser enforces this as a security measure. You have two options:
Convince the owner of that site ("gis.infrastructure.gov.au") to enable HTTPS. This is standard practice these days and fairly trivial to do. They should do this.
You can run a proxy like the Esri Resource Proxy on your own server. That way your application will access the url via HTTPS (because your server is secured with HTTPS), but then the server makes the HTTP request on the server site, thus getting around the browser security limitation

axios causing an unintended OPTIONS request on HERE Autocomplete api

I am getting a preflight error 405: Method not allowed from the HERE API when I request autocomplete as per the documentation.
UPDATE 2:
I have since determined that Axios was adding my default.common authentication headers from my app's API client onto the HERE API client. Axios is supposed to keep those defaults separate per-client, but it seems that it doesn't ... at least not the version I have. I replaced the defaults with a per-client request interceptor and it worked fine. The request no longer triggers an OPTION pre-flight. No issue with HERE's API other than that it doesn't support OPTION method.
UPDATE:
The reason it fails is because HERE does not support the OPTIONS method, only the GET. So now the question is: Why does axios trigger an OPTIONS request when I don't set any headers? An XMLHttpRequest() based GET request does not trigger OPTIONS for the same URL. Something is happening with axios but I don't know what and I can't seem to investigate the headers that axios is sending.
ORIGINAL:
I've tried to find information about this error, as well as HTTP vs HTTPS. I haven't seen others having this problem so I feel like I must be making a simple error. The URL is generated correctly because it works when pasted directly into the browser for example.
const hereClient = axios.create({
baseURL: 'https://autocomplete.geocoder.api.here.com/6.2/'
})
async function searchHere (query) {
let searchTerms = query.split(' ').join('+')
let result = await hereClient.get('suggest.json', {
params: {
app_id: '<APPID>',
app_code: '<APPCODE>',
query: searchTerms
}
})
return processHereSearchResults(result.data)
}
The GET request fails on the OPTION preflight with a 405: Method not allowed. But if I paste the generated URL into a browser then it returns the expected results. For example:
https://autocomplete.geocoder.api.here.com/6.2/suggest.json?app_id=APPID&app_code=APPCODE&query=8131
returns:
{"suggestions":[{"label":"Česko, Brandýs nad Orlicí, 3123","language":"cs","countryCode":"CZE","locationId":"N . . .
Same result whether http or https.
I have since determined that Axios was adding my default.common authentication headers from my app's API client onto the HERE API client. Axios is supposed to keep those defaults separate per-client, but it seems that it doesn't ... at least not the version I have. I replaced the default header setting with a per-client request interceptor to set my authentication and it worked fine. The request no longer triggers an OPTION pre-flight. No issue with HERE's API other than that it doesn't support OPTION method.

Odd CORS error querying JIRA REST API [duplicate]

This question already has answers here:
Origin is not allowed by Access-Control-Allow-Origin
(18 answers)
Closed 6 years ago.
I am trying to develop a D3 visualisation project for our JIRA boards, but I've fallen at the first hurdle. I'm having trouble authenticating and getting a list of JIRA boards.
This code is entirely client-side and is in Angular 2 RC 3. My service looks like this:
public authenticate( username:string, password:string ):void {
let encodedAuth:string = window.btoa( `${username}:${password}` );
this.headers = new Headers();
this.headers.append( 'Content-Type', 'application/json' );
this.headers.append( 'Authorization', `Basic ${encodedAuth}` );
}
public getAllBoards():Observable<Boards> {
return this.http.get( `http://${this.host}/rest/agile/1.0/board`, this.headers )
.map( response => response.json() as Boards )
}
and the code in my component looks like this:
constructor( protected jiraService:JIRAService ) {
this.jiraService.authenticate('me#you.com', 'password');
this.jiraService.getAllBoards().subscribe(
boards => this.boards = boards
);
}
Unfortunately, this generates what looks like a CORS error in my browser:
XMLHttpRequest cannot load https://myjira.atlassian.net/rest/agile/1.0/board. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 401.
...which is a little unexpected. This same URL in the browser works fine. Examining the request in Charles I see the error "SSL Proxying not enabled for this host: enable in Proxy Settings, SSL locations", but cannot actually find this setting. I don't care if I can't see it in Charles actually, I just want to get it working!
I have tried several of the npm JIRA packages but none of them are remarkable and seem to be designed for server-side development.
Any help greatly appreciated.
You get this error when you access it from within an application that was initially loaded from a different URL. If you load a new page from this "other" URL then this is not a CORS situation because the initial page load is already from this URL.
The server need to provide the expected CORS headers for the browser to allow this request. This is not an Angular issue but only a server issue.
Workarounds are
JSONP (doesn't support custom headers)
provide support server-side where your Angular application calls to your server which then forwards to the other server and then forwards the response it gets to your Angular application.

How to send POST and GET requests from Sails app to outside Sails API

I am beginning to use SailsJS and i found it wonderful and powerful.
Can anybody please explain me how to send POST and GET requests to an API outside Sails and where do i actually write this request?
Thanks a lot and Happy 2016 everyone!!!
Edit:
Hello #arcseldon, thank you for been trying to help me.
I'll try to explain myself better, and show you my code.
I have an API, written in php (which i think is not relevant) which accepts POST, GET, PUT, DELETE methods. I use Postman for testings and everything looks OK.
I am trying to make an app in Sails, which GETs and POSTs requests to my API, but i dont know where is the best place to put the GET's and POST's codes.
In the model i already have the following to ask for a token to perform the other requests, and it works:
gettoken: function (requestnewtoken,tokenresult) {
if(!requestnewtoken) {
tokenresult(global.tokeng);
} else {
request({
headers: {
'User-agent' : 'develop',
'Content-Type' : 'application/x-www-form-urlencoded;charset=UTF-8',
'Content-Length' : '29',
'Authorization' : 'Basic ' + global.idsecret
},
uri: "https://myapi/oauth2/token",
method: "POST",
form: {
grant_type: "client_credentials"
}
}, function(error, response, body) {
var tokenjson = JSON.parse(body);
var token = tokenjson['access_token'];
global.tokeng = token;
tokenresult(token);
});
}
}
Then, i perform a GET request to another endpoint, which works:
listpublicroutes: function(requestnewtoken,cb) {
Model.gettoken(requestnewtoken,function(token) {
request({
headers: {
'Authorization' : 'Bearer ' + token
},
uri: "https://myapi/folder/file.json",
method: "GET",
timeout: 10000,
followRedirect: true,
maxRedirects: 10
}, function(error,response, body) {
if(error || (response.statusCode != 200)) {
Model.listpublicroutes(true,cb);
} else {
cb(null,JSON.parse(body));
}
});
});
}
My doubts are if this is the best way to write a POST and GET request or they could be more simple, and if the requests should be done in the controller (or anywhere else) instead of the model.
Can you give me an example of a POST and GET request?
Thanks a lot to everyone who's trying to understand me.
Your question isn't clear exactly what you are asking... Here are a few suggestions depending on what you wish to do.
If you are trying to call out and make an http request from within
server-side Sails code then I would recommend you take a look at the
NPM module request.
If you are talking about making get / post requests to test your API,
then use a web browser plugin / tool such as postman (also a
Chrome plugin of same name).
If you are talking about calling a completely different domain URL
using AJAX from within your web application client (via web browser)
then you can just use any AJAX approach (jquery / angular / whatever
client library you are using to make ajax calls) but be aware that the
domain you are calling to would have to have been setup with a cross
origin resource sharing (CORS).
You have control over your own CORS settings (allowing apps originating from other domains to call into your sails API from the browser, by updating config/cors.js settings.
Does this answer your question? If you need further help leave me a message below, and I'll try to assist.
Update Based On Question Update:
#Michi - ok, you wish to call your PHP api from within SailsJS - the three contenders in terms of location to do this are inside a Controller, a custom Model method, or within a custom service.
My "recommendation" is that most of the time, this logic sits within a Controller if it is logic that doesn't really need to be shared elsewhere. You could conceivably call into a Model.method(), but "usually" you want to think of the models as your domain data (certainly not always, if the responsibility for what you are doing truly belongs to a single Model etc which owns all the state interaction then the model might be the right place to locate that responsibility).
However, in your case, you are getting a token, and without seeing your model code (you have just provided the getToken function which doesn't really look like it is tied to a particular model..?) then I would say opt to invoke it within your controller if not needed elsewhere. Otherwise, refactor it out into a service. To quote the SailsJS documentation:
Services can be thought of as libraries which contain functions that
you might want to use in many places of your application. For example,
you might have an EmailService which wraps some default email message
boilerplate code that you would want to use in many parts of your
application. The main benefit of using services in Sails is that they
are globalized--you don't have to use require() to access them.
I have frequently put custom logic in Controllers, Models and Services, but for networking related logic etc, my preference is:
Controller if one-off logic.
Service if reusability required, or encapsulating the code as service improves readability / maintenance of the app
Use a model, only if you strongly believe the logic and responsibility is truly tied to that model - err on the side of caution here and use sparingly. But I acknowledge my recommendations may be construed as subjective - am basing them on what I believe to be good OOP practices in general terms.