How can I provide a client application (port 443) the ability to consume a REST API (port 9000) on the same server when the port is not public facing? - angularjs

I am running an angular (1.5+) application on node with express and ui-router, and I would like to connect this application to a REST API that is running on the same server but on a port that is not public facing (9000).
How can I configure my angular application and express server to consume the REST API on port 9000 using server side logic?
An example route and parameter that I would like to hit my REST API on port 9000 would be https://example.com/item/123

Normally i use Express Http Proxy to solve this problem. It is very configurable.
Example code would be:
var proxy = require('express-http-proxy');
// app is your express based Web application in port 443
var app = require('express')();
app.use('/item', proxy('localhost:9000', {
forwardPath: function(req, res) {
return require('url').parse(req.url).path;
}
}));
Using this middleware you can provide custom handling of the request before and after the request to the private API has been performed. Read the documentation for more examples.

Related

how nodejs build webserever in frontend for fraework for react and angular

I am new to web development and slowly understanding the web process . I want to know which how nodejs helps to build webserver in frontend ? for react applications npm start --> react-scripts start which runs application in localhost .here where exactly it create webserver and executes in localhost
An application can have front end and back end. A ReactJs application can be the front end for example, and nodeJs can be the back end. The back end will offer the server and will communicate with the database.
So, concretely, you will have 2 different projects: client and server. The client project will be your ReactJS application. The server project will be the NodeJS server. You create each one separetly.
A server can be accessed by paths, for example
http://my-server.localhost/login
http://my-server.localhost/logout
http://my-server.localhost/users
So, a basic connection between client and server can be based on the url paths, so in your client project you can do:
window.location.href = "http://my-server.localhost/login";
to call the login service from the server. And then, in your server, you can redirect to a client's url path.
BUT: the best way (for me) to establish connection between client and server is by using socket.
Socket is very simple, your client can emit requests to the server, and vice-versa:
socket.emit('hello', data);//where data can be any type of object, a string for example..
Similarly, the server can also emit requests to the client:
socket.emit('welcom', new_data);
Then, in the server and the client, you should hear for each request. Finally the code can be something like this:
Client side:
socket.emit('hello', data);// I will say 'hello' message (request) to the server..
socket.on('welcome', (data, callback) => {//I will hear to 'welcome' message(request) from the server..
console.log('server emited welcome with data =>', data);
});
Server side:
socket.on('hello', (data, callback) => {//I will hear to 'hello' message(request) from the client..
console.log('client emited hello with data =>', data);
socket.emit('welcome', ':)');//I will say(reply) 'welcome' to the client..
});
Hope this helps you to understand the concept.

AngularJS - Request to localhost server fail

I have made an api end point using express.
Now im trying to get the data from my localhost server that is running on port 3010.
$scope.getBooks = function(){
$http.get('/api/books').then(function(resp){
$scope.books = resp;
});
}
The function is working good because i can test whit the JSONPlaceholder.com.
I cannot get my data, im using gulp on port 3002 and my server is in port 3010, he is running and working good, i can see my data using postman.
why can i get my data from the localhost server ?
Thank You
This issue happens because the API endpoint you are accessing does not implement CORS. If you run your code in Chrome and look at the console, you will see an error:
XMLHttpRequest cannot load .....
The solution is to change the API endpoint to set the Access-Control-Allow-Origin header to either the wildcard * or to the domain where the page using the JavaScript code will be served from.
For More Details on CORS
To prevent websites from tampering with each other, web browsers implement a security measure known as the same-origin policy. The same-origin policy lets resources (such as JavaScript) interact with resources from the same domain, but not with resources from a different domain. This provides security for the user by preventing abuse, such as running a script that reads the password field on a secure website.
If your site is on port 3002 and your server is on port 3010 then you must specify the URL of the entire server's location
$scope.getBooks = function(){
$http.get('http://localhost:3010/api/books').then(function(resp){
$scope.books = resp;
});
}
Specify the entire url in AngularJS code and use CORS middleware in the express backend.
https://github.com/expressjs/cors
This is bad way of doing front end(AngularJs) and backend development parallely on local on same machine. Try to fit Front-end repository to be hosted by BE server and use it in following way :
If you are doing FE development locally and backend server is also hosted locally.
use following line as common baseUrl
var baseUrl = "//" + window.location.host +'/'
Doing so, you don't need to update while committing changes to prod environment.
$scope.getBooks = function(){
var _url = baseUrl + '/api/books'
$http.get(_url).then(function(resp){
$scope.books = resp;
});
}
Above code works in case of same server FE and BE.
If you have different servers locally , you need to work more with setting :
You can use express-http-proxy
var proxy = require('express-http-proxy');
app.use('/api/', proxy('http://localhost:3010'));
In higher of version of angular 4+ , we have such setting as in initial configuration.
READ ARTICLE :
https://juristr.com/blog/2016/11/configure-proxy-api-angular-cli/
You cannot just write /api/books. You need to specify your port number of API running on localhost.
In your case localhost:3010/api/books

