I am running a Django Rest backend with a React front-end.
JSON data during user registration is being pushed per normal. When users submit the register form, they are sent to a login page. I realize how annoying this is for the users, however I’m not so sure how automatically send the user to the logged-in version of the homepage.
I would like to accomplish this in the frontend (I have multiple ways to verify, thanks to social logins, so just seems easier to code this once in the front-end for all methods of registration)
register.js post
you can see below I push the user to /login
, however I just want to push them to /home
in an already verified and authorized state.
const handleSubmit = (e) => {
e.preventDefault();
console.log(formData);
axiosInstance
.post(`user/register/`, {
email: formData.email,
username: formData.username,
first_name: formData.first_name,
last_name: formData.last_name,
password: formData.password,
subscribed: formData.subscribed,
})
.then((res) => {
history.push('/login');
console.log(res);
console.log(res.data);
});
};
I have access_tokens
and refresh_tokens
generated by Django, which I can access thanks to my axios instances.
my main axios.js
import axios from 'axios';
const baseURL = 'http://127.0.0.1:8000/api/';
const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 5000,
headers: {
Authorization: 'Bearer ' + localStorage.getItem('access_token'),
'Content-Type': 'application/json',
accept: 'application/json',
},
});
axiosInstance.interceptors.response.use(
(response) => {
return response;
},
async function (error) {
const originalRequest = error.config;
if (typeof error.response === 'undefined') {
alert(
'A server/network error occurred. ' +
'Looks like CORS might be the problem. ' +
'Sorry about this - we will get it fixed shortly.'
);
return Promise.reject(error);
}
if (
error.response.status === 401 &&
originalRequest.url === baseURL + 'token/refresh/'
) {
window.location.href = '/login/';
return Promise.reject(error);
}
if (
error.response.data.code === 'token_not_valid' &&
error.response.status === 401 &&
error.response.statusText === 'Unauthorized'
) {
const refreshToken = localStorage.getItem('refresh_token');
if (refreshToken) {
const tokenParts = JSON.parse(atob(refreshToken.split('.')[1]));
// exp date in token is expressed in seconds, while now() returns milliseconds:
const now = Math.ceil(Date.now() / 1000);
console.log(tokenParts.exp);
if (tokenParts.exp > now) {
return axiosInstance
.post('/token/refresh/', {
refresh: refreshToken,
})
.then((response) => {
localStorage.setItem('access_token', response.data.access);
localStorage.setItem('refresh_token', response.data.refresh);
axiosInstance.defaults.headers['Authorization'] =
'JWT ' + response.data.access;
originalRequest.headers['Authorization'] =
'JWT ' + response.data.access;
return axiosInstance(originalRequest);
})
.catch((err) => {
console.log(err);
});
} else {
console.log('Refresh token is expired', tokenParts.exp, now);
window.location.href = '/login/';
}
} else {
console.log('Refresh token not available.');
window.location.href = '/login/';
}
}
// specific error handling done elsewhere
return Promise.reject(error);
}
);
export default axiosInstance;
I think I can copy some code from my login.js
file to get users tokens directly?
login.js
import React, { useState } from 'react';
import axiosInstance from '../../axios/Login';
import { useHistory } from 'react-router-dom';
import FbLogin from 'react-facebook-login';
import FacebookLogin from '../../axios/facebookLogin';
//MaterialUI
import Avatar from '@material-ui/core/Avatar';
import Button from '@material-ui/core/Button';
import CssBaseline from '@material-ui/core/CssBaseline';
import TextField from '@material-ui/core/TextField';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Checkbox from '@material-ui/core/Checkbox';
import Link from '@material-ui/core/Link';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import Container from '@material-ui/core/Container';
const useStyles = makeStyles((theme) => ({
paper: {
marginTop: theme.spacing(8),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(1),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));
export default function SignIn() {
const history = useHistory();
const initialFormData = Object.freeze({
email: '',
password: '',
});
const [formData, updateFormData] = useState(initialFormData);
const handleChange = (e) => {
updateFormData({
formData,
[e.target.name]: e.target.value.trim(),
});
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(formData);
axiosInstance
.post(`auth/token/`, {
grant_type: 'password',
username: formData.email,
password: formData.password,
client_id: 'xxx',
client_secret:
'xxx',
})
.then((res) => {
console.log(res);
localStorage.setItem('access_token', res.data.access_token);
localStorage.setItem('refresh_token', res.data.refresh_token);
history.push('/');
window.location.reload();
});
};
const responseFacebook = async (response) => {
FacebookLogin(response.accessToken);
};
const classes = useStyles();
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}></Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form className={classes.form} noValidate>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
autoFocus
onChange={handleChange}
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
onChange={handleChange}
/>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
onClick={handleSubmit}
>
Sign In
</Button>
<FbLogin
appId="719891865332276"
fields="name,email" //picture
callback={responseFacebook}
/>
<Grid container>
<Grid item xs>
<Link href="#" variant="body2">
Forgot password?
</Link>
</Grid>
<Grid item>
<Link href="#" variant="body2">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</form>
</div>
</Container>
);
}
Sorry if things seem a little obscure, I’m new to react, I appreciate any type of assistance.
Advertisement
Answer
First, You need to manage states of users (logged in or not). So you can use [Redux][1] for manage states of users.
Next thing is redirect users to /home page. React in default only support single page web applications. So you can’t use window.location.href
.You need to use [React-Router][2] for do that.
If you need example, see:: https://github.com/krypto-i9/fixbit/tree/main/src. (this repo use redux to manage user states and react-router for route between pages)
[1]: https://redux.js.org/introduction/getting-started
[2]: https://reactrouter.com/web/guides/quick-start