How to structure Express to always send Angular whilst protecting API routes? - node.js

On my node-express back-end, I want to always serve my Angular files UNLESS it is an API route. If it is an API route, then deal with it as such.
All API routes are protected, except /api/signin, /api/changepass.
How do I structure my code? I think the order of my code is wrong... I keep getting back an UnauthorizedError: No authorization token was found from express-jwt.
Currently my code:
app.use(jwt({secret: secretKey}).unless({path: ['/api/signin', '/api/changepass']}));
app.use('/', [
AuthRouter,
StructureRouter,
DataRouter,
ResultsRouter,
]);
// Serve angular unless it is a path for the acme-challenge for let's encrypt certificate
app.use(ServeAngular().unless({path: [/\/.well-known\/acme-challenge/i]}))
app.use(/\/.well-known\/acme-challenge/i, express.static(path.join(__dirname, '.well-known', 'acme-challenge'), {dotfiles:'allow'}));

"want to always serve my Angular files UNLESS it is an API route"
Instead, you should return your Angular app on the root path or on a static path if called via HTTP GET method and let hash routing handle the routes in Angular. Node doesn't bother hash routing, so you could use them to navigate through your app.
Anyway on error you could redirect on error or login page
"All API routes are protected, except /api/signin, /api/changepass"
redirection, authentication and protection should be handled by express's middleware function (https://expressjs.com/en/guide/using-middleware.html) in order to ensure authentication or redirection. Your application shouldn't be aware of which route should be protected or not.
"I keep getting back an UnauthorizedError: No authorization token was found from express-jwt"
On your Angular code have you created the required interceptors in order to forward on each request the required jwt (as cookie or header)?

Related

CSRF - invalid token: Capacitorjs App with Node.js backend

In building a mobile app with capacitorjs from a functional web app with Node.js backend that uses the csurf library for the prevention of CSRF attacks, I am getting invalid token errors. The backend is being served from a local machine over http, for now. CORS is setup on the routes under test.
As I understand it, the csurf library provides the client two pieces of information, a secret in the form of a cookie, and a token, both of which the client sends back when making a POST request. The library then checks the expected value of the token with the calculated value (from the secret and from part of the token), and looks for them to match. (Aside: Getting the client to send back the cookies required some effort: I could make it work with a POST using form submission, but not with jQuery $.ajax.) At any rate, I was able to get the client to send back the secret (as a cookie in form submission or otherwise in AJAX POST) and the CSRF-Token, but they don't check out, i.e., the csurf library seems to expect a different answer, for example, here's an example of what the cookie and token look like in one instance:
req.cookies: { _csrf: 'W66Nq2CMcTTJeiFjJRu0gWFH' }
_csrf: 'guOiwkW0-BZguE8LKmYvW3ArKXhUGZuFN_88'
I put some log statements inside the function that checks these two values for correspondence in the csrf library that is used by the csurf library, and got this result:
csrf: secret W66Nq2CMcTTJeiFjJRu0gWFH
csrf: token guOiwkW0-BZguE8LKmYvW3ArKXhUGZuFN_88
csrf: expected guOiwkW0-cWREHVwpgMGiIMoKiSJmc4bA3HE
This kind of result happens whether I make a POST as form submission, or as an AJAX request. For the time being then, I have disabled CSRF protection on these cors routes serving the capacitorjs app.
Another issue that has me concerned is that the folks who wrote this library have this advice:
Don't ever create a GET /csrf route in your app and especially don't
enable CORS on it. Don't send CSRF tokens with API response bodies.
in Understanding CSRF. I am wondering how to send CSRF Tokens to the client, if not in API response bodies!

Postgraphile + express + jwt is throwing 'No authorization token found' even though graphiql works

