How to security save Facebook response token to React app? - reactjs

I'm developing an React app using facebook login, after login success, facbook return a list of pages that user current manager, includes tokens. These tokens I will use in future in my app. This is response I want to save:
[
{
// page 1
access_token: "this_is_token",
category: "Community",
id: "461787374317076",
name: "page_name",
......
},
{
// page 2
},
....// other pages
]
But I don't know how to save this response in my app for security. which is best secure to save? Redux state (not secure), Redux store? Cookies? localstorage? or inmemory?
In my app, I'll use these tokens many times, so I think should dispatch them to Redux store, but does it secure?
Thanks you very much!

Token that you receive do not have password inside. You are saying if you can store it any where?
The website we are on now (stackoverflow) also store that token in local-storage
You can see in this pic they are storing token in localstorage.
is it safe ?
Yes as it do not have any important data like password or credit card number. More over if you as user have this token on your computer then you will not give this string to some other people to access your account (it is like you are giving somebody your password which is not developers fault) and this string is too large that no other can create acceptable string by own.
redux / cookies / localstorage ?
The way I use it is . On signIn/signUp I will set it in localstorage and request headers and after refresh i will check first if token is present in localstorage or not if yes then will need to set headers again as on refresh they will lost.
By axios you can easily set headers like this. Then on server you need to get headers from request and verify your token.
import axios from 'axios'
export default function setAuthToken(token){
if(token){
axios.defaults.headers.common['autherization'] = `Bearer ${token}`
}
else{
delete axios.defaults.headers.common['autherization']
}
}

Related

Log out from all tabs/devices using React, JWT and cookie

I'm using React on frontend and Node on backend. How I structure the authentication is, when a user logs in, a JWT token is created and stored into the user data model. That token then get stored into cookie (instead of Localstorage).
Localstorage, on the other hand, is used to store user info such as username, name, and email.
When a user logs out, the JWT token is removed, and so is the cookie and userinfo in Localstorage. I designed my React so that if there's no userinfo in Localstorage, then the private routes would become inaccessible to users.
When a user logs out from all devices, all JWT tokens are removed (but cookie and Localstorage on other devices are not, since they are local).
However, this approach results in some problems:
since removing all JWT tokens doesn't remove the userinfo from Localstorage, the private routes can still be viewed, which is undesirable
after all JWT tokens are removed, even if a user wants to log out from another device, they can't, because now without any token, the user can't pass the authentication.
What would be a better way to structure the logOutAll component?
In order to logout the user if there isn't any JWT available, using Axios interceptor you can catch the response error and status. So in your case the API will response with status code 401 or any other status code you're sending. If the API fails with 401 status you could add your logout logic.
Here's the code snippet using Axios interceptor, hope this helps.
axios.interceptors.response.use(
(response) => response,
(error) => {
const { status } = error.response;
if (status === 401) {
// your logout logic goes here
}
return Promise.reject(error);
}
);

Where to store token from auth header in React

I am currently working on a medium scale app and am a month into learning React. I got to the part where I need to authenticate users. I have written some code and It is working, but I don't know is it secure enough. When my users login, they are assigned with a JWT token like this:
await axios.post(APIbase + '/login', {
username: username, password: password
}).then(res=>{
const token = res.data.token;
localStorage.setItem('token', token);
}).catch(err => {
console.log(err);
});
And then, when the user makes a request to a server it send the token by an auth header like this:
const token = localStorage.getItem('token');
const headers = { Authorization: `Bearer ${token}`};
const detailResult= await axios.get(API.base + API.details, {
headers:headers});
Is this safe enough? I heard that this is a not really a good practice, but I am not sure what exactly should I do.
Local storage is generally used for this kind of token, but keep in mind any JS on the page can access local storage. If you have any 3rd party code, it can get to the token by simply reading the local storage.
If you want a bit more secure way of storing it, you can use HTTPonly, secure cookie. That way it will not be accessible by JS and it will also be sent automatically in any request to the API, but it requires changes on the server to implement cookies instead of Authorization header.
You can also use a BFF (backend for frontend) approach with a server handling session then you don't need to store the token on the client side either (and only store in on BFF linked to the session), but keep using it for requests to the API from the BFF.
Security is a complex field and has a lot of trade-offs. There is no one correct answer for every use case.
This does really belong to react domain but is a more beta question and there is a special stack exchange for this: https://security.stackexchange.com/

