Invalid CSRF Token via Postman - node.js

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

Related

NodeJS send a token in the url when redirecting user after login

I'm building an application with nextJs for frontend, and nodejs for backend with using passportjs and facebook strategy for authentication.
And I want to send a token for the client after the authentication. After some research I've found the solution below:
router.get(
"/auth/facebook/callback",
passport.authenticate("facebook", {
session: false,
}),
(req, res) => {
// generate token ...
res.redirect(`localhost:3000/home?%{token}`)
}
)
And then, in the client, I would get the token in the query params and save it on localstorage to use it in the requests.
But my question is: does this solution leaves the token too vulnerable? is there a better way to do it?
If anyone could help me. I'm kinda lost in what's the best way to handle this situation.
You can send the access token through "response | res", eliminating some security problems when passing the entire URL.
res.status(200).send({ token: token });
And then access the response on the client.

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

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

Passport JWT is always returning 401 unauthorized when using OpenID Connect ID Token

I am following this tutorial to enable jwt authentication in my express API.
https://jonathanmh.com/express-passport-json-web-token-jwt-authentication-beginners/
If I use a standard username/password authentication, I am able to use JwtStrategy to authenticate the JWT Token that I receive in the request header. jwt.sign() happens on the user id and secret. All of this works fine.
When I try to modify this code to verify the id_token (JWT Token signed using RS256) from OpenID Connect, then I get 401 Unauthorized no matter what. I tried to debug in the JwtStrategy method and it looks like the request doesn't even go inside that function. This id_token appears to be a lot longer than the one signed with HS256 algorithm.
A simple passport.authenticate call app.get('/callback', passport.authenticate('jwt', { session: false }), function(req, res, next) {
});
Can someone please explain why it doesn't even recognise my token?
It depends on how you are passing the token from client and reading it in server. The request will go into the validate function only if it receives the token correctly. Check similar post https://stackoverflow.com/a/46020083/4548946.
It worked for me. Hope it helps you too.

PassportJS + RestAPI +SPA

I am using ExpressJS to build RestAPI, client is SPA and support authenticate by Google/FaceBook/GitHub/... via PassportJS. My question, callback from social login will return to RestAPI or SPA? If system returns to RestAPI, how can to redirect to home page on SPA. Another case, if system callback SPA, how can RestAPI receive and validate token from client. Please let me know common approachs.
Thanks,
You provide the callback url to the authentication service, you decide whether you handle the route by the SPA or the API. Oauth authentication (simplified) has two steps. Illustration on github:
Step 1) https://github.com/login/oauth/authorize?client_id=*YOUR_CLIENT_ID*$redirect_uri=*YOUR_REDIRECT_URI*
Opens a popup dialog that requests the user to authorize your application, if successful returns to your redirect_uri with a query parameter ?code=AUTHORIZATION_CODE
Step 2)You exchange the above AUTHORIZATION_CODE for a long-term access token via https://github.com/login/oauth/access_token
In your architecture, you should do Step 1 in the SPA and Step 2 in the rest api. You should rely on the spa to get the authorization code from the authentication provider, send that to your rest api, let the rest api exchange for a long term access token, save that token to the database, use it to retrieve user information or do whatever you want with it, then log in the user.
For step 1, you only need the CLIENT_ID, for step 2 CLIENT_ID and CLIENT_SECRET as well, so you can keep your application secure by storing the CLIENT_SECRET on the server side only.
The problem with having the callback uri handled by your rest api, is that the callback uri is called by the authentication provider (in this case github) and not by your SPA, therefore you can't send a response that redirects the user to the homepage. This would only work if your templates and routing were handled on the server side, which I assume is not the case in your architecture.
It's not obvious from the documentation, but when you register a passport middleware on a route like app.post('/login',
passport.authenticate('github'),, the middleware will check if the 'code' query param contains an AUTHORIZATION_CODE, if not, it kicks off step 1, if yes step2.
I used same stack(express, angular, passport) and followed that approach.
I created a button.
Login with facebook
Also I have two routes for passport
// send to facebook to do the authentication
app.get('/auth/facebook', passport.authenticate('facebook', {scope: 'email'}));
// handle the callback after facebook has authenticated the user
app.get('/auth/facebook/callback', passport.authenticate('facebook', {
successRedirect: '/#/profile',
failureRedirect: '/' //Redirect Homepage
}));
This code shows that if you login successfully you will be redirect to angular route(/#/profile) After redirect you'll have a cookie which has a token with name connect.sid since passportjs uses express-session.
Then you can check if user logged in everywhere by this middleware
// route middleware to ensure user is logged in
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect(301, '/');
}
You can take a look at my repository which contains the code above.
https://github.com/AOnurOzcan/meanTest
If you encounter a problem please let me know.

Resources