Interceptor for npm request package - node.js

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);

Related

How can i secure my api endpoint when there is no users registration

I have front end page - contact us - where every user can fill up the form and contact us.After that the filled form is send to our email. Because on our web site, there will not be user registration, so possible client can contact us but he will not need to sign up to visit our web site because it is not "friendly".
I always secured my web api with json web token, so i see if the user is registered in our db so he can have access to some api routes or not. But because this time there will be no DB with users, how can i secure my api endpoints ?
For example: malicious user comes to my website, he can see in the network tab the post request that is made for sending the email.
He can go in postman, and he can make thousands of request if he wants to my api endpoint and it will make me a problems because he is not filling the form on the frontend page, but maybe he will ping my endpoint very often with pre-made body post maked object in postman.
How can i prevent this things without user authentication ?
So the only way that i found until now is to check the origin - from where the request is coming. We can write a middleware at the beggining of our .js file before all other routes and check that
const express = require('express');
const router = express.Router();
const helpers = require('../utils/helpers');
router.use(helpers.checkOrigin);
router.post("/sendemail", async (req, res) => {
...
})
helpers.js file
const checkOrigin = (req, res, next) => {
console.log("checkOrigin", req.headers.origin);
if(req.headers.origin == "www.yourdomain.com") {
next();
} else {
res.status(403).json({error: "Unauthorized"});
}
}
in the
console.log("checkOrigin", req.headers.origin);
when we send request from postman then it prints undefined so it goes to the else block
but if the request comes from www.yourdomain.com then it will go in the if block, execute next middleware and accept request from all routes below including - sendemail.
If anyone has other solutions and better please let me know !

How to use Kerberos Client Authentication with NodeJS and Axios to make api call

We have a use case where we are calling multiple APIs in parallel from the ReactJS UI (from browser) which is hosted in IIS web server to NodeJS application server. In NodeJS application server we have written authorization express middleware which does the authorization checks using external API to see if the logged-On user is authorized or not, If authorized then we are calling further API calls to the backend to get the data or else middleware is returning back response as the user saying user is unauthorized to make further API calls.
Now we are trying to add kerberos based authentication for authorization API call and backend further API calls.
We are getting below error when we trying to add below working Kerberos NodeJS code snippet (Kerberos authentication in Node.js https.get or https.request) to our authorization API call in the middleware and backend data API calls.
const kerberos = require('kerberos').Kerberos;
const fetch = require('node-fetch');
(async () => {
const client = await kerberos.initializeClient("HTTP#site.internal.net", {
mechOID: kerberos.GSS_MECH_OID_SPNEGO,
})
const ticket = await client.step("")
const resp = await fetch("https://site.internal.net/api/v1/hello", {
headers: {
'Authorization': 'Negotiate ' + ticket
}
})
console.log(await resp.json())
})();
We are getting this error when called in parallel above working code:
[Error: AcquireCredentialsHandle: No credentials are available in the security package
and 401 unauthorized request error
Also, we have noticed above errors when kerberos.initializeClient & ticket = client.step("") code is called multiple times inside the for Loop, it was failing 2 or 3 times out of 5 and was throwing above error.
Can someone please explain what is the meaning of the above error and how to avoid that error ??
Thanks in advance

Local authentication in NodeJS express passing JWT token back to separate Angular SPA client

I am building an app with a back-end in NodeJS 12 Express 4 and a front-end client SPA in Angular 8. I am building local authentication with the PassportJS local authentication strategy.
Auth workflow:
A GET request is sent to the /login endpoint and the login page is loaded.
Note: The login page is NOT in the SPA, it is a simple pug page with a form that sends a to POST to the /login endpoint.
GET /login
router.get('/', (req, res, next) => {
return res.render('login');
});
The user enters their credentials, submits the form and sends a POST request to /login. The Passport local strategy checks the credentials and then in the callback, creates a JWT to be sent back to the client.
This is where I am getting stuck. If I had the login page in the SPA, I could just send an AJAX request and get the response back to the client as JSON e.g. return res.json(jwtToken) and the SPA could parse the token and store it in session storage directly.
However, since the login page is on the server directly, how can I send the token back to the client?
At the moment, I am trying to place the token in the auth header and 'redirect' to the client URL. This is working (I can see the auth token in the browser console) but how does can the SPA read the token on the Angular side? Angular would need to access the HTTP Headers, get the token and save it in the session storage.
POST /login
router.post('/', (req, res, next) => {
// Passport authentication strategy
passport.authenticate('local', function (err, user, info) {
// Callback after authentication strategy is complete
// Check error
if (err) {
console.error(err);
return res.status(404).json(err);
}
// Check if user was returned
if (user) {
// Generate JWT token
let jwt;
jwtToken = generateJwt();
// Set authorization header
res.set({
'Content-Type': 'application/json',
'Authorization': `Bearer: ${jwtToken}`,
});
// Redirect to the client
return res.redirect('http://localhost:4200/login');
//return res.json(jwtToken);
}
})(req, res);
});
Question:
In the Angular component, is it possible to parse the Authorization header to get the token that was sent by the server? I tried using the activatedRoute module but wasn't able to get access to the header data from the initial page load. I also tried adding the token as a URL parameter in the GET request but that makes the URL extremely long and exposes the token in plain text. Are there any reasonable ways send the token from the server to the client safely?
UPDATE:
I am going to try sending the token in a cookie using express cookieParser similar to this answer in another post. That way the SPA can access the token saved in the cookie, parse it, and then save it in session storage. However, I am hesitant to do this and am not sure if this is going to be the most sustainable technique, since this requires an additional module to parse the cookie in the SPA.
let options = {
maxAge: 1000 * 60 * 15,
httpOnly: false,
signed: true
}
// Set cookie
res.cookie('jwt-token', jwt, options)
// Redirect to the client
return res.redirect(302, 'http://localhost:4200/login');

ReactJs frontend & Passport NodeJs backend

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);
});

Invalid CSRF Token via Postman

I am using the csrf protection in my MEAN-Stack Application with the csurf node.js module.
As long as I send POST requests from my Angular frontend to the web service, everything works fine. But if I try to make a POST request via postman, I'll always face:
"ForbiddenError: invalid csrf token"
According to the first answer from How do I send spring csrf token from Postman rest client? i get the Token out of the cookie from the login request and set it to every post request.
Get requests are working fine.
I configured it as follows:
app.use(csrf({cookie: {path: '/', httpOnly: true}}));
app.use(function(req, res, next) {
let token = req.csrfToken();
res.cookie('XSRF-TOKEN', token);
res.locals.csrfToken = token;
next();
});
Best regards,
Tobias

Resources