React proxy how to prevent from outside world - node.js

I have a react js application working on port 3000 and a nodejs working on port 4000.
I am using setupProxy as
const createProxyMiddleware = require(`http-proxy-middleware`)
module.exports = function (app) {app.use('/api/*', createProxyMiddleware({ target:http://localhost:4000', changeOrigin: true, }))}
On server, running on port 4000, I am using cors as:
app.use(cors((cors.CorsOptions = { origin: `http://localhost:3000`,})))
The application on localhost:3000 is exposed as https://example.com/
I have an end point on Node server as /api/todos which perfectly accessible from react client.
Outside world can post for example https://example.com/api/todos. How to prevent this?

There was a similar post I answered a few days ago here
How to launch a command on the server from a web page ( nodejs )
With that being said though, and maybe a TLDR you need a way to protect your route. This is where you have two options really.
Use JWT
Use 'sessions' (this would assume you are not connecting / posting from outside the main application so it shares a session between frontend / backend)
From what it sounds like, the application / front-end are not bound together so option 2 may not be an options.
With option one you would create a JWT token from the front end. This token would contain an encoded string that can only be decoded on the server. You send this token with your post or get request and have middleware to decode and verify the token is valid, if not, don't let it post to the route.

Related

Is there a way to add a separate node website under a node website's route?

I have two Node.js websites (website_a, website_b) that use ExpressJS. I wanted to add "website_b" under a route of "website_a".
For example, going to http://www.website_a.com/website_b will show the pages of "website_b".
i.e. Requesting http://www.website_a.com/website_b/ shall not redirect the request to website_b (http://www.website_b.com/) but instead fetch the request from website_b and respond from the website_a server.
The response on requesting http://www.website_a.com/website_b/about shall be the same as requesting http://www.website_b.com/about.
⚠ The websites (website_a, website_b) are completely separate and shall stay separate.
Is there a way to use the route.use() to add route /website_b to website_a and let ExpressJS fetch the response from website_b and then respond the same from website_a's server.
Maybe the thing you want ask it to proxy pass certain routes to another websites. I've do before with one npm module http-proxy-middleware
npm i http-proxy-middleware
Proxy /api requests to http://www.example.org
var express = require('express');
var proxy = require('http-proxy-middleware');
var app = express();
app.use(
'/api',
proxy({ target: 'http://www.example.org', changeOrigin: true })
);
app.listen(3000);
// http://localhost:3000/api/foo/bar -> http://www.example.org/api/foo/bar
So basically it will send request to another website under website one.
check out more about it - https://www.npmjs.com/package/http-proxy-middleware
Hope it helps :)

When to use proxy and when to use CORS in a react project?

I am a beginner at react development, I am confused about when I should use proxy or cors to make the front end talk to the back end.. Or do i need to use both? like proxy for development and cors for production?
CORS is completely related to back end when you want make your back end server accessible for any request use CORS.
example:
const app=require('express');
const cors=require('cors');
app.use(cors())// server will respond to any domain
Most of the time you are going to use a proxy when you want to be able to connect to an api that the webpack dev server isn't hosting but will be hosted by your server when published. An example will probably clear this up better than anything.
When developing you have the following scenario
API Server - running at localhost:4567 Webpack Dev Server - running at localhost:8080
Your App.js will make a request to the API server like so
$.ajax({
url: '/api/getOwnedGames',
...
});
Without a proxy this will actually make a request to localhost:8080/api/getOwnedGames (since you are browsing from the webpack dev server). If you however setup the proxy like so...
proxy: {
'/api/*': {
target: 'http://localhost:4567'
}
}
the api request will get rewritten to be http://localhost:4567/api/getOwnedGames.
if you aren't hosting your own api you probably don't need the proxy.

create-react-app with Express

I need to query a database and I'm using create-react-app. The library to connect to the DB (pg-promise) does not work with Webpack and needs to be running on a Node server.
So I installed Express and have this:
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
})
How can I load data from the database from the React pages? I though of using request but how can I make a request to my own server? And what should I add to the lines of code above? I think it would be something like:
app.get('/query/:querybody', (req, res) => {
// process and return query
})
Is this right? How can I make it work with a SPA?
Probably the most friction-free method would be to have a separate app.js or server.js along side your CRA application. You can use a tool like concurrently to run both your React app and the express app.
The trick is to serve your express app on a different port than the default :8080 that CRA serves on. Usually 8081 is a good choice, as it's a common convention to use port numbers that are close together when developing.
In your React app, you will need to make sure you use the full URL for the express endpoint: http://localhost:8081/query/...
On the server side you are going in the correct direction: you need to setup endpoint which will respond with data based on request. In you example you setup an endpoint for a GET HTTP request. If you will need to pass a complex request (for example add new record to database), consider using POST HTTP requests.
On the client side (in the browser) you will need a library that will assist you in sending requests to your server. I can recommend to try Axios (https://github.com/mzabriskie/axios). Usually if you omit protocol, server name and port, request will be sent to the server from which the page was loaded:
http:127.0.0.1:8001/api/endpoint => /api/endpoint

Authentication with separated client and server

I have created web application in angular 2 for the client side and NodeJS with express framework for the server-side.
For the client side, I generated the project with angular-cli which runs on a lite-server, so my client and server are running on 2 different services.
I want to integrate ADFS authentication.
To implement the authentication, I am using passport-saml package.
There is a middleware in my server-side API which requires a user to authenticate.
The authentication process works fine when reaching the server directly (without the client).
However, I fail to access the API through the #angular/http.
I tried a simple GET request from the server (with the middleware in the end-point) and as a result I am getting the authentication page without redirection (I don't think it's the core problem, but the actual implementation is).
How should I properly implement the authentication when using separate services to the server and the client?
Hi I was also facing the same issue my angular project was hosted on 4200 port. and my node on 3000 port.
Its difficult to implement passport when we have 2 ports running.
step 1
make angular project static by doing an ng build to public folder .
make sure angular-cli.json has *"outDir": "../public",*
step 2
Now we can use the same node port to access angular roots please add below code in your node app.js
var path = require('path');
// Set Static Folder
app.use(express.static(path.join(__dirname, 'public')));
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'public/index.html'));
});
This will enable your angular project accessible through node port.
step 3:
Now we can add the passport login button in the UI
and give the url twitter
THIS IS not explanatory means feel to ask me the doubts.
You are not giving much detail on what the failed response was when the client did the GET to the server. Was it a 400? 401? 404? 500? did you get a CORS error?
Why are you using GET for your login endpoint. You should be POSTing credentials right in the POST payload?
Anyway, in your angular2 code you should have an auth service with a login method. The login method should do something like ..
login(credentials) {
return http.post(your_server_url, payload);
}
you can then subscribe to the Observable returned by the login method and if all is good router.navigate to the home page or if it did not go well display login error messages.
Set separate urls for ui and server in ..src/environments/environment.ts
export const environment = {
production: false,
BASE_URL: 'http://localhost:4200',
API_BASE_URL: 'http://localhost:5000',
};
In node app.js
app.use('/', express.static('public'));
app.get('*', function (req, res) {
res.sendFile(path.join(process.cwd(), 'public', 'index.html'));
});
In your development environment, you should accomplish this by instructing your Angular CLI to proxy all requests to a backend server running on a separate port whenever you run "ng serve". Angular has good documentation on how to do this at https://angular.io/guide/build#proxying-to-a-backend-server. This will make your development process much faster, because you will not need to manually build your Angular application to test every code change.
When a production build is run, Angular will move the distributed files to the location specified in the "outputPath" property of Angular.json (by default set to "dist/<projectName>"). Your main production server will serve them appropriately from there as mentioned by #Lijo in their answer.

