how i validate if the user has a token in localStorage - javascript

My app calls a Login api and returns me a token,i stored the token in localStorage so my problem is how i validade if the user has a token to do the login. what can i do to do that?
this is my login Page where i used to add the token to the localStorage
import React, { useState, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { login } from '../services/login.services';
function Login() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const history = useHistory();
const loginHandler = async () => {
const result = await login(email, password);
console.log(result);
localStorage.setItem('token', result?.response?.result?.token);
localStorage.getItem('token');
};
return (
<section className='layout'>
<div className='wrp-login'>
<div className='container'>
<h1 color='white'>Login Page</h1>
<div className='col-sm-6 offset-sm-3'>
<input
type='text'
placeholder='email'
onChange={(e) => setEmail(e.target.value)}
className='input-wrapper'
/>
<br />
<input
type='password'
placeholder='password'
onChange={(e) => setPassword(e.target.value)}
className='input-wrapper'
/>
<br />
<button onClick={() => loginHandler()} className='button'>
Login
</button>
</div>
</div>
</div>
</section>
);}export default Login;
this is my Login Service wher i do the api call and return data
export const login = async (email, password) => {
try {
const result = await fetch(
'teste.com',
{
method: 'Post',
body: JSON.stringify({ login: email, senha: password }),
headers: {
'Content-Type': 'application/json',
},
mode: 'cors',
cache: 'default',
},
);
return await result.json();
} catch (err) {
return err;
}};
Someone could help me?

You can validate and redirect users by creating a wrapper for protected routes with react-router-dom to the login page if they don't have the token stored this way:
const ProtectedRoute = (props) => {
const token = localStorage.getItem('token');
if (token == null) {
return <Redirect to={Routes.LOGIN} />;
}
return <>{props.children}</>;
};

Related

xhr.js:220 POST http://localhost:3000/EShop/register 400 (Bad Request)

Trying to POST request to send data to database but it always shows 400 bad request.
The AuthReducer file is as follow. Data is not getting posted when done in Frontend but its properly working when tested in postman api.
export const Register = (username, email , password) => async(disptach) => {
try{
disptach({type:REGISTER_USER_REQUEST})
const config = {
Headers:{
'Content-Type':'application/json'
}
}
const { data } = await axios.post('/EShop/register', {username ,email , password} , config)
disptach({
type:REGISTER_USER_SUCCESS,
payload:data.user
})
}catch(error){
disptach({
type:REGISTER_USER_FAIL,
payload : error.response.data.message
})
}
}
The register form is as follow..
import React, { useState, useEffect } from "react";
import { Link, useNavigate } from "react-router-dom"
import { useSelector, useDispatch } from "react-redux"
import Loader from "./loader";
import { Register } from "../actions/UserAction";
import "../css-files/Account.css"
export default function register() {
const [email, setemail] = useState('');
const [password, setpassword] = useState('');
const [username, setusername] = useState('');
const disptach = useDispatch();
const navigate = useNavigate();
const { isAuthenticated, error, loading } = useSelector(state => state.user)
useEffect(() => {
if (isAuthenticated) {
navigate('/account/login')
}
}, [disptach, isAuthenticated])
const SubmitRegisterHandler = (e) => {
e.preventDefault()
disptach(Register(username, email, password))
}
return (
<div id="Account_container">
{loading ?
<Loader />
:
<div id="wrapper">
<div id="Wrap_First">
<img src="https://res.cloudinary.com/dqxozrie1/image/upload/v1659935744/eshop/online-registration-sign-up_gfb2gs.webp" />
</div>
<div id="Wrap_Second">
<div id="login">
<h2>Create New Account</h2>
<form onSubmit={SubmitRegisterHandler}>
<input
required
type="text"
placeholder="Username"
value={username}
onChange={(e) => { setusername(e.target.value) }}
/>
<input
required
type="email"
placeholder="Email"
value={email}
onChange={(e) => { setemail(e.target.value) }}
/>
<input
required
type="password"
placeholder="Password"
value={password}
onChange={(e) => { setpassword(e.target.value) }}
/>
<button>Register</button>
</form>
<p id="existing_acc"><Link to="/account/login">Already have an account !</Link></p>
</div>
</div>
</div>
}
</div>
);
}
It gives 400 bad request always. Please help me how to resolve this issue.

