I am planning to have an REST API in node.js , I want to make sure if the request comes from my web domain allow the request or reject it, how do I do this?
Basically I am trying to restrict access to the REST api by simple technique, any advise on this ?
If your criteria is only a particular user can access it or only signed user can access it,then you can do it with a helper function like below.
app.get('/api/users', checkuser, function(req, res) {
UserModel.find(function(err, users) {
if (!err)
res.json(users);
else
console.log(err);
});
});
function checkuser(req, res, next) {
if (req.user != 'manoj') return res.json('message': 'you dont have permissions to access this url');
next(); //if it is manoj then call the next() iterator function that will take u to the final callback(userFind)
};
Related
I am new to Auth0 and trying to implement it in my regular express web application. I need to protect/validate the user before they access some of my endpoints. My understanding is that i can do this with the JWT that is returned from the login callback. I have gotten that far, but when I login, it redirects, and I'm unsure of how to pass in the access token/store it securely on the client side.
this is what my callback endpoint looks like after logging in. It returns the authorization code but I am lost from here.
https://auth0.com/docs/api-auth/tutorials/authorization-code-grant
I return this on login:
/callback?code=oi9-ZTieXo0hYL6A&state=sMJAUK4QVs7jziJ7lXvwmGKF
// Perform the final stage of authentication and redirect to previously requested URL or '/user'
router.get('/callback', function (req, res, next) {
passport.authenticate('auth0', function (err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function (err) {
if (err) { return next(err); }
const returnTo = req.session.returnTo;
delete req.session.returnTo;
res.redirect('/user);
});
})(req, res, next);
});
where do i go from here?
Auth0 does not recommend storing tokens in browser storage (session/local storage). For client side applications, tokens should be short lived and renewed when necessary via silent authentication (renewed via a cookie session with the auth server in a hidded iframe).
This is outlined here:
https://auth0.com/docs/security/store-tokens
If you have a backend, then handle the tokens there, if you are using a SPA + API then use the strategy outlined in the link.
I have some routes in my Node.js API sending data from a MongoDB database to an Angular 4 frontend.
Example:
Node.js route:
router.get('/api/articles', (req, res) => {
Article.find({}, (err, articles) => {
if(err) return res.status(500).send("Something went wrong");
res.status(200).send(articles);
});
});
Angular 4 service function:
getArticles() {
return this.http.get('http://localhost:3000/api/articles')
.map(res => res.json()).subscribe(res => this.articles = res);
}
The question is, how do I protect my Node.js API routes from browser access? When I go to http://localhost:3000/api/articles I can see all my articles in json format.
This is not a security measure, just a way to filter the request. For security use other mechanisms like JWT or similar.
If the angular app is controlled by you then send a special header like X-Requested-With:XMLHttpRequest (chrome sends it by default for AJAX calls) and before responding check for the presence of this header.
If you are really particular about exposing the endpoint to a special case use a unique header may be X-Request-App: MyNgApp and filter for it.
You can't really unless you are willing to implement some sort of authentication — i.e your angular user will need to sign into the api.
You can make it less convenient. For example, simply switching your route to accept POST request instead of GET requests will stop browsers from seeing it easily. It will still be visible in dev tool or curl.
Alternatively you can set a header with your angular request that you look for in your express handler, but that seems like a lot of work for only the appearance of security.
Best method is to implement an authentication token system. You can start with a static token(Later you can implement dynamic token with authorisation).
Token is just a string to ensure the request is authenticated.
Node.js route:
router.get('/api/articles', (req, res) => {
let token = url.parse(req.url,true).query.token; //Parse GET param from URL
if("mytoken" == token){ // Validate Token
Article.find({}, (err, articles) => {
if(err) return res.status(500).send("Something went wrong");
res.status(200).send(articles);
});
}else {
res.status(401).send("Error:Invalid Token"); //Send Error message
}
});
Angular 4 service function:
getArticles() {
return this.http.get('http://localhost:3000/api/articles?token=mytoken') // Add token when making call
.map(res => res.json()).subscribe(res => this.articles = res);
}
With Express, you can use route handlers to allow or deny access to your endpoints. This method is used by Passport authentication middleware (which you can use for this, by the way).
function isAccessGranted (req, res, next) {
// Here your authorization logic (jwt, OAuth, custom connection logic...)
if (!isGranted) return res.status(401).end()
next()
}
router.get('/api/articles', isAccessGranted, (req, res) => {
//...
})
Or make it more generic for all your routes:
app.use('*', isAccessGranted)
I'm using express framework , Lets say I have this line in the API :
router.delete('/user',(req, res) => { //deleting...}
Now I want that only an Admin will be able to access this line.
In the rest of the code there are lines that only user can access like :
router.put('/post')
And lines only admin can access like:
router.put('/killDB)
what is the best way (tokens, sessions or something like that) that will be able to help me differenitate between the two?
Use password to authenticate users and then check if the user is an admin. And then simply add password logic to your route. Below I will provide my code where I just check if user is logged in (it was enough for me)
router.get('/delete', isLoggedIn, function (req, res) {
Page.collection.drop();
var page = new Page();
page.save(function (err) {
if(err) throw err;
res.redirect('/admin');
});
});
// render login form
router.get('/login', function (req, res) {
res.render('login',{ message: req.flash('error'), layout: null});
});
// process the login form
router.post('/login', passport.authenticate('local-login', {
successRedirect : '/admin', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/');
}
You can use the connect-roles package to authorize your users, and then route them to those URL's which they are allowed to access.
You can also opt for passport.js, however it is more or like a authentication package where as the connect-roles just aims at to provide only the "authorization" part. And this package works well with Express.
Once you implement this package, you can use the "role" attribute to check the user's authorization level and allow them to perform their respective actions.
For eg.,
if (req.user.role === 'admin') {
router.put('/killDB)
}
You can check out the package here: https://www.npmjs.com/package/connect-roles
Hope this helps!
I'm trying to build a simple application with parse.com as my user manager.
I would like to make a login call to parse.com from my client side, and call my node.js server with the user's session token (I'll add it as a cookie). In the server side, I'll validate the session (using https://parse.com/docs/rest#users-validating) and allow access only if the session is valid.
For example (in my server):
app.get('/api', function(req, res, next) {
var token = getTokenFromRequest(req);
if(tokenIsValid(token)) {
next();
} else { // Redirect... }
});
app.get('/api/doSomething', function(req, res) {
// Do something....
});
the tokenIsValid(token) function should be implemented using https://parse.com/docs/rest#users-validating.
However, it seems that the REST API user validation returns the user even if the user is logged out (expected to return 'invalid session').
Is this a bug in the REST API user validation? What am I doing wrong? Is there a better way for doing that?
Thanks!
Via REST there's no concept of sessions really. REST calls are meant to be stateless meaning that the (current) user at /me will be serialized from the token provided. If the token is associated to a user it will return the JSON representation of that user otherwise in returns an error.
One way or another that call is asynchronous so you can't really use it in and if statement.
You can do:
app.get('/api', function(req, res, next) {
var token = getTokenFromRequest(req);
serializeUserFromToken(token,function(err,parseResponse) {
if(err) return next(err)
if(parseResponse.code && parseResponse.code === 101){
// called to parse succedded but the token is not valid
return next(parseResponse);
}
// parseResponse is the current User.
next();
});
});
Where serializeUserFromToken makes a request to Parse with the token in the X-Parse-Session-Token header field.
I want to send JSON back if a user accesses a route and the accept headers only allow JSON, and I want to redirect a user to a page if a user accesses a route and the accept headers do not allow JSON.
My solution is very hacky, but it involves inspecting req.headers.accept and seeing whether the string contains json. If it does, I return back JSON, else, I redirect. Is there a more optimal solution?
You can try the res.format method.
res.format({
'application/json': function(){
res.send({ message: 'hey' });
},
default: function(){
res.redirect('nojson.html');
}
});
The method describe by cr0 is probably 'The right way'. I was unaware of this newer helper method.
That solution is about right. You can use req.get to get headers in a case insensitive manner and use regexp to check the value. Typically I use the following.
module.exports = function() {
function(req, res, next) {
if(req.get("accept").match(/application\/json/) === null) {
return res.redirect(406, "/other/location");
};
next();
}
}
Then this can be used as a middleware.
app.use(require("./jsonCheck")());
You could also get more elaborate with the module and redirect to a custom place by changing the exported function.
module.exports = function(location) {
function(req, res, next) {
if(req.get("accept").match(/application\/json/) === null) {
return res.redirect(406, location);
};
next();
}
}
and use it like this
app.use(require("./jsonRedirect")("/some.html"));