Nginx reverse proxy with JWT cookies - reactjs

I've been working on a Full stack project with React, Mysql, Express and Nginx. The project is working fine locally. I'm trying to deploy this project on a GCP instance.
I'm struggling with how to handle authorization and cookies like accessToken and refreshToken with reverse proxy.
Made some changes in the Nginx configs and server at port 80.
Here is the overview :
I'm using reverse proxy method to interact with the server running at the instance with the help of PM2 module.
Nginx config :
server {
listen 80;
server_name GCP IP;
location / {
# proxy_bind 127.0.0.1;
client_max_body_size 100m;
proxy_buffers 8 16k;
proxy_buffer_size 16k;
add_header 'Access-Control-Allow-Origin' http://localhost:3000; #frontend port
add_header 'Access-Control-Allow-Credentials' 'true';
proxy_pass http://localhost:8800;
# replace port with your backend port
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $http_host;
proxy_set_header Cookie $http_cookie;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $remote_addr;
port_in_redirect off;
}
}
So, I'm able to access the frontend with http:// GCP IP , registering a user is working with "http:// gcp_ip /api/users/addUsers" . But when it comes to check the cookies it doesn't work http:// gcp_ip /api/users/token.
Login provides accessToken and refreshToken , a route which authenticate user's token at http:// gcp_ip /api/users/token just after someone logged in . This route interacts with the cookies.
const refreshToken = req.cookies.refreshToken;
Nginx is not able to access the cookie through the frontend for authentication.

Related

How can I connect localhost of the host machine?