Checking if a user is logged in to use features on other pages

I have connected to an API to make users log in if they have an account. However, I have other pages which I want them to be logged in in order to use. How would I check to make sure a certain user is logged in to use certain features? Is there any source someone can guide me to? Any help would be appreciated.
Thanks,
import React, { useState, useEffect } from "react";
import ForgotPassword from "./ForgotPassword";
import TermsOfService from "./TermsOfService";
import axios from "axios";
function Login() {
const [user, setUser] = useState("");
const [userName, setUserName] = useState("");
const [password, setPassword] = useState("");
function handleLogin() {
var config = {
method: "post",
url: "http://localhost:8080/api/account/login",
data: {
username: userName,
password: password,
},
};
axios(config)
.then(function (response) {
setUser(response.data);
localStorage.setItem("user", JSON.stringify(response.data));
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});
}
return (
<>
<Navbar />
<div className="login_form">
<input
className="form_input"
type="text"
placeholder="Username or Email"
onChange={(e) => setUserName(e.target.value)}
/>
<input
className="form_input"
type="password"
placeholder="Password"
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit" onClick={handleLogin} className="Signup_button">
Login
</button>
</div>
</>
);
}
export default Login;

After changing UseState Hook React component not re-rendering

I am new at React and i am trying to develop a login page. I did almost all but I could not re-render after successful login. I need to refresh the page to see the protected content. As far as I know, using custom Hook and changing its value should trigger a component re-render but although I change the value of it (token), page is not re-rendered. What is the point i missed?
//App.js
function App() {
const { token, setToken } = useToken();
if(!token) {
return <Login setToken={setToken} />
}
return (
<div className="wrapper">
<h1>Application</h1>
<BrowserRouter>
<Routes>
<Route path="/" element={<Dashboard />} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
//UseToken.js
export default function useToken() {
const getToken = () => {
const tokenString = localStorage.getItem('token');
const userToken = JSON.parse(tokenString);
return userToken;
};
const [token, setToken] = useState(getToken());
const saveToken = userToken => {
localStorage.setItem('token', JSON.stringify(userToken));
setToken(userToken.token);
};
return {
setToken: saveToken,
token
}
}
//Login.js
async function loginUser(credentials) {
return fetch('http://localhost:8080/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(credentials)
}).then(data => data.json())
.then(response => response.token)
}
export default function Login({ setToken }) {
const [username, setUserName] = useState();
const [password, setPassword] = useState();
const handleSubmit = async e => {
e.preventDefault();
const token = await loginUser({
username,
password
});
setToken(token);
}
return(
<div className="login-wrapper">
<h1>Please Log In</h1>
<form onSubmit={handleSubmit}>
<label>
<p>Username</p>
<input type="text" onChange={e => setUserName(e.target.value)}/>
</label>
<label>
<p>Password</p>
<input type="password" onChange={e => setPassword(e.target.value)}/>
</label>
<div>
<button type="submit">Submit</button>
</div>
</form>
</div>
)
}
Login.propTypes = {
setToken: PropTypes.func.isRequired
}
//Dashboard.js
export default function Dashboard() {
const logout = () => {
localStorage.clear();
}
return(
<div>
<h2>Dashboard</h2>
<button type="button" onClick={logout}>Logout</button>
</div>
);
}
In useToken.js
const saveToken = userToken => {
localStorage.setItem('token', JSON.stringify(userToken));
setToken(userToken.token);
}
should be replaced to
const saveToken = userToken => {
localStorage.setItem('token', JSON.stringify(userToken));
setToken(userToken); //userToken.token changed to userToken
}
Because, there is no variable named as 'token' in userToken object. It is token itself. So the hook thinks that there is no change and because of that it does not re-render.

Cannot read properties of null (reading 'user')

I have been trying to solve this issue wherein, I can grab the accessToken after login only? I have been stuck on this
The main problem is, the Token is already looking for it on localstorage, but I'm not even logged in yet. How can I make the user to login first before looking to the local storage
requestMethod.js
import axios from 'axios'
const BASE_URL = 'http://localhost:5000/api'
const TOKEN = JSON.parse(JSON.parse(localStorage.getItem('persist:root')).user)
.currentUser.accessToken
export const publicRequest = axios.create({
baseURL: BASE_URL,
})
export const userRequest = axios.create({
baseURL: BASE_URL,
headers: { token: `Bearer ${TOKEN}` },
})
Login.jsx
import { useEffect } from "react"
import { useState } from "react"
import { useDispatch } from "react-redux"
import { useHistory } from "react-router"
import { login } from "../../redux/apiCalls"
import { userRequest } from "../../requestMethod"
const Login = () => {
let history = useHistory()
const [username, setUsername] = useState("")
const [password, setPassword] = useState("")
const dispatch = useDispatch()
const handleClick = (e) =>{
e.preventDefault()
login(dispatch,{username,password})
history.push('/home')
}
useEffect(() =>{
try {
} catch (error) {
}
},[])
return (
<div style={{display: 'flex', alignItems:"center", justifyContent:"center", height: '100vh', flexDirection: "column"}}>
<form action="">
<input style={{padding: 10, marginBottom:20}} value={username} type="text" placeholder="username" onChange={e => setUsername(e.target.value)} />
<input style={{padding: 10, marginBottom:20}} value={password} type="password" placeholder="password" onChange={e => setPassword(e.target.value)} />
<button style={{padding: 10, width: 100}} onClick={handleClick}>Login</button>
</form>
</div>
)
}
export default Login
apicalls.js
import { loginFailure, loginStart, loginSuccess } from './userRedux'
export const login = async (dispatch, user) => {
dispatch(loginStart())
try {
const res = await publicRequest.post('/auth/login', user)
const TOKEN = JSON.parse(
JSON.parse(localStorage.getItem('persist:root')).user
).currentUser.accessToken
dispatch(loginSuccess(res.data))
} catch (error) {
dispatch(loginFailure())
}
}
You have to lookup on localstorage first.
Just check if localstorage contains token or not. If not, render some message and redirect user to login page.
Use optional chaining(?.):
const TOKEN = JSON.parse(JSON.parse(localStorage.getItem('persist:root'))?.user)
?.currentUser?.accessToken;

Async/await not working with react js(hooks)

I am trying to create a react application in which I am using react hooks.
In login form when the user submits the form email and password are passed to handleClick function.
That function fetches the data from the server and displays on client side but the response is always undefined and being called before return from service.
Here is the code...
Login.js
import React, { useState, useEffect } from 'react';
import { Button, Form, Container, Row, Col } from 'react-bootstrap';
import './login.css'
import * as services from '../services'
function Login() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleClick = async(e) => {
e.preventDefault();
console.log(email, password);
let res = await services.login(email, password);
console.log(res);
}
return (
<Container>
<Row className="justify-content-md-center ">
<header><h2>Rao infotech workspace</h2></header>
</Row>
<Row className="justify-content-md-center form">
<Col md="auto">
<Form onSubmit={handleClick}>
<Form.Group controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email" placeholder="Enter email" onChange={(e) => setEmail(e.target.value)} />
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password" placeholder="Password" onChange={(e) => setPassword(e.target.value)} />
</Form.Group>
<Button variant="primary" type="submit" >
Submit
</Button>
</Form>
</Col>
</Row>
</Container>
);
}
export default Login;
services.js
import axios from "axios";
const baseUrl = "http://localhost:4000/";
export function login(email, password) {
var body = {email: email, password: password}
axios.post(baseUrl + 'user/login', body)
.then((res)=>{
console.log("res in service", res);
return res;
})
}
I tried using useEffect but coudn't get how to call function inside useEffect()
You need to return your loginfunction:
export async function login(email, password) {
var body = {email: email, password: password}
return axios.post(baseUrl + 'user/login', body)
.then((res)=>{
console.log("res in service", res);
return res;
})
}
Or simply:
export async function login(email, password) {
var body = {email: email, password: password}
return axios.post(baseUrl + 'user/login', body);
}
import axios from "axios";
const baseUrl = "http://localhost:4000/";
export function login(email, password) {
var body = {email: email, password: password}
return new Promise((resolve, reject) => {
axios.post(baseUrl + 'user/login', body)
.then((res)=>{
console.log("res in service", res);
return resolve(res);
});
})
}
Just create the promise in service your async/await will start working.
Your service.js login function is not returning a promise so you cannot await its result

Categories