multiple axios request in a react-native app: best practices - react-native

I have a question concerning a react native app and doing network requests.
I'm creating a react native app and as a backend I'm using NodeJS.
Users can sign up/sign in, and the refresh token is stored. Everytime the app opens, a new refresh token is fetched (if the user is signed in). This is an example of a network request that happens every time the app opens.
When the app opens and the user is signed in, I do a second network request (after the first network request for the access token was successful), to check if the data in redux has to be synchronized with the data in the database. I store some general information like the username locally + in the database. If - for any reason - I have to change the username in the database, I set the field "shouldSync" to true. The app sends a request to /api/sync, the controller sees that shouldSync = true and sends back all the data from the database to the user.
I also have a third network request that runs every time the app opens up: to check if there is a new version. I do a request to /api/version, with a response like "1.0.0". If the local version differs from the version in the response, I show an alert (only one time) saying there is a new version in the app store/play store.
When the app closes/goes in background mode, I also do a network request to the server to store the last active timestamp.
All these requests work, and I don't see any bottlenecks yet, but I have never built a production-graded app, so I have a few question concerning these network requests. I hope somebody can answer them.
Is it ok to do 3 separate network requests, or should I try to combine the three requests into one? I could combine the access token request + sync request (because these run when the user is signed in), but NOT the version request (because this request always has to run).
On some screens, I need dynamic data from the database/server. Sometimes I have 3-5 separate requests running at the same time. I'm using axios and I've made my code like this:
// first request
const requestOne = () => {
return axios({ ... });
};
// second request
const requestTwo = () => {
return axios({ ... });
};
// run these requests when the screen mounts
useEffect(() => {
axios.all([requestOne(), requestTwo()])
.then(axios.spread((requestOneRes, requestTwoRes) => {
// response from request one
console.log(requestOneRes.data);
// response from request two
console.log(requestTwoRes.data);
}));
}, []);
Is this a good example of combining multiple requests?
The most requests don't have a lot of response data. I have tested some requests in Postman and I've checked the response sizes of some requests, I've listed them here:
Everytime the app opens up:
/api/version: 463B request size / 231B response size
When the user signs in or signs up:
/sign-in: 476B request size / 1.16kB response size
/sign-up: 472B request size / 408B response size
When the app opens up + when the user is signed in:
/api/version: 463B request size / 231B response size
/refresh-access-token: 649B request size / 521B response size
/api/sync: 633B request size / 244B response size (NOT SYNCING) or 592B response size (SYNCING)
Total: +/- 1.6kB request size / +/- 1.25kB response size
I'm using express and BodyParser and I've set the limit to 2MB (2,000,000B).
app.use(bodyParser.json({ limit: 2000000 }));
I have installed request-stats in my NodeJS-backend to log all incoming requests. I'll all parts of my app separately and log all (big) requests, but for now I don't see any requests > 10kB, and even these are very rare.
Sorry for the long text. I want to be as clear as possible.

One recommendation, depending on the nature of your auth, is to remove the refreshToken expiry. Technically, the refresh token should be the retainer for the generation of new accessTokens (of which have an expiry). Refresh tokens themselves should not be regenerating without a relog by the end user. So instead of the user getting a new auth token, my way of assessing requests is 1. attempt the desired request, upon a 400 error, assess the response in axios for handling. If it is the result of an invalid/expired access token, request for a refresh with the stored refresh token. 2. Resend the prior request. This system removes the need for unnecessary request handling upon app start. Good luck!

Related

How to judge the success of third-party authentication?

My front-end is built with vue, and the back-end is with golang. My questions are 1. When I click the button to request a third-party login, how do I judge that the third-party authentication is successful? 2. And how do I get the data on the server side
The second question I think of is to save data on the server side through cookies and session, and the front end can get information through the cookie HTTP request header. Is there a more concise way
The second question, how can I judge the success of the third-party authentication?
My jump Url code is
/// vuex
async accountLoginAction({ commit, dispatch }, payload: any) {
const from: string = payload
window.location.href = getMixinUrl(from)
},
Through this code, the page can be jumped to a third party, then how can I judge that the authentication is successful? And how to request data gracefully when the judgment is successful.

How to secure an endpoint

I have an endpoint written in expressjs
router.post("/mkBet", async (req, res) => {
console.log(req.body)
const betToPush = new Bet({
addr: req.body.address,
betAmount: req.body.amount,
outcome: req.body.didWin,
timePlaced: Math.round(+new Date()/1000)
})
try {
const newBet = await betToPush.save()
res.status(201).json(newBet)
} catch(err) {
res.status(400).json({message: err.message})
}})
And I am trying to make it so that it can only be called when an action is performed on the frontend. So users cannot call it with custom arguments to make it so the outcome is always true. What would be the best way to achieve this?
It is not possible to securely tell what client sent the request. In other words, a request from your client and a different one can be identical in general.
Talking about unmodified browsers (as opposed to non-browser tools like Postman), you can tell the origin of the request (~the url loaded in the browser when the request was sent) with some confidence from the Origin and Referer request headers. However, your backend needs authentication and authorization anyway.
With the latter two in place, ie. with proper security implemented on the server-side, it doesn't matter anymore what client sends the requests.

