force ssl with nodejs and reactjs - node.js

I do not really have a big experience in production mode of nodejs & reactjs, and today i heard that i should do force ssl. i did some googling and as it seems
function requireHTTPS(req, res, next) {
if (!req.secure && req.get('x-forwarded-proto') !== 'https' && process.env.NODE_ENV !== "development") {
return res.redirect('https://' + req.get('host') + req.url);
}
next();
}
app.use(requireHTTPS);
this kind of code is used for expressjs to force ssl. (code from lavamantis)
then i did some researches about forcing ssl with reactjs, because using res.redirect with react is not thing that i heard before. and as it seems i should do following in package.json
"scripts": {
"start": "set HTTPS=true&&react-scripts start",
...
}
so what should i do when i am using reactjs with nodejs? i have not deployed single application of their combination but when i will i think i will use nginx

i am not willing to use ssl in development mode but i am talking about production
A simplified scenario looks like that:
You do your development in the development environment, for example on your laptop. You do not use SSL. You have some security-sensitive cookie but Express doesn't make it secure-only, otherwise the client (e.g. browser) with your React app won't be able to send it back to Express in order to prove the user has been already logged in.
You finished development and testing so you are now switching from development build of both React app and backend/Express code to the production build. You do not use SSL. You finished testing the production build.
You added Nginx and tested the React app can access Express using Nginx as reverse proxy. You do not use SSL.
You generate a self-signed SSL certificate and use it to switch Nginx to: (a) use SSL and (b) to terminate SSL traffic. The HTTP endpoint is not exposed anymore, Nginx doesn't accept HTTP connections anymore. Only HTTPS. You make the client/browser trust this self-generated certificate. You change the production build to generate secure-only cookie. You test the React app and it works with Express via Nginx.
You move from the dev environemt to the production environment e.g deploy your production build in the cloud or wherever. You replace the self-generated SSL certificate with a proper one issued by CA. Issued either for a fee or for free. You add a firewall supplied by the deployment environment provider. The firewall can optionally terminate SSL traffic instedd of Nginx.

Related

node Vue.js different code scenario if run in dev mode

I have Vue.JS front app with nodeJS backend based on expressJS. ExpressJS also used as web server for statically built Vue.JS app
Front app communicates with express backend via rest and websocket. It uses url host from window.location instance and easily communicates with backend
In production mode, when built application in static expressJS server area, everything work perfect
In dev mode, Vue use it's own web server, and backend urls based on window.location are incorrect because no expresJS on same host and port.
So my question is it possible change some code blocks if running in dev mode ?
Like something this :
if( devmode)
{
const url = "http://somebackendhost/rest"
}
else {
const url = location.host ....
}
}
I will assume you are developing your Vue app using Vue CLI
Changing app behavior depending on environment
In Vue CLI you can use Environment Variables
if(process.env.NODE_ENV === "development")
{
}
This works thanks to Webpack's Define plugin and big advantage is that process.env.NODE_ENV is replaced at build time by the real value. So in production build Webpack will see just if("production" === "development") {} and happily removes the code in optimization phase because it knows this can never be true
Better solution
But I would not use this approach for your problem. Using different API server (not same as the server used for serving Vue SPA) can easily lead to CORS problems
Exactly for this use case, Vue CLI (and Webpack Dev server used under the hood) supports proxying
vue.config.js
module.exports = {
devServer: {
proxy: {
'^/api': {
target: 'http://localhost:58300/',
ws: true, // websockets
changeOrigin: true,
}
}
},
},
This config makes Vue Dev server to proxy any request to /api to other server running at http://localhost:58300/ (your node/express app) and change the origin (so browser thinks response came from the dev server)
All of this can be done without Vue CLI but you will need to set it up by yourself in Webpack config...
The problem
You can't access this information from your browser.
But there are three solutions:
Solution #1
On compilation time create a variable in code which defines devmode (const devmode = true;)
Solution #2
Because your bundler can minify your variable names or changing the scope for security reasons, may be the situation where you can't access it.
So second solution is to define devmode in your localStorage.
Solution #3
Third solution is almost the best.
If you are developing, you are probably accessing your web app via localhost.
location.hostname will return the name of host, so you can make something like:
const devmode = location.hotname == 'localhost';
Best solution
Do not do this. Develop a fully working web app using local REST API and define the URL of REST API in some variable, so when you are preparing your production app, you or compiler just changes the URL adress variable in code of your REST API.
Why is this the best solution?
Because it do not impacts your end-user's performance and they will be loading less code, which is the best practise.
Post Scriptum
Don't forget to remove all devmode codepaths when compiling production version!

