I am trying to build a React frontend app to fetch data from a backend Express server with PassportJS. I have tried using Postman to login and verify that the session is being stored in the server side until I logout. It works.
Then I tried to do the same stuff on my React app but when I get the user information (successful login) all the further fetchs are being rejected (403) according to a "rule" I set up on the server side.
export const checkSession = (req, res, next) => {
if (req.path === '/api/auth/login' || req.path === '/api/auth/register') {
next();
return;
}
if (!req.user) {
res.status(403).json({ error: 'Access not allowed' });
return;
}
next();
};
Again, this works great with Postman.
This is my login form:
import React, { useState, useEffect, useRef, useContext } from 'react';
import { Redirect } from 'react-router-dom';
import { SERVER_URL } from '../../utils/config';
import axios from 'axios';
import {
Container,
Row,
Col,
Form,
Button
} from 'react-bootstrap';
import { NotificationManager } from 'react-notifications';
import { UserContext } from '../../context/UserContext';
export default () => {
const userContext = useContext(UserContext);
const emailRef = useRef('');
const passwordRef = useRef('');
const [rememberMe, setRememberMe] = useState(false);
const [redirect, setRedirect] = useState(false);
useEffect(() => {
if (localStorage.getItem('auth')) {
setRedirect(true);
}
}, [localStorage]);
const handleSubmit = async e => {
e.preventDefault();
const data = {
email: emailRef.current.value,
password: passwordRef.current.value,
rememberMe
};
try {
const response = await axios(SERVER_URL + 'auth/login', {
method: 'POST',
data
});
const fetchData = await response.data;
if (fetchData) {
localStorage.setItem('auth', JSON.stringify(fetchData));
NotificationManager.success(`Welcome, ${fetchData.nombre || 'User'}`)
setRedirect(true);
}
} catch(err) {
NotificationManager.error('Wrong user name or password', 'Wrong credentials');
console.log('Login error:', err.message);
}
};
if (redirect) {
return <Redirect to="/" />
}
return (
<Container>
<Row>
<Col xl="4" lg="6" md="8" sm="10" className="mx-auto text-center form p-4">
<h1 className="title">Users Login</h1>
<Form method="POST" onSubmit={handleSubmit}>
<Form.Control required type="email" ref={emailRef} className="mt-2" placeholder="Email" />
<Form.Control required type="password" ref={passwordRef} className="mt-2" placeholder="Password" />
<Form.Group>
<Form.Check type="checkbox" value={rememberMe} onChange={() => {setRememberMe(!rememberMe)}} label="Remember me" />
</Form.Group>
<Button variant="primary" type="submit">Login</Button>
</Form>
</Col>
</Row>
</Container>
);
};
Regardless this does not work "really great"... I guess is not the point. I verified the React Developer Tools "Context Container" and it contains the user information inside userContext.auth
.
This is my router component:
...
export default () => {
const userContext = useContext(UserContext);
useEffect(() => {
if (localStorage.getItem('auth')) {
userContext.setAuth(JSON.parse(localStorage.getItem('auth')));
}
}, []);
useEffect(() => {
if (userContext.message) {
NotificationManager.success(userContext.message);
userContext.setMessage(null);
}
}, [userContext]);
axios.interceptors.request.use(
config => {
config.headers['Content-Type'] = 'application/json';
return config;
},
error => Promise.reject(error)
);
return (
<Router>
{userContext.auth && (
<div className="user">
<p>{userContext.auth.name} <Link to="/logout" className="btn btn-danger m-2">Log out</Link></p>
</div>
)}
<Switch>
<Route path="/login" exact>
<Login/>
</Route>
<PrivateRoute path="/" exact>
<Home/>
</PrivateRoute>
...
<Route path="*">
<Error404 />
</Route>
</Switch>
<NotificationContainer />
</Router>
);
};
This is an usual axios request to the server:
const totalUsers = async () => {
try {
const response = await axios(SERVER_URL + 'users/total');
const result = await response.data;
setTotalUsers(result.total);
} catch(err) {
NotificationManager.error('Server error while loading users. Check developer console to check them out', 'Server error');
console.log('Error while loading users:', err.message);
}
};
Should I send some headers to the server while fetching data? I didn't do that with Postman. Thanks in advance.