I was trying to host react as a frontend and rails as backend.
I host rails at http://localhost:3000.
You can see that it is working.
But when I call http://localhost:3000 from react, instead of going to server's localhost, it go to user's localhost.
How can I fix this? I am using Nginx as web server.
I just solved by doing reverse proxy in Nginx.
location / {
try_files $uri /index.html;
}
location /api {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
first location / will find static frontend files and /api will go to localhost:3000.
For example, in my case
this.url='https://yourdomain.com/api/' to access the backend.
Also don't forget all of your backend route to start with 'api/'.

Nginx redirects to logout page

We are using Nginx Web Server to run our localhost on secured 'https'.
Our server context in configuration file is like :
server {
listen 443 ssl;
server_name <our-server-name>;
ssl_certificate <certificate>
ssl_certificate_key <key>
location / {
proxy_pass http://<our-server-name>:<port number>
proxy_pass_request_headers on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Our code flow is when user logs in and credentials get valid, user is routed to url : https://our-sever-name/authorise?token='token_value'&state='state_value'&home&cid='cid_value' which takes user to home page.
This works in production successfully, once credentials gets valid user is taken to home page, but locally using Nginx web server, once user's credentials gets valid and code redirects to the above url, we get 401 in network tab and it redirects to logout page.
I'm not sure but my guess is may be Nginx is not passing the token authentication to the proxy_pass url.
Our token is generated dynamically, its not hard coded.
Our application is written in React.
Please help. Thanks

How do I set up proxy for production react application?

I am developing a React application which consumes a REST API running on another server. Now, in development, I am using the proxy by adding the proxy field in package.json.
I am wondering how I can configure a proxy for the production application so that my REST request can be routed to the other server. Any ideas?
The proxy variable in your package.js file is only being used in development. I assume you are using create-react-app, here is the doc.
The way I routed all the API requests in my react app is by proxying all the requests through Nginx. Of course, it really depends on wich web server you are using.
Considering you are making all the requests to an /API endpoint you can proxy all the requests like this:
location / {
try_files $uri $uri/ /index.html;
add_header Cache-Control public;
expires 1d;
}
location /api {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://yourapiserver:port/;
}

Nginx setup for angular app with node API

I have been building API using express and front end using angular. Both are in different directory named /var/www/apps/client and /var/www/apps/server.
I want to deploy my application using nginx as a webserver. I am able to host angular application but when trying to request my API getting following error on browser.
Mixed Content: The page at 'https://xxx.xxx.xxx.xxx/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://xxx.xxx.xxx.xxx:3000/api/videos'. This request has been blocked; the content must be served over HTTPS.
Nginx config
server {
listen 80;
server_name localhost;
access_log /var/log/client/access.log;
error_log /var/log/client/error.log;
root /var/www/apps/client/dist;
charset utf-8;
location / {
rewrite ^ https://$host$request_uri? permanent;
}
}
server {
listen 443 ssl;
server_name localhost;
access_log /var/log/client/access.log;
error_log /var/log/client/error.log;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
keepalive_timeout 5;
root /var/www/apps/client/dist;
charset utf-8;
location ~ ^/(scripts.*js|styles|images) {
gzip_static on;
expires 1y;
add_header Cache-Control public;
add_header ETag "";
break;
}
location / {
try_files $uri /index.html;
}
}
My express server code -
var express = require("express"),
app = express(),
mongoose = require("mongoose"),
config = require("./config");
app.set("appPath", config.root);
mongoose.connect(config.mongo.uri, config.mongo.options);
app.use(function (req, res, next) {
"use strict";
// Website you wish to allow to connect
res.setHeader("Access-Control-Allow-Origin", "*");
// Request methods you wish to allow
res.setHeader("Access-Control-Allow-Methods",
"GET, POST, OPTIONS, PUT, PATCH, DELETE");
// Request headers you wish to allow
res.setHeader("Access-Control-Allow-Headers",
"X-Requested-With,content-type,api_key,adminid,userid");
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader("Access-Control-Allow-Credentials", true);
// Pass to next layer of middleware
next();
});
app.use(function (req, res, next) {
"use strict";
next();
});
require("./routes")(app);
app.listen(config.port);
console.log("Listening on port " + config.port)
Serving API at 3000 port. I found this If possible use nginx to redirect by location to node app?
But this is also not working. Any kind of help would be great.
I don't think, the issue is completely with your nginx config. The error message implies that the initial connection from the browser and nginx server was over https. And then you are trying to make an insecure connection through XMLHttpRequest with http.
Solution:
Either load up the initial connection as insecure i.e http
Or make your XMLHttpRequest with a secure connection i.e https.
To help with the config file
# For http
server {
listen 80
server_name localhost
access_log /var/log/client/access.log
error_log /var/log/client/error.log
root /var/www/apps/client/dist
charset utf-8
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:3000/;
}
}
# For https
server {
listen 443 ssl
server_name localhost
access_log /var/log/client/access.log
error_log /var/log/client/error.log
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
root /var/www/apps/client/dist
charset utf-8
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:3000/;
}
}
Restart Nginx
sudo /etc/init.d/nginx restart
Issue is the other endpoint which you are hitting internally is not Https protected, because of which you are getting the error
http://xxx.xxx.xxx.xxx:3000/api/videos
So, you should write a separate config for client to make the connection https secured. Add that proxy pass also to redirect all your request coming to port 443 to 3000 similar what you did for server
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:3000/;
}
Make sure ports are different for node and client app

Angular route without hash

I have an app where the admin side is built in angular, but the front consumer facing side is not.. and lives on a different server.
I'd like if visitors coming to:
domain.com/#/admin => angular app
But if they got to:
domain.com
This goes to the other server
Is this possible?
Thanks.
For a little more clarity, I think what I need is this:
I have a rails app as an api that angular consumes. Rails lives on server A and Angular lives on server B.
Both servers use nginx as the web server.
Also, the rails app serves up its own content, so I want any path other than admin to go to rails.
What I want is if users go to:
mydomain.com --> they hit the rails app and content on server A
when they go to:
mydomain.com/admin or mydomain.com/#/admin --> they hit the angular app on server B
I think I almost figured it out with the following nginx configs on the rails server, server A:
upstream serverA {
server rails;
server unix:///var/www/rails/shared/tmp/sockets/puma.sock;
}
upstream serverB {
server angular;
}
server {
listen 80;
server_name serverA;
root /var/www/rails/current/public;
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://serverA;
}
location ~* ^/assets/ {
expires 1y;
add_header Cache-Control public;
add_header Last-Modified "";
add_header ETag "";
break;
}
location /admin/ {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://serverB/#/;
}
}
While this gets me close, my angular scripts and styles that are references by my angular index.html file are not being found.

Resources