I am trying to use the jwt express middleware as well as the postgraphile middleware together, and I want to add an exception for having an auth token to the graphiql interface. I know that postgraphile starts up graphql on /graphql and graphiql on /graphiql unless otherwise configured. So in my jwt middleware init I am doing this:
app.use(jwt({ secret: process.env.JWT_SECRET}).unless({path: ['/', /\/graphiql/i, /\/graphql/i, /auth/i]}));
Which makes it so /graphiql, /graphql, and /auth routes do not require an auth token. This appears to work fine because I can get to the graphiql interface just fine, and the graphql queries I'm building are working just fine. However, in my express terminal, there is still something that it's trying to connect to that is throwing a No authorization token found when I load http://localhost:3000/graphiql
Any thoughts on what else it might be trying to hit that I will also have to add to the unless() method in the JWT middleware?
PostGraphile currently loads the GraphiQL assets (JS, CSS) from /_postgraphile/*, so you probably want to whitelist those assets.
Another approach is to mount postgraphile before you add the jwt middleware - that way it will be unaffected by it and you won't need to maintain a .unless list.
app.use(postgraphile(...));
app.use(jwt(...));
app.use(...);

Implementing Passport Local Authentication in Backend

I am trying to implement the passport local authentication in my backend. It is a todo app which is built with the help of the MEAN stack. Unfortunately, I am facing some problems implementing it. The folder structure is
In Controllers folder, the controllers for the various routes are present.
In routes folder, the file "api.route.js" contains the main route. I want to implement authentication here such that no further routes can be accessed if the user is not autheticated.
In the api subfolder, the different routes are configured.
In the config subfolder, the passport local strategy is defined.
Another new problem I have noticed is that the routes after todo are not detected.
Example : localhost:3000/api/todos
localhost :3000/api/todos/login
route does not work. It says Error 404. Every other sub routes are the same. Any help which will help me to implement will be appreciated. The github profile for this project is :
https://github.com/AritraWork97/TODO-FULLSTACK
The main folder is Todo Backend, it contains the backend code
To, protect routes in back-end I think express-jwt will be handy.
Initialize it like this,
const jwt = require("express-jwt");
const auth = jwt({secret: jwt_secret});
Then put the auth middleware before a route that you want to protect.
router.get("/secret/:uid", auth, profileCtrl.secret);

Best way to handle API calls from frontend

Okay, so atm i have a frontend application built with Nuxt JS using Axios to do requests to my REST API(separate).
If a user does a search on the website the API URL is visible in XMLHttprequests so everyone could use the API if they want to.
What is the best way of making it so that only users that search through my website gets access to the API and people that just directly to the URL gets denied. I suppose using some sort of token system, but what is the best way to do it? JWT? (Users never log in so there is no "authentication")
Thanks!
IMO, you CANNOT block other illegal clients accessing your
backend as you describe that the official client and other illegal have the same knowledge about your backend.
But you can make it harder for illegal clients to accessing your backend through some approach such as POST all requests, special keys in header, 30-minutes-changed token in header and server-side API throttling by client IP.
If the security of the search API is really important, authenticate it by login; if not, just let it go since it is not in your critical path. Let's focus on other important things.
I'm in the same "boat" and my current setup is actually in VueJs but before even come to StackOverflow I developed a way to actually, the frontend calls the server and then the server calls the API, so in the browser, you will only see calls to the server layer that, the only constraint is that the call must come from the same hostname.
backend is handled with expressJs and frontend with VueJs
// protect /api calls to only be originated from 'process.env.API_ALLOW_HOST'
app.use(api.allowOnlySameDomainRequests());
...
const allowHostname = process.env.API_ALLOW_HOST ||'localhost';
exports.api = {
...
allowOnlySameDomainRequests: (req, res, next) => {
if(req.url.startsWith('/api') && req.hostname === allowHostname) {
// an /api call, only if request is the same
return next();
} else if (!req.url.startsWith('/api')) {
// not an /api call
return next();
}
return res.redirect('/error?code=401');
},
...
};
In our case, we use Oauth2 (Google sign through passportJs) to log in the user, I always have a user id that was given by the OAuth2 successful redirect and that user id is passed to the API in a header, together with the apikey... in the server I check for that userid permissions and I allow or not the action to be executed.
But even I was trying to find something better. I've seen several javascript frontend apps using calls to their backend but they use Bearer tokens.
As a curious user, you would see the paths to all the API and how they are composed, but in my case, you only see calls to the expressJs backend, and only there I forward to the real API... I don't know if that's just "more work", but seemed a bit more "secure" to approach the problem this way.

Protect non-api (res.render) route with express-jwt token in Node.js

First of all, I have read all tutorials on protecting REST API routes with jwt (express-jwt & jsonwebtoken), and it works fine for that purpose.
This works fine:
app.use('/api', postApiRoute);
And this also works, somewhat, I mean.. it does verify the token when I use it to show a webpage with angular http request calls, but when you add expressJwt({secret: secret.secretToken}), you cannot just access localhost:3000/api/post anymore. The expressJwt({secret: secret.secretToken}) is the problem here.
app.use('/api', expressJwt({secret: secret.secretToken}));
app.use('/api', userApiRoute);
What I really need is to protect a non-json but html/text request route with jwt like eg.:
app.get('/admin*', expressJwt({secret: secret.secretToken}), function(req, res){
res.render('index', {
//user: req.session.user, <- not sure how to do the equivalent, to extract the user json-object from the express-jwt token?
js: js.renderTags(),
css: css.renderTags()
});
});
.. without having to make http requests in angular/js, but using express' render function.
I need to do this since my application has 2 primary server routed views, so 1 where admin scripts are loaded from, and 1 where the frontend (theme) assets gets loaded.
I cant however get jwt/tokens to work with server rendered views, only json api requests.
The error i'm getting is: "UnauthorizedError: No Authorization header was found"
Couldn't find any information about (server rendered views protected with jwt, only serverside api requests and client side angular/ajax http requests) this, so I hope my question is clear, and that I do not have to fall back to using sessions again.
Not sure if I understood correctly, but if you are talking about entry html routes (i.e., loaded directly by the browser and not by you angular app), then you simply have no way of instructing the browser as to how to set the authorization header (no without introducing some other redirect based auth flow).

Resources