JWT retrieve for every request or save in redux (or equivalent) store

I am writing a react app and using localStorage (for now) to store a JWT.
My question is is it better to retrieve the token on page load from localStorage and set in the redux store? or should I retrieve it from localStorage on every request.
i.e.
const App = () => {
useEffect(() => {
const token = localStorage.getItem('token')
dispatch(setTokenInStore(token))
})
}
Then in each request pull token in from the store and then use it in the requests.
Or the other option is to retrieve the token from localStorage on every request:
fetchA = () => {
const token = localStorage.getItem('token')
fetch(url, token)
}
fetchB = () => {
const token = localStorage.getItem('token')
fetch(url, token)
}
If one is better than the other would it be possible to give reasons. If anything is unclear please let me know.
Generally speaking about the redux store vs localStorage is that they are meant for different purposes. If you need to share state in your app then you go with redux. If you need to persist data in your browser cache then localStorage is the way.
Regarding where to put an jwt-token is a debate iself. The jwts are design to be short lived and IF an external user somehow would get a hold of the token they have a limited time to use it. If its not stored in the localStorage, the user would need to login if they refresh the browser. That would not make a good experience for the end user.
But, If you need authentication in your app you should not reinvent the wheel.
Most jwt-providers can be used with the OpenID Connect layer and there is a lot of docs regarding that topic. For your react app I would there for go with the react-oidc-client. The client uses its own store (WebStorageStateStore) which can be set to localStorage.
If you store tokens in local storage, then it's easily accessible by any XSS attack and any external user can get the token by a script inside your page. You can save JWT token in redux, but mostly redux is used if you want to share the states across the app.
But the general answer to your question would be : try to follow best practices of jwt tokens and security. One main point of security would be setting expiry of your tokens.
There are several blogs which suggest to store tokens in cookies and they are super secure. You can read here.

Misunderstanding the process of JWT authentication

I create project using React + Redux + Apollo Client + Graphql
When we need to log in in our app we need to use token (saved in localStorage for example) which is put in the headers parameter like in the code below:
const client = new ApolloClient ({
uri: 'http://localhost:4000/api',
headers: {
authorization: `Bearer ${localStorage.token}`,
},
});
After request server verifies token and becomes aware who is the user.
My question: from where do we need to get token and put it to the headers parameter for log on (sign up) process? A new customer comes to our log on page, he has no token (in localStorage or somewhere else) at the beginning but server requires it in the requests. And if we remove headers parameter from our client, the log on process will proceed but server won't understand who is the current user.
Typically the server would be the one issuing the JWT token, and this would happen during user login or maybe during account creation. For these particular calls, you should not be expecting the JWT in the header. Instead, the user would be passing credentials, such as username and password. For most other calls, it is appropriate to pass the JWT in the header of the request.
Keep in mind that the main purpose of the JWT is free the user from having to provide personal credentials during most requests. Instead, the user can just present a JWT, much as one would present a passport, to get access to your web services.
In response to your comments below, I would suggest that you keep the signup/registration process separate from the user-only area of your application. Here is a typical workflow:
Prospective user visits your site, and creates an account, by choosing a username and password, and possibly by providing certain other personal information
Your application creates an account, and then sends an email verification link to the user's email address. The server lands the user on a page which mentions all of this
The user opens the email, which contains a verification link, which when clicked will activate the account. Your application returns a web page which then asks the user to login.
Finally, the user logs in from the normal login page.
Note carefully here, that JWT were not at all involved in the signup process, nor do they need to be. The user JWT only needs to come into existence after the user actually logs in for the first time.
Decision:
you need to check for token in localStorage and update the request if token exists
const client = new ApolloClient({
uri: 'http://localhost:4000/api',
request (operation) {
const headers = {};
const token = localStorage.getItem('token');
if (token) headers.authorization = 'Bearer ' + token;
operation.setContext({ headers });
}
})

