Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it safe to use react js state to store token of authenticated user?

I am implementing a simple user authentication system using react js and node js api. This is what i am doing inside ComponentWillMount method :-

1.checking if the token exits (in localStorage)
2.if it doesn't exits then the value of state 'token' will stay blank
3.if it exists then checking if it's valid using an request to backend.
4.If the token is valid then state 'token' as localstorage.token
5.If the token is invalid then the value of state 'token' will stay blank

inside render method i have added conditional rendering based on the value of state 'token' i.e. if the state 'token' is blank then normal page will be rendered else it will be redirected to user's page.

The problem is i can change the value of state 'token' using any react developer tool. And that is causing a loophole to login using a fake token.To avoid that i have to check for the validity of state 'token' everytime it is changed using one of the life cycle methods like componentDidUpdate shouldComponentUpdate . But as mentioned in the official documentation of react

shouldComponentUpdate only exists as a performance optimization. Do not rely on it to “prevent” a rendering, as this can lead to bugs.

Using componentDidUpdate isn't useful as it will be called after component will already be changed due to state change.

Using componentWillUpdate is mentioned as Unsafe in the official documentation

I am not sure how can i tackle this loophole. Here is the code for the component

import React,{Component} from 'react';
import {
    BrowserRouter as Router,
    Route,
    Link,
    Switch,
    Redirect
} from 'react-router-dom';

import Home from './Home';
import Nav from './Nav';
import Login from './Login';
import Signup from './Signup';

class Out extends Component{
    constructor(){
        super();        

        this.state = {
            token : '',
            isLoading:false            
        }
        this.isLoading = this.isLoading.bind(this);
    }

    logout(){
        alert('logged out');
    }

    componentWillMount(){
        let {match} = this.props;
        this.navNoSessionRouteData = [
            {to:`${match.url}login`,name:'Login',key:'r1'},
            {to:`${match.url}signup`,name:'signup',key:'r2'},
            {to:`${match.url}`,name:'Home',key:'r3'}
        ];

        this.navNoSessionButtonData = [];

        this.setState({
            isLoading:true
        });

        const tokenVar = localStorage.getItem('token');
        if(tokenVar == null){
            console.log('not logged in');
            this.setState({
                isLoading:false
            });
        }else{            
            fetch('http://localhost:3000/api/account/verify?token='+tokenVar)
            .then(res=>res.json())
            .then(json=>{
                if(json.success){
                    console.log('logged in');
                    this.setState({
                        token : tokenVar,
                        isLoading:false
                    });
                }else{
                    this.setState({                 
                        isLoading:false,
                    });
                }
            });
        }
    }

    isLoading(){
        let {isLoading,token} = this.state;
        if(isLoading === true){
            return (
                <p>Loading...</p>
            );
        }
        else{
            let {match} = this.props
            console.log(token);
            return(
                <div>
                    {
                        (token)?<p>Logged In</p>:(<p>NOT logged IN</p>)
                    }
                    <div className = "row">
                        <Nav navRouteData = {this.navNoSessionRouteData}  navButtonData = {this.navNoSessionButtonData}/>
                    </div>
                        <div className="row justify-content-center">
                            <Switch>
                                <Route exact = {true} path={`${match.path}`} component={Home} />
                                <Route path={`${match.path}login`} component={Login}/>
                                <Route path={`${match.path}signup`} component={Signup}/>
                            </Switch>
                        </div>
                </div>
            )
        }
    }


    render(){    
        return(
            <div>
                {this.isLoading()}
            </div>
        )
    }
}

export default Out;

image is showing logged in user using real tokenimage is showing logged out user with blank tokenimage is showing logged in user with fake token

like image 333
Vaibhav Verma Avatar asked Oct 08 '18 09:10

Vaibhav Verma


1 Answers

Just to loop in here, I would answer this in two questions:

(I think closer to your question): If I can edit React state variables, how is anything I display secure?

The point here is they CAN navigate to UI that requires them to be signed in, but when they actually go to request data (either to your backend, or directly to your database like Firebase) then they will need a valid token to do so. Your backend should be checking for this, and won't return any valuable data.

If I can read React state variables, how safe is my token from being stolen and used by someone else to request and write data?

For this, see this answer

like image 180
Nth.gol Avatar answered Sep 29 '22 06:09

Nth.gol