Shopify app with reactjs and nodejs without nextjs?

I am developing a shopify app so the reactjs handles the UI part and node-express handles the shopify auth things.
The tutorials in shopify site are
node, react and nextjs
node and express without reactjs
My concern is how to test the app without reactjs server side rendering with nextjs?
As we know node and react runs one seperate ports, so how can we handle the authentication flow with shopify?
How I am trying to work is
User enters app -> Node authenticates with shopify -> if auth success -> show react app.
Update : I am using ant design so ssr of ant design will be helpful.
Anyone please help me out with a solution.
After some research I got a simple solution and I am adding the links that give me solution.
React App is running in port 3000
Node server running in port 3001
Setup proxy in client package.json to localhost:3001
{
proxy: "localhost:3001"
}
Install http-proxy-middleware
$ npm install http-proxy-middleware --save
$ # or
$ yarn add http-proxy-middleware
Next, create src/setupProxy.js and place the following contents in it:
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
app.use(proxy('/api', { target: 'http://localhost:3001/' }));
};`
6. That's all.
If using ngrok to make your localhost public, you may get Invalid Host Header error. Here is the solution.
ngrok http 8080 -host-header="localhost:8080"
ngrok http --host-header=rewrite 8080
https://stackoverflow.com/a/45494621/1445874
This 2 link gave me the solution.
When specified, "proxy" in package.json must be a string
https://create-react-app.dev/docs/proxying-api-requests-in-development#configuring-the-proxy-manually
It wouldn't be too difficult, you'd just have to set up Server Side Rendering with Express/Node in order to get react working. Next.js does this automatically saving you the time, but if you would like to do it yourself you can always.
You can follow this guide for reference - https://medium.com/bucharestjs/upgrading-a-create-react-app-project-to-a-ssr-code-splitting-setup-9da57df2040a
I'll do up my own example in a bit since I'm looking to do the exact same thing.

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.

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.

Running Keystone.js app over https on Heroku

I have a web app built on Keystone.js CMS for node.js that I will be deploying with a custom domain on Heroku. I want the whole app to run on https by default and not allow any http connections. I've look around quite a bit and can't seem to find a definitive answer as to the best way to go about this. Typically, i.e. for a Rails app, I would just buy a Heroku add-on SSL certificate for my custom domain(s) and point my DNS to point to the Heroku provisioned SSL endpoint. In my app, I would configure to default all connections to HTTPS.
For a node instance (and specifically a Keystone.js instance), I'm a little unclear. Can I just go about the same process as above, buy an SSL add-on and point my DNS to the Heroku SSL endpoint? Do I need to do anything in the base node code to support? And how to enforce https and not allow http?
New to node and keystone and so any help would be greatly appreciated!
Use express-sslify.
I put it in my routes/index.js since the function I export from there receives a reference to the express application.
All you need to do is to tell express to use sslify, but you probably want to not enable it for development.
Since july, Heroku defaults NODE_ENV to production so you can do
// Setup Route Bindings
exports = module.exports = function(app) {
if (process.env.NODE_ENV === 'production') {
var enforce = require('express-sslify');
app.use(enforce.HTTPS({ trustProtoHeader: true }));
}
// Declare your views
};
That will send a 301 to anyone trying to access your app over plain HTTP.

Resources