Save user in store compromise the security of my application? - reactjs

I'm using react with redux, and when the user logs in, I put the entire user object generated with the login in store. is it recommended to bring to the application any object user? const user = auth.signInWithEmailAndPassword(email,passwd)
export function* login(auth, action){
try{
const {email, password} = action.user
const user = yield auth.signInWithEmailAndPassword(email, passwd)
yield put(ActionCreator.signinSuccess(user))
}catch({message}){
yield put(ActionCreator.signinFailure("Dind't have possible do login"))
}
}
I use information like the token that comes in the user object to do authorization, the date of creation of the account and others .. so I keep all the object in the store of redux. Does this leave my system vulnerable?

Based on this answer (Is Redux secure?), is not a good idea to save sensitive data on the store.
If the data that you are saving will not compromise the application, it should be fine.
If not, then don't save on the store.

Related

Nextjs - How Do I Store A JWT in The Client's Browser That Can Persist A Browser Restart

I am making an app that involves creating a JWT that the client must "remember" for at least 24 hours. I know that sounds strange but this app I'm building involves something called "Litprotocol" which does decentralized authorization. When a user logs in/registers, a JWT is created by a series of 3rd party servers, and the resulting JWT is valid for 24 hours. Since this JWT involves a somewhat intricate process, for efficiencies sake, I don't want to create a new JWT every time the user tries to login. The app is written in Nextjs and I tried to use the following code to attempt creating a persistently stored variable name "storedVal."
export default function Home(props: any) {
...
...
...
const [storedVal, setStoredVal] = useState(String);
function storePersistence() {
setStoredVal('I set this');
}
function printPersistence() {
console.log(storedVal);
}
return (
<>
<VStack>
<Heading as='h3'>Connect to see unity app</Heading>
{
!connected ? <Button variant='solid' onClick={connect}>Connect</Button> : <Text>Now you can click on protected path link at the bottom</Text>
}<br></br>
<Button variant='solid' onClick={storePersistence}>Store Persistence</Button>
<Button variant='solid' onClick={printPersistence}>Check Persistence</Button>
</VStack>
</>
)
}
The "Store Persistence" and "Check Persistence" buttons and functions are the relevant code. This doesn't work. As soon as I restart my browser, "storedVal" is cleared. So how can I make "storedVal" persist browser and possibly computer restarts?
General Idea/Mechanism for persisting data via localStorage/sessionStorage in client side.
Store it in localStorage when JWT is sent to client.
When user closes the site and open again that time fetch JWT from localStorage and check if it's valid or not and do the needful. Refer Blog for localstorage.
You can set JWT as follows localStorage.setItem("jwt", value) and fetch it localStorage.getItem("jwt")
You can use hooks/function provided by library/framework as well it does work on similar idea.
Aside from #GodWin's comment, you could also use this hook which I love: useLocalStorage. There's many variants of it and you can certainly write your own. It basically loads in a localStorage value into a hook given a key, for which you can provide a default value.
You can use it just like a useState:
function Home() {
const key = "local-jwt"
const defaultValue = null
const [jwt, setJWT] = useLocalStorage(key, defaultValue)
// use your jwt somewhere
return (
...
)
}

Adding extra information to registration user Firebase

I would like to make an application in React Native that allows to work in two modes, parent and child. The initial stage is registration with Firebase, then after adding additional information about the role (parent / child), registering both the child and parent, and after logging in both of them, the child will share location and parent will receive it.
I would like to add additional fields such as role (parent / child) in my application in React Native + Firebase, to later create other functionalities of the application based on the role.
Registration:
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then(userCredentials => {
return userCredentials
.user.updateProfile({
displayName: name,
})
.additionalUserInfo.profile = {
role: role,
}
})
Homescreen
const { displayName } = firebase.auth().currentUser;
const { role } = firebase.additionalUserInfo.profile;
this.setState({displayName, role});
and role returns undefined.
The properties that you can store on a user profile are defined by Firebase Authentication. You can't just add additional properties to it as you see fit. At best Firebase will simply ignore those, but likely it will also explicitly reject them (throwing an error).
If you want to store additional information about a user, you have two main options:
Store the additional information as custom claims in the user's authentication token.
Store the additional information in an external database, such as the Firestore and Realtime Database that are part of Firebase.
While storing the data as custom claims is pretty close to what you want to accomplish, you'll need to keep a few things in mind:
Custom claims are used for authorization purposes, and for that reason can only be set from a trusted environment (such as your development machine, a server you control, or Cloud Functions). So you can't simply set the role from within the app, and will need a separate process to add that claim.
After setting a custom claim on a user profile it may take up to an hour before that change is visible in the client. If you need it sooner, you can force the user to sign in again, or refresh their ID token.
Custom claims are sent with every request you make to Firebase resources, and for that reason are very limited in size. There's a maximum size of 1000 bytes for custom claims for a user. While your current role will easily fit into that, it may limit what you can add later.
If instead you store user data in an external database, you'll typically combine it with other information about that user into a users node/collection. In here you'd store a document/node for each user based on that user's UID, and then their profile information.
So something like:
users: {
uidOfAleksandra: {
username: "Aleksandra",
displayName: "Aleksandra Lastname",
role: "parent",
registrationDate: "2020-02-01"
},
uidOfPuf: {
username: "puf",
displayName: "Frank van Puffelen",
role: "child",
registrationDate: "2015-03-07"
},
}
Having this list of user profiles does not only allow you to store the additional information for each user, but would also allow you to query that list of users from within your app, something that the Authentication API doesn't allow from within application code.

