Best practice for REST API url format when it's stateful with session? - node.js

I am writing a full stack app. I am using front end templating, not server side.
I originally wrote my routes to be api endpoints with restfull standards. So, for instance....on the front end if a user wanted to view their profile I would have the api call out:
router.route('/users/:userId')
.get(isLoggedIn, api.getUserById)
These api endpoints are not public in the manner to be consumed by other apps, they are just for the front end web app to consume.
I am using session tracking to do this, because the user will always stay logged in once they are logged in. I realize that I do not need the user ID number in the api call, because I can just get it from the session object. With that being said, how should I construct the /users/:userId route? I no longer need the :userId because I can get it from the session object. But if I did something like /profile it looks crummy and not to restful standards(even though I am doing session tracking so it is statefull).
What would be the best way to make the route for best practices? /profile or /users/:userId even though I don't need :userId?

Related

Should login and get profile be two different api endpoints?

I am designing api for mobile application.
I am not sure should I have one endpoint login which will return tokens & user profile
Or have two endpoints and after login call getProfile endpoint.
I saw that people mostly use second option but I don't see benefit of that approach?
Thinking in terms of the single-responsibility principle (which basically says "API methods should do one thing really well"), I'd suggest separating these into two separate things:
POST /login would set up a session and return the session ID to be used in subsequent requests.
GET /profile would return profile information provided a valid session ID is provided.
There are obvious benefits along the "happy path" for combining these, mainly the fact that after a login operation completes, you automatically provide the user with the data they most obviously would want next (who the user is). Why waste an extra API call to find it out, right?
If that's all your API will ever need to support, then there's no reason to separate these. But there are a couple cases I can think of for why you might want them separate:
What if an existing and already logged-in user wants to fetch the latest profile information? This means you must support GET /profile anyway (or have them POST /login again which is wasteful).
What if profile information is already cached and the POST /login API call is only happening to re-authenticate the user inside the app to complete an action? You'd be wasting bandwidth by sending data that's not needed.
Additionally, testing is usually a bit easier when you have each API method doing the one thing they imply they do (POST /login logs the user in, GET /profile fetches the current logged-in user's profile).

Restrict api access in Node JS express

I have an express server with a few API routes like this:
server.post("/api/send-email", (req, res) => {
});
});
You don't need an auth token to access the API, but I only want my website mydomain.com to be able to use it.
I have tried enabling restricting access like this:
function restrictAccess(req, res, next) {
if (req.headers['origin'] !== 'http://localhost:3000') {
res.sendStatus(403);
} else {
next();
}
}
And I then passed restrict access into my route as a middleware.
When I make a POST request with postman I can't the API anymore, but I can just change the origin header and am able to access it again.
How can I allow only requests from mydomain.com? I have searched the internet for a long time now, but couldn't find anything. Is it even possible?
How can I allow only requests from my own webpages at mydomain.com?
In a nutshell, you can't. Any tool like postman or any script (such as node.js, PHP, Perl, etc...) can send whatever headers or other request parameters it wants so headers by themselves are useless for restricting access to only a web page in your domain.
That's just how the web works.
Restricting access would more commonly require a user login or some credential like that (probably setting a cookie that you can check) and then if you see that your APIs are being abused, you can ban/remove a specific user account that is doing it.
There are other techniques that may make it more work for scripts or tools to use your API, but even they are not immune to a hacker that wants to put in the work. For example, your server can generate a token, embed it in your web page and then whenever you make an API request from your web page, you include the token from the web page. Your server, then checks for the presence of a valid token. You make sure that tokens expire in some reasonable amount of time so a hacker can't just get one and use it for a long time.
A determined hacker can still scrape a token out of your web page whenever they want to use it so this is only an obstacle, not something that stops a determined hacker.
The only real solution here and what someone like Google uses for their APIs is to require some sort of credential with each API call and then instrument your server for abuse of the APIs (rate limiting, unintended use, etc...) and then revoke that credential if it is being misused. The credential can be a developer token (as with some Google APIs) or it can be some sort of authentication credential from a user login (like perhaps a cookie).
There are other tricks I've seen used before where an API only works properly if a sequence of requests came before it that would normally be coming from your web page. This is a lot more work to implement and maintain, but if your web page would normally issue a request for the web page, then make two ajax calls, then request five images and then call the API, you can somehow have your server track this sequence of events from a specific browser and only if you see the expected sequence of events that looks like it's coming from a real browser web page, so you allow the API call to work. Again, this is a lot of work and still not infallible because determined hacker can just use something like puppeteer to automate an actual browser.
Major browsers send along the origin header without permitting any browser Javascript to modify it.
Non-browser API clients, like Postman and anything else, can set the origin header, and other headers, to whatever they choose. Non-browser API clients can easily spoof your API pretending to be browsers.
Therefore, security tip, using the origin header's value to decide whether to grant access to your API offers you no security whatsoever.
You really do need some kind of token access mechanism. Especially for an API that sends email. If a cybercreep finds your API, your hosting service will accuse you of sending spam.
Sorry about that. :-( Security is a pain in the neck.

Security for React front-end and Node back-end

I'm relatively new to the modern JavaScript web development world. I've built a very simple Node/Express back-end and a separate React front-end. My vague plan is to have users that will have permission to access certain areas of the front-end, and then have the front-end make requests to the back-end. Can the front-end and back-end share the same authentication/authorization scheme? Can they both use something like Auth0? How can I make these two secure?
I'm a little stuck and would appreciate any advice or a nudge in the right direction. I'm mostly stuck because these are two separate applications but the same "user" would technically have permissions to certain React views as well as certain Express endpoints - how they moosh together?
Thanks.
Although seems not directly related to your topic, but I would actually suggest you try Meteor if you are not planning to immediately start working on large projects (not pressing too hard on scalability).
Meteor has a builtin support for Accounts and interacts with MongoDB nicely, and it also has its own DDP protocol that simplifies API call massively. It also interacts nicely with React.
If you think Meteor might not be a good choice for yourself, you could still learn from its design policies of authorization, etc. It has quite a bit package source code that are not too difficult to understand, and should be helpful for you to learn the basic idea. (Actually, Meteor's Accounts package already implements the basic idea mentioned by another answerer, you can learn from its design principles)
When users log in to your site, issue them with an access token that they keep client side. On front-end, check if user has token and correct permissions before rendering components. On back-end, send the token as request headers to the endpoints.
I have implemented a similar case, but with the spring boot kotlin at the backend instead. My solution is using JWT token to validate the authentication and authorization.
User logins by input login form and send POST method to backend via a REST API.Backend validates credential and returns the JWT token including encrypted user_role, expiration date, etc... if valid or 403 exception
Front-end decodes the JWT (using jwt-decode lib or something else),
save it to validate the access permission to specific page in the
website based on user_role. Eg: role='ADMIN' can access to admin dashboard page, role='USER' can access user profile page, etc.
If you use express as the backend, I suggest to use the feathersjs. It has backend solutions for this and an optional front end version. Refer: https://docs.feathersjs.com/api/authentication/jwt.html
Secure Front end (React.js) and Back end (Node.js/Express Rest API) with Keycloak follow this

Best way to handle authentication on a react-redux single page appliction?

I'm currently sending the client an empty html document with a few scripts included that set up my single page application with react-redux. After everything is set up I'm fetching the dynamic data using AJAX and determine if the user is logged in or not. If the user is not logged in, he will see the products available only for users that are not authenticated and conversely.
Even though I am a noob, this seems extremly primitive to me and I don't know how I can do this better.
So what is the best way to handle authentication in react-redux applications?
Thanks a lot for helping.
There's a few options:
Passport which you can install through npm and it has a variety of strategies you can authenticate through such as Auth0 Link here
Firebase - a solution that google has that can be used as a drop-in authentication module. Link here
Meteor framework - I believe this framework has multi user authentication. Link here
First, for authentification you need to have a token or session id on the client side. So, there should be next steps:
After login, you receive token|session_id from backend and put it to the store and also to the localstorage not to lose it after page reload.
While initializing your app, get the token from localstorage and put it to the store every time.
When you do request for products list, add the token to ajax request (usually in headers).
Based on token, back-end application should returns another list of products.
It is a regular logic for such situations and of course it requires work on back-end side as well.

How to make sure a POST request to a REST api is "safe"

I have a JSON REST-api with NodeJs, Express and MongoDB.
Several user accounts are using this API to CRUD resources of a web app.
Access to the API is granted via a /login route, where users can establish a session.
But lets say one of my users are evil, and he knows that the front-end is talking to a API, and he wants to send some unexpected JSON data to the API.
Lets say he establish a session with the API, and then use a REST-client, like POSTMAN to send JSON that is not expected to a POST route.
What is the route is expecting something like this
{
name: "Anders",
age: 32,
country: "sweden"
}
but instead receive something like this from an "evil" user armed with a REST-client.
{
wrong_key1: 23423432423423,
wrong_key2: 2341234123431542315413,
wrong_key2: ["ascdaeawe", "sadfasfe", "sdfahrta"]
wrong_key4: "http://www.evildomain.com/",
}
What is the best way to handle this?
Filter out just the expected values from req.body, validate them, and ignore all others?
Disallow request from other domains, making sure the request are only coming from my web app domain? This seems a bit "anti REST"
although, and I dont even know if this is possible.
Expect users with a login never to do something like this, and therefore not deal with it?
Something else...?

Resources