NodeJS and AngularJS - Secure REST API with Client Certificate Authentication

I am currently working on making my REST Api Server (NodeJS + Express + Mongoose) secure, so nobody, except my client application (AngularJS 1.6) and my admin application (based on AngularJS 1.6), can access the routes and fetch or put data into my database. Everything is running on https with a valid SSL certificate.
I mainly thought about two approaches:
Shared secret keys where specific routes needs an "access key"
Client certificate authentication
I went with no. 2, because in my thoughts this is the most secure (please correct if I am wrong :))
So I set up my API Server to run on https and request a valid client certificate:
var options = {
ca: fs.readFileSync(__dirname + "/cert/server.ca"),
key: fs.readFileSync(__dirname + "/cert/server.key"),
cert: fs.readFileSync(__dirname + "/cert/server.crt"),
requestCert: true,
rejectUnauthorized: false
};
https.createServer(options, app)
.listen(PORT, () => {
console.log(`up and running #: ${os.hostname()} on port: ${PORT}`);
console.log(`enviroment: ${process.env.NODE_ENV}`);
});
I handle the rejection of unathorized users directly in the app via:
if (!req.client.authorized) {
var cert = req.socket.getPeerCertificate();
console.log("unauthorized: ", cert);
return res.status(401).send('Not authorized!');
}
And here the problems begin :). On every request my client application does I receive an error:
401 - not authorized
I thought that the client application is sending the SSL certificate with every request (or if requested by nodejs) via "requestCert" and everything is working just fine. But it seems to be a bit more complicated.
In my server.ca file I currently have the certificate chain which I received from the CA.
In console.log the transmitted certificate in the request, but its always empty.
What am I doing wrong? Do I have to configure Angular to send it along with every request? Any suggestions?

How can I add a spring security JSESSIONID with SockJS and STOMP when doing a cross-domain request?

I am having the following problem. I will describe 3 use cases - two which work and the other one which doesn't.
I have an AngularJS client using SockJS with STOMP. In the backend I have a Spring application. Client is in domain domainA.com, backend is in domainB.com.
var socket = new SockJS(("http://domainB.com/myApp/messages"));
stompClient = Stomp.over(socket);
stompClient.connect('guest', 'guest', function(frame) {
...
}
In the backend there are Cors filters and the Cross-origin calls are possible. All works fine.
Use Case 1. Client domainA, Server domainB
My application is unsecured on the backend side. I subscribe like below:
stompClient.subscribe('/topic/listen', function(message) {
showMessage(JSON.parse(message.body).content);
});
All works fine.
Use Case 2. Client domainB, Server domainB
My application is secured on the backend side with Spring security. Authentication is done through a form - username and password. Nothing uncommon.
In this case the client is on domainB.com, same as the backend. All works fine, the difference is that I use a different subscription method:
stompClient.subscribe('/user/queue/listen', function(message) {
showMessage(JSON.parse(message.body).content);
});
in order to benefit from getting the principal from the security session. All works well. No issues.
The JSESSIONID cookie is added to the connection request in new SockJS(("http://domainB.com/myApp/messages"));.
Use Case 3. Client domainA, Server domainB
The application is secured the same as in UC2. However, the client is now on a different domain.
The JSESSIONID is NOT added to the connection request. The connection to websocket in Spring is unauthenticated and redirected back to login page. This repeats and makes it impossible to connect.
Why is the JSESSIONID cookie not populated with the websocket requests in this case?
Cheers
Adam
As part of SockJS protocol, a http GET is sent to websocket server for negotiating the supported protocols. It's done using XmlHttpRequest which won't add any cookies stored for a different domain than its own domain the web application and scripts are served due to same-origin policy implemented in every modern web browser.
You should resort to a way of circumventing the same-origin policy.
I think you'll find the answers you are looking for here : http://spring.io/blog/2014/09/16/preview-spring-security-websocket-support-sessions
the trick to implement a HandshakeInterceptor

How do I implement secure OAuth2 consumption in AngularJs?

I'm setting up oauth2 with Salesforce connect using AngularJS. When I attempt the initial GET using $http I get CORS errors - Access-Control-Allow-Origin not allowed for my client. However, using the hack below in my controller function works.
Is there a better way to do this in AngularJs given that I don't have control over the server? My backend is Firebase so it would be great if I could do this through FIrebase like I can for Facebook :
$scope.auth = function () {
var authUrl = $scope.AUTHORIZATION_ENDPOINT +
"?response_type=token" +
"&client_id=" + $scope.CLIENT_ID +
"&redirect_uri=" + "https://www.xyz/";
window.location = authUrl ;
The cors issue happens when make asynchronous call to different server via browser.
So it doesn't appear if the call is made from another server. so you have to use a proxy server which in turn makes a call to your actual server.
You can try the below proxy server which is straightforward.
https://www.npmjs.com/package/cors-anywhere
or you can write your own proxy server which runs on the same domain as your client app and proxies your request to the secured server.

Resources