How to get data from an API of the same origin?

I have a route (/user/{id}) that returns user information in json format. I want to display some user info on my index(/) page. So, in my handler for the index(/), I have
const host ="https//www.example.com"
const url = host + "/user/1"
const response = await fetch(url, init)
But, the thing is that it hangs and times out. I guess it is because, it is still serving the request for the index page, which is also making another request to /user/{id}. So, the second request doesn't seem to be served as the handler is occupied by the first request in my opinion.
Is there a way to fix this?
Thank you

Add custom session data to jsoup POST request in clojure

I am testing my first clojure ring application with midje and jsoup.
The app uses ring-session to add session for logged-only pages.
Session is not a cookie, neither part of the header of the request and I dont know how to add it to perform a post request correctly on logged pages...
A POST request in jsoup is something like:
(-> (Jsoup/connect "http://localhost:3001/sendto")
(.userAgent "...")
(.header "Content-Type","application/x-www-form-urlencoded")
(.data "amount" amount)
(.data "to" email)
(.data "sendto-submit" "Send")
(.post))
Altough this will not work when trying to perform a request against a logged-only url.
I'd have to add the session object, that in my case is something like:
{:session {:auth {:email "name#email.com"}}}
to the request, but so far neither (.cookie) nor (.data) worked...
Any help is suuuuper welcome :)
Without knowing the server side config, it's hard to give exact advice, but you have to remember the cookie you get on login and send it with the requests.
What you see on the server as {:session {:auth ,,,}} is the result of the session wrapper loading server side stored data into the request.
So basically:
you send a request, that starts a session (e.g. your login)
the server sends you a cookie back and stores informations about the login in it's session storage
you send a request, that includes that cookie
the server looks the cookie up in the session storage and injects the data associated with it in the request.
See the source/doc

What method should I use for a login (authentication) request?

I would like to know which http method I should use when doing a login request, and why? Since this request creates an object (a user session) on the server, I think it should be POST, what do you think? But since the login request should be idempotent, it could be PUT, couldn't it?
Same question for a logout request, should I use the DELETE method?
If your login request is via a user supplying a username and password then a POST is preferable, as details will be sent in the HTTP messages body rather than the URL. Although it will still be sent plain text, unless you're encrypting via https.
The HTTP DELETE method is a request to delete something on the server. I don't think that DELETING an in memory user session is really what it's intended; more it's for deleting the user record itself. So potentially logout can be just a GET e.g. www.yoursite.com/logout.
I believe that you can translate LOGIN & LOGOUT methods into basic CRUD operations CREATE & DELETE. Since you are creating a new resource called SESSION and destroying it when logging out:
POST /login - creates session
DELETE /logout - destroys session
I would never do LOGOUT as GET just because anyone could make an attack just simply by sending an email with IMG tag or link to website where such an IMG tag exists. (<img src="youtsite.com/logout" />)
P.S.
Long time I was wondering how would you create a RESTful login/logout and it turned out it's really simple, you do it just like I described: use /session/ endpoint with CREATE and DELETE methods and you are fine. You could also use UPDATE if you want to update session in one way or another...
Here is my solution based on REST guides and recommendations:
LOGIN - create a resource
Request:
POST => https://example.com/sessions/
BODY => {'login': 'login#example.com', 'password': '123456'}
Response:
http status code 201 (Created)
{'token': '761b69db-ace4-49cd-84cb-4550be231e8f'}
LOGOUT - delete a resource
Request:
DELETE => https://example.com/sessions/761b69db-ace4-49cd-84cb-4550be231e8f/
Response:
http status code 204 (No Content)
For login request we should use POST method. Because our login data is secure which needs security. When use POST method the data is sent to server in a bundle. But in GET method data is sent to the server followed by the url like append with url request which will be seen to everyone.
So For secure authentication and authorization process we should use POST method.
I hope this solution will help you.
Thanks
Regarding the method for logging out:
In the Spring (Java Framework) documentation, they state that a POST request is preferred, since a GET makes you vulnerable to CSRF (Cross-Site Request Forgery) and the user could be logged out.
Adding CSRF will update the LogoutFilter to only use HTTP POST. This ensures that log out requires a CSRF token and that a malicious user cannot forcibly log out your users.
See: https://docs.spring.io/spring-security/site/docs/current/reference/html/web-app-security.html#csrf-logout
Logging in should also use POST (body can be encrypted, see the other answers).
For Login I use POST, below is my code for LOGIN method
I used Nodejs with Express and Mongoose
your router.js
const express = require("express");
const router = express.Router();
router.post("/login", login);
your controller.js
export.login = async(req, res) => {
//find the user based on email
const {email, password} = req.body;
try{
const user = awaitUser.findOne({email});
if(user==null)
return res.status(400).json({err : "User with
email doesnot exists.Please signup"});
}
catch(error){
return res.status(500).json({err :
error.message});
}
//IF EVERYTHING GOES FINE, ASSIGN YOUR TOKEN
make sure you have JWT installed
const token = jwt.sign({_id: user._id}, YOUR_SECRET_KEY);
res.cookie('t');
const {_id, name, email} = user;
return res.json({token, user : {_id, email, name}});
}