What is the best practice to use Oauth2, React, Node.js and Passport.js to authenticate user with Google sign on button?

I want to have a login button in my website so when a user clicks on it, the user can use their Google credentials. I'd like to ideally perform the authentication server side using Express.js and Passport.js.
I implemented authentication server-side but the problem is that I can't make an AJAX request from the website to the server to start authentication because Google or Oauth don't support CORS. So I need to use a href element in my website which would call the server authentication endpoint. However, I can't catch server response in this way.
If I perform the authentication client-side (I'm using React) I could store login state in Redux and allow the user to access the website's resources. However, when the user logs out I need to make sure that server endpoints stop serving the same user which feels like implementing authentication twice: client-side and server-side.
In addition when authenticating client-side, Google opens a popup for the user to authenticate which I think is worse user experience then just a redirect when authenticating server-side.
I'm wondering what the best practice in terms of authenticating using Oauth2/Google. For example, stackoverflow.com also has Google button but just makes a redirect, without any popup, so I guess they figured out a way to perform server-side authentication and to bypass CORS issue.
I faced the same issue. This article is Gold link
1.In auth route File I had following code
const CLIENT_HOME_PAGE_URL = "http://localhost:3000";
// GET /auth/google
// called to authenticate using Google-oauth2.0
router.get('/google', passport.authenticate('google',{scope : ['email','profile']}));
// GET /auth/google/callback
// Callback route (same as from google console)
router.get(
'/google/callback',
passport.authenticate("google", {
successRedirect: CLIENT_HOME_PAGE_URL,
failureRedirect: "/auth/login/failed"
}));
// GET /auth/google/callback
// Rest Point for React to call for user object From google APi
router.get('/login/success', (req,res)=>{
if (req.user) {
res.json({
message : "User Authenticated",
user : req.user
})
}
else res.status(400).json({
message : "User Not Authenticated",
user : null
})
});
2.On React Side After when user click on button which call the above /auth/google api
loginWithGoogle = (ev) => {
ev.preventDefault();
window.open("http://localhost:5000/auth/google", "_self");
}
3.This will redirect to Google authentication screen and redirect to /auth/google/callback which again redirect to react app home page CLIENT_HOME_PAGE_URL
4.On home page call rest end point for user object
(async () => {
const request = await fetch("http://localhost:5000/auth/login/success", {
method: "GET",
credentials: "include",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"Access-Control-Allow-Credentials": true,
},
});
const res = await request.json();
//In my case I stored user object in redux store
if(request.status == 200){
//Set User in Store
store.dispatch({
type: LOGIN_USER,
payload : {
user : res.user
}
});
}
})();
5.last thing add cors package and following code in server.js/index.js in node module
// Cors
app.use(
cors({
origin: "http://localhost:3000", // allow to server to accept request from different origin
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
credentials: true // allow session cookie from browser to pass through
})
);
Your authentication should be done server side. Here is how it works.
You make a fetch or axios call to your authentication route.
Your authentication route sends a request to Google's Authentication servers. This is important to have on the backend because you will need to provide your clientSecret. If you were to store this on the frontend, it would make it really easy for someone to find that value and compromise your website.
Google authenticates the user and then sends you a set of tokens to your callback url to use for that user (refresh, auth, etc...). Then you would use the auth token for any additional authorization until it expires.
Once that expires, you would use the refresh token to get a new authorization token for that client. That is a whole other process though.
Here is an example of what that looks like with Passport.js: https://github.com/jaredhanson/passport-google-oauth2
EDIT #1:
Here is an example with comments of the process in use with Facebook, which is the same OAuth codebase:
https://github.com/passport/express-4.x-facebook-example/blob/master/server.js
Redux can really help with achieving this and this follows the same logic as Nick B already explained...
You set up oauth on the server side and provide an endpoint that makes that call
You set up the button on you react frontend and wire that through an action to the endpoint you already setup
The endpoint supplies a token back which you can dispatch via a reducer to the central redux store.
That token can now be used to set a user to authenticated
There you have it.

Resources