ReactJs frontend & Passport NodeJs backend - node.js

I am building a project which is API RESTful with NodeJS, Express & Passport. And for the Frontend of this application I want to use ReactJS.
Can I create a separate project with create-app-react for my frontend and fetch my API while keeping the benefits of Passport ? Or I should send always the user's information in my request? Or serve my Frontend on the same server of the API?

Yes, you can have a client & a server on 2 differents port, and keep the benefits of Passport.
But for that, when you fetch you API use credentials : 'include'
Because, by default, fetch won't send or receive any cookies from the server, resulting in unauthenticated requests if the site relies on maintaining a user session (to send cookies, the credentials init option must be set).
Example:
fetch('https://example.com', {
credentials: 'include'
})
.then( res => {
// Some stuff...
})
.catch(err => {
console.log(err);
});

Related

Handle login for API and static page in node js

I'm working on MERN stack application. There are two types of endpoints in my applications. One for API and another for static routes (using handlebars in NodeJS). I have used the basic JWT token to secure the API endpoints which would be accessible by React App. But JWT is not useful for static routes.
So How can I use single authentication for both types of routes?
Static routes are preview URL which is generated by admin panel. Only authenticated users can access them. HubSpot has the same strategy for the pages, Preview URL of pages can only be accessible by authenticated users.
Is there any other way to authenticate both endpoint types?
We can try the following way to achieve this requirement.
Host a NodeJS on the primary domain where APIs and static routes will run. And Host a react app on a subdomain where the admin panel run.
so the domains would be as follows:
React path would be app.website.com
Node path would be website.com
A user can login via API in react app and store the token in cookies with the primary domain. Now we can verify JWT in static routes by retrieving that token from the cookie.
Store a token in cookie:
document.cookie = `token=${TOKEN};expires;;domain=${PRIMARY_DOMAIN};path=/`;
Middleware to check the authentication:
const { token } = req.cookies
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
if (err) {
return res.status(401).send("Unauthorized!");
}
req.user = decoded;
});
next()

How to authenticate angular 10 client app from node/express js using passport-google strategy?

I'm building a web app that is being used on top of microservices architecture.
Using node/express js I have implemented auth service and products service both are listening on different ports like
http://localhost:8001 for authentication service
http://localhost:8002 for products service.
Kong Gateway used to authenticate and connect the microservices with jwt. Implemented passport-jwt and passport-local strategy to authenticate the users from client side using post calls.
Finally I have implemented the google auth on server side using passport-google strategy in this below URL
http://localhost:8001/auth/google -> it directs me to google auth consent screen after sign in it is redirecting to below Url
http://localhost:8001/auth/google/callback with token. it works fine at server end.
async googlecallback(req, res, next){
passport.authenticate('google', {
session: false,
}, (err, user, message) => {
if (!user) {
return next(new UnAuthorizedException(message))
}
const token = user.generateToken()
user = UserTransformer.transform(user)
user.token = token
this.Response(res, user, message) // sending response to client using custom method
})(req, res)
}
. When I come to authenticate the user from angular app client side. I'm unable to proceed further. just struggling here. :-(
How can I authenticate the user when they click google sign in button in angular 10 on client side?
My front end app Url like http://localhost:4002/account/login
Tried to use window.open("http://localhost:8001/auth/google","_blank") method, not working as expected.
res.setHeader('x-code', 'jwthere'); header method. Also tried to pass the JWT token with URL parameter. but both seems unsecure.
http://localhost:4002/account/login?token=7wF8bit5W1Pfi5Glt1X8H0YQu8BN7OeNRcX1zbj3AGpUHaYSxLlNIjHpzuw
security is the major concern here. I want the google sign in like khanacademy social login
https://www.khanacademy.org

Where and how do you generate a JWT token when authenticating a socket.io connection with Node/React?

From what I understand about Socket.io, there are multiple security issues, such as those mentioned in this stack exchange post.
For my case, I'm using socket.io in Node and socket.io-client for React, and setting up a nice line of communication, however I don't need any login from the client side, since I'm simply querying an external API from the backend and posting results to the front end. So I've decided to use the package socketio-jwt to secure the connection using jwt tokens.
To implement, the documentation contains the following example to use jwt authentication:
Server Side
io.use(socketioJwt.authorize({
secret: 'your secret or public key',
handshake: true
}));
io.on('connection', (socket) => {
console.log('hello!', socket.decoded_token.name);
});
Client Side
const socket = io.connect('http://localhost:9000', {
extraHeaders: { Authorization: `Bearer ${your_jwt}` }
});
My question is this: on the client side where does the variable your_jwt come from and how can I generate it?
The token needs to be generated by the login API. The user sends username and password to a login endpoint and then your server returns the JWT.
Now, what is this login API?
Most API server implements an HTTP endpoint (POST /login). Then the client can save it in local storage.
If your app doesn't have an HTTP server to support you can just implement this via WebSocket.
You should have an endpoint in your Node app where you generate JWT, client side will get it from that endpoint, save it in persistent storage and reuse it.

Expose CSRF tokens to the client-side

I have a web application that consists of two parts:
app-front React application, that deployed in AWS CloudFront, and avaliable via app-example.com
app-api Node.js + Koa application, that deployed in EC2 instance (behind load balancer), and avaliable via api.app-example.com
app-api has CSRF protection, that uses a secret key in user session and token that is verified on the server side. (https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Synchronizer_Token_Pattern)
How can app-api expose CSRF tokens to the app-front ?
There are several ways:
Include the token in html pages:
<meta name="csrf-token" content="{{csrfToken}}">
But this method does not work for me, because app-api doesn't serve html pages (app-front located in AWS CloudFront)
Set CSRF tokens in cookies via AJAX
server.get('/csrf', (req, res) => {
res.cookie('_csrf' , res.locals._csrf, {expire : new Date() + 9999});
return res.json({
"status": "success"
})
})
But this is an additional request that I would like to avoid.
Maybe there is another solution?

Interceptor for npm request package

I am working on an Express JS web application. I have 3 layers in my application. External API server, Express and Angular as front end. So each AJAX requests from front end should pass through express in order to reach the API server and the same way, response too. Authentication is managed by API server. When I send request to login from Angular, it will reach Express first, then Express will sent a request to API server, API server will send the Authentication token to Express and Express will pass it to the front end. So all the request from Angular will send the Authentication token as header to Express, express will send the corresponding request with the access token. This how my application works. I know little complicated. Now I am retrieving the access token from front end request and pass it to the API server in all the Controllers. What I want to do is, I have to write an interceptor which will globally retrieve the access token from the front end request and will pass to the API server.
You can add an application middleware in your main file i.e. (app.js/server.js) above your routes.
function interceptor(req, res, next) {
let headers = req.headers;
headers.someHeader = 'xyz'; // add your headers like this
request('your server url here', {
method: req.method,
headers: headers,
}, (err, response, body) => {
if (err) {
next(err);
}
else {
console.log(response.request.headers);
res.send('OK');
}
});
}
app.use(interceptor);

Resources