Create user profile with user choice on firestore using redirect

I am creating a site using react-redux-firebase, and when a user logs in with facebook I want to create a profile that stores a user choice. I know how to define what to store with the profileFactory, but I don't know how to pass dynamic data coming from the user. In my case I want to save the users' language. My configuration is similar to this:
const config = {
userProfile: 'users', // where profiles are stored in database
profileFactory: (userData, profileData) => { // how profiles are stored in database
const { user } = userData
return {
language: [i need to put here what the user chose]
email: user.email
}
}
}
The configuration was based on this recipe.
When logging in I'm using type redirect.
await firebase.login({
provider: 'facebook',
type: 'redirect'
})
How could I save the user choice when the user is created?
To solve the user custom fields I'm creating a user when the redirect comes back from facebook.
I'm still not totally sure this is the best way to do it. Seems odd that I can define a profileFactory but can't pass user custom fields in some way.

How to create custom URLs for new users using Firebase?

I have a React/Redux application that creates and saves new users under Firebase as /users/<uid>
However, I also want to have each user have a custom URL for their profile pages, like domain.com/users/john-david or domain.com/users/john-david-1343 (if the original /users/john-david is already taken.)
What's the best way to do this?
My problem is that I was going to store users under /users/<firstname-lastname-hash> in Firebase, but that seems like a bad idea to store them under anything besides uid (is this true?).
But also, if I don't do that, then how do I maintain /users/<uid> in Firebase, while creating new usernames that account for duplicates, and searching if the user exists when visiting domain.com/users/john-david-123
Here is some sample code of where the new user gets saved to Firebase
export function saveUser (data, user) {
let username = data.username
return ref.child(`users/${user.uid}/info`)
.set({
email: user.email,
firstname: data.firstName,
lastname: data.lastName,
admin: false,
// for /users/<username>
username: username,
uid: user.uid
})
.then(() => user)
}
In general we say you should store data in Firebase how you intend to view it, and there's no reason in particular that you must use the UID as your primary key when storing users. What you might want to is:
Store user data in /users/${username} as you mentioned, including a uid field.
When a user signs up, generate the firstname-lastname slug and store in /uids/${uid} = username.
This way you have a simple way to map from UID to user and vice-versa. The downside here is that once you bake a username into your data structure, you should probably never let them change their username.
Alternatively, you could reverse my suggestion and store /usernames/${username} = uid and /users/${uid}. This makes it easier to rename usernames, but requires that you do an extra lookup to go from username to data.

Firebase: How to get the $id of an object after I authenticate using angularFire

Firebase has the $onAuth method that listens for changes to the client's authentication state. If the client is authenticated, the callback will be passed an object that contains the uid.
Here is my question:
Based on this uid, how can I get the the $id for this object.
This is how my data looks like in firebase:
profile {
-K2a7k9GXodDriEZrM3f {
email: "ale#aol.com"
gravatar: "https://www.gravatar.com/avatar/1d52da55055f0c8..."
uid: "3f9e0d53-4e61-472c-8222-7fc9f663969e"
name: "ale"
}
}
I am using
auth.$onAuth(function (authData) {
if (authData) {
authData.profile = //here I want the $id of the object
}
})
All I see I can do with the authData response is to get the uid of the object by using:
$firebaseObject(ref.child('profile').child(authData.uid));
This authData does not contain the $id (i.e. the -K2a7k9GXodDriEZrM3f) of the object. And that is what I am looking for in order to have the user's information available. Is there a way to achieve this?
Thanks.
If an object has a natural unique ID, you should usually store the object under that ID. Using push IDs in those cases adds no value and only complicates things.
Most developers using Firebase do as the "Storing User Data" section in the documentation illustrates: they store users by their uid. If you follow that guideline, you can find the key as authData.uid.
If you decide to stick to your current course, you can find the key for the user with:
ref.child('profile').orderByChild('uid').equalTo(authData.uid).once('child_added', function(snapshot) {
console.log(snapshot.key());
});
But you will be making it harder for the database to find your user, thus limiting the scalability of your app.

Resources