express.js + socket.io - how to initialize session on server from client app

I have to create 2 apps. One app is a server using express.js and socket.io. Second app is a simple client (static html+js file) and must not be served from server express.js instance. The cookie express.sid witch is used to establish session is created only when express.js route is accessed.
My problem occurs when I'm connecting from client (ie. http://client.addr) to server (ie. http://server.addr:0000) using socket.io - I can't establish express.js session because I didn't accessed the server route and I don't have express.sid session cookie.
I ended up with client trying to send AJAX call to server /set-session-cookie route in hope I can identify session, send back cookie with encrypted sessionID and than start socket.io connection hooking in to session that was created in previous call but no cookie is sent back after AJAX call.
Server route:
app.all('/set-sesion-cookie', function(req, res){
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Credentials', 'true');
res.cookie('express.sid2', req.sessionID, {signed: true});
res.send(200);
});
Client call:
$.post('http://127.0.0.1:3000/set-sesion-cookie');
Second thought was to send back only string containing encrypted session id and create cookie using JS but I can't find out what the encryption algorithm is for res.cookie('express.sid2', req.sessionID, {signed: true}); to do it manually.
Is this approach valid? If there is another way to achieve this please let me know. TIA.
IMHO session cookies should be HTTP-Only for security reasons.
This means there is no scripting support for this cookie.
You can avoid the Same-Origin-Policy problem by serving static files w/ nginx and reverse proxy node.js app behind nginx. This way all comes from one server and you don't have problems sharing a cookie/session-id.
AFAIK Apache httpd is not able to proxy WebSocket calls.
Another possible workaround instead of nginx might be HAProxy.

Resources