React Js : Unable to login until page gets refresh manually - reactjs

As a beginner to the React Js I'm trying simple projects for hands-on experience and to learn as well! so, in the same way I've created one login portal with react js and WAMP server by watching YouTube tutorial
in the middle I went through some errors but somehow I managed and get them off but after completing the project when I'm trying to login with the credentials which I've given in database the response and all was clear but the page doesn't redirect to welcome page after clicking on login button instead it redirects to welcome page after refreshing manually. I couldn't identify the mistake in my code.
LoginForm.js
import React from 'react';
import InputField from './InputField';
import SubmitButton from './SubmitButton';
import UserStore from './stores/UserStore';
class LoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
buttonDisabled: false
}
}
setInputValue(property, val) {
val = val.trim();
if (val.length > 12) {
return;
}
this.setState({
[property]: val
})
}
resetForm() {
this.setState({
username: "",
password: "",
buttonDisabled: false
})
}
async doLogin() {
if (!this.state.username) {
return;
}
if (!this.state.password) {
return;
}
this.setState({
buttonDisabled: true
})
try {
let res = await fetch('/login', {
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: this.state.username,
password: this.state.password
})
});
let result = await res.json();
if (result && result.succes) {
UserStore.isLoggedIn = true;
UserStore.username = result.username;
}
else if (result && result.succes === false) {
this.resetForm();
alert(result.msg);
}
} catch (e) {
console.log(e);
this.resetForm();
}
}
render() {
return (
<div className="loginForm">
Log In
<InputField
type='text'
placeholder='Username'
value={this.state.username ? this.state.username : ''}
onChange={(val) => this.setInputValue('username', val)}
/>
<InputField
type='password'
placeholder='Password'
value={this.state.password ? this.state.password : ''}
onChange={(val) => this.setInputValue('password', val)}
/>
<SubmitButton
text='Log In'
disabled={this.state.buttonDisabled}
onClick={() => this.doLogin()}
/>
</div>
);
}
}
export default LoginForm;
SubmitButton.js
import React from 'react';
class SubmitButton extends React.Component {
render() {
return (
<div className="submitButton">
<button
className='btn'
type='submit'
disabled={this.props.disabled}
onClick={() => this.props.onClick()}
>
{this.props.text}
</button>
</div>
);
}
}
export default SubmitButton;
App.js
import React from 'react';
import { observer } from 'mobx-react';
import UserStore from './stores/UserStore';
import LoginForm from './LoginForm';
import SubmitButton from './SubmitButton';
import './App.css';
class App extends React.Component {
async componentDidMount() {
try {
let res = await fetch('/isLoggedIn', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
let result = await res.json();
if (result && result.success) {
UserStore.loading = false;
UserStore.isLoggedIn = true;
UserStore.username = result.username;
}
else {
UserStore.loading = false;
UserStore.isLoggedIn = false;
}
}
catch (e) {
UserStore.loading = false;
UserStore.isLoggedIn = false;
}
}
async doLogout() {
try {
let res = await fetch('/logout', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-type': 'application/json'
}
});
let result = await res.json();
if (result && result.success) {
UserStore.isLoggedIn = false;
UserStore.username = '';
}
}
catch (e) {
console.log(e);
}
}
render() {
if (UserStore.loading) {
return (
<div className="app">
<div className='container'>
Loading ,Please Wait...
</div>
</div>
);
}
else {
if (UserStore.isLoggedIn) {
return (
<div className="app">
<div className='container'>
Welcome {UserStore.username}
<SubmitButton
text={'Log Out'}
disabled={false}
onClick={() => this.doLogout()}
/>
</div>
</div>
);
}
return (
<div className="app">
<div className='container'>
<LoginForm />
</div>
</div>
);
}
}
}
export default observer(App);
Router.js
const bcrypt = require('bcrypt');
class Router {
constructor(app, db) {
this.login(app, db);
this.logout(app, db);
this.isLoggedIn(app, db);
}
login(app, db) {
app.post('/login', (req, res) => {
let username = req.body.username;
let password = req.body.password;
username = username.toLowerCase();
if (username.length > 12 || password.length > 12) {
res.json({
success: false,
msg: 'An error occured,please try again'
})
return;
}
let cols = [username];
db.query('SELECT * FROM user WHERE username =? LIMIT 1', cols, (err, data, fields) => {
if (err) {
res.json({
success: false,
msg: 'An error occured,please try again'
});
return;
}
if (data && data.length === 1) {
bcrypt.compare(password, data[0].password, (bcryptErr, verified) => {
if (verified) {
req.session.userID = data[0].id;
res.json({
success: true,
username: data[0].username
})
return;
}
else {
res.json({
success: false,
msg: 'Invalid Password'
})
}
});
} else {
res.json({
success: false,
msg: 'User not Found,please try again..!'
})
}
});
});
}
logout(app, db) {
app.post('/logout',(req,res)=>{
if(req.session.userID){
req.session.destroy();
res.json({
success:true
})
return true;
}
else{
res.json({
success:false
})
return false;
}
})
}
isLoggedIn(app, db) {
app.post('/isLoggedIn',(req,res)=>{
if(req.session.userID){
let cols =[req.session.userID];
db.query('SELECT * FROM user WHERE ID=? LIMIT 1',cols,(err,data,fields) =>{
if(data && data.length ===1){
res.json({
success:true,
username:data[0].username
});
return true;
}
else{
res.json({
success:false
});
}
});
}
else{
res.json({
success:false
})
}
});
}
}
module.exports = Router;

you have to change some logic in LoginForm.js. There are multiple ways in which you can do that. I am showing you one example.
import React from 'react';
import InputField from './InputField';
import SubmitButton from './SubmitButton';
import UserStore from './stores/UserStore';
import {Redirect} from 'react-router-dom' //add a redirect from react-router-dom
class LoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
buttonDisabled: false,
redirectToRefer : false //add a state here for redirect
}
}
setInputValue(property, val) {
val = val.trim();
if (val.length > 12) {
return;
}
this.setState({
[property]: val
})
}
resetForm() {
this.setState({
username: "",
password: "",
buttonDisabled: false
})
}
async doLogin() {
if (!this.state.username) {
return;
}
if (!this.state.password) {
return;
}
this.setState({
buttonDisabled: true
})
try {
let res = await fetch('/login', {
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: this.state.username,
password: this.state.password
})
});
let result = await res.json();
if (result && result.succes) {
UserStore.isLoggedIn = true;
UserStore.username = result.username;
this.setState({redirectToRefer:true})//set rediectToRefer as true
}
else if (result && result.succes === false) {
this.resetForm();
alert(result.msg);
}
} catch (e) {
console.log(e);
this.resetForm();
}
}
render() {
//add a condition at render if redirectToRefer is true then redirect to your page
if(redirectToRefer)
{
return <Redirect to ="/"/>
}
return (
<div className="loginForm">
Log In
<InputField
type='text'
placeholder='Username'
value={this.state.username ? this.state.username : ''}
onChange={(val) => this.setInputValue('username', val)}
/>
<InputField
type='password'
placeholder='Password'
value={this.state.password ? this.state.password : ''}
onChange={(val) => this.setInputValue('password', val)}
/>
<SubmitButton
text='Log In'
disabled={this.state.buttonDisabled}
onClick={() => this.doLogin()}
/>
</div>
);
}
}
export default LoginForm;

Related

Failed to load resource : the server responded with status of 400

import React from 'react';
class Register extends React.Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
name: ''
}
}
onNameChange = (event) => {
this.setState({name: event.target.value})
}
onEmailChange = (event) => {
this.setState({email: event.target.value})
}
onPasswordChange = (event) => {
this.setState({password: event.target.value})
}
onSubmitSignIn = () => {
fetch('https://warm-earth-96837.herokuapp.com/register', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
email: this.state.email,
password: this.state.password,
name: this.state.name
})
})
.then(response => response.json())
.then(user => {
if (user.id) {
this.props.loadUser(user)
this.props.onRouteChange('home');
}
})
}
render() {
return (
<article className="br3 ba b--black-10 mv4 w-100 w-50-m w-25-l mw6 shadow-5 center">
<main className="pa4 black-80">
<div className="measure">
<fieldset id="sign_up" className="ba b--transparent ph0 mh0">
<legend className="f1 fw6 ph0 mh0">Register</legend>
<div className="mt3">
<label className="db fw6 lh-copy f6" htmlFor="name">Name</label>
<input
className="pa2 input-reset ba bg-transparent hover-bg-black hover-white w-100"
type="text"
name="name"
id="name"
onChange={this.onNameChange}
/>
</div>
<div className="mt3">
<label className="db fw6 lh-copy f6" htmlFor="email-address">Email</label>
<input
className="pa2 input-reset ba bg-transparent hover-bg-black hover-white w-100"
type="email"
name="email-address"
id="email-address"
onChange={this.onEmailChange}
/>
</div>
<div className="mv3">
<label className="db fw6 lh-copy f6" htmlFor="password">Password</label>
<input
className="b pa2 input-reset ba bg-transparent hover-bg-black hover-white w-100"
type="password"
name="password"
id="password"
onChange={this.onPasswordChange}
/>
</div>
</fieldset>
<div className="">
<input
onClick={this.onSubmitSignIn}
className="b ph3 pv2 input-reset ba b--black bg-transparent grow pointer f6 dib"
type="submit"
value="Register"
/>
</div>
</div>
</main>
</article>
);
}
}
export default Register;
server.js
const express = require('express');
const bodyParser = require('body-parser');
const bcrypt = require('bcrypt-nodejs');
const cors = require('cors');
const knex = require('knex');
const register = require('./controllers/register');
const signin = require('./controllers/signin');
const profile = require('./controllers/profile');
const image = require('./controllers/image');
const db = knex({
client: 'pg',
connection: {
connectionString : process.env.DATABASE_URL,
ssl : true,
}
});
const app = express();
app.use(cors())
app.use(bodyParser.json());
app.get('/', (req, res)=> { res.send('it is working!') })
app.post('/signin', signin.handleSignin(db, bcrypt))
app.post('/register', (req, res) => { register.handleRegister(req, res, db, bcrypt) })
app.get('/profile/:id', (req, res) => { profile.handleProfileGet(req, res, db)})
app.put('/image', (req, res) => { image.handleImage(req, res, db)})
app.post('/imageurl', (req, res) => { image.handleApiCall(req, res)})
app.listen(process.env.PORT || 3000, ()=> {
console.log(`app is running on port ${process.env.PORT}`);
})
App.js
import React, { Component } from 'react';
import Particles from 'react-particles-js';
import FaceRecognition from './components/FaceRecognition/FaceRecognition';
import Navigation from './components/Navigation/Navigation';
import Signin from './components/Signin/Signin';
import Register from './components/Register/Register';
import Logo from './components/Logo/Logo';
import ImageLinkForm from './components/ImageLinkForm/ImageLinkForm';
import Rank from './components/Rank/Rank';
import './App.css';
const particlesOptions = {
//customize this to your liking
particles: {
number: {
value: 30,
density: {
enable: true,
value_area: 800
}
}
}
}
const initialState = {
input: '',
imageUrl: '',
box: {},
route: 'signin',
isSignedIn: false,
user: {
id: '',
name: '',
email: '',
entries: 0,
joined: ''
}
}
class App extends Component {
constructor() {
super();
this.state = initialState;
}
loadUser = (data) => {
this.setState({user: {
id: data.id,
name: data.name,
email: data.email,
entries: data.entries,
joined: data.joined
}})
}
calculateFaceLocation = (data) => {
const clarifaiFace = data.outputs[0].data.regions[0].region_info.bounding_box;
const image = document.getElementById('inputimage');
const width = Number(image.width);
const height = Number(image.height);
return {
leftCol: clarifaiFace.left_col * width,
topRow: clarifaiFace.top_row * height,
rightCol: width - (clarifaiFace.right_col * width),
bottomRow: height - (clarifaiFace.bottom_row * height)
}
}
displayFaceBox = (box) => {
this.setState({box: box});
}
onInputChange = (event) => {
this.setState({input: event.target.value});
}
onButtonSubmit = () => {
this.setState({imageUrl: this.state.input});
fetch('https://warm-earth-96837.herokuapp.com/imageurl', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
input: this.state.input
})
})
.then(response => response.json())
.then(response => {
if (response) {
fetch('https://warm-earth-96837.herokuapp.com/image', {
method: 'put',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
id: this.state.user.id
})
})
.then(response => response.json())
.then(count => {
this.setState(Object.assign(this.state.user, { entries: count}))
})
.catch(console.log)
}
this.displayFaceBox(this.calculateFaceLocation(response))
})
.catch(err => console.log(err));
}
onRouteChange = (route) => {
if (route === 'signout') {
this.setState(initialState)
} else if (route === 'home') {
this.setState({isSignedIn: true})
}
this.setState({route: route});
}
render() {
const { isSignedIn, imageUrl, route, box } = this.state;
return (
<div className="App">
<Particles className='particles'
params={particlesOptions}
/>
<Navigation isSignedIn={isSignedIn} onRouteChange={this.onRouteChange} />
{ route === 'home'
? <div>
<Logo />
<Rank
name={this.state.user.name}
entries={this.state.user.entries}
/>
<ImageLinkForm
onInputChange={this.onInputChange}
onButtonSubmit={this.onButtonSubmit}
/>
<FaceRecognition box={box} imageUrl={imageUrl} />
</div>
: (
route === 'signin'
? <Signin loadUser={this.loadUser} onRouteChange={this.onRouteChange}/>
: <Register loadUser={this.loadUser} onRouteChange={this.onRouteChange}/>
)
}
</div>
);
}
}
export default App;
import React, { Component } from 'react';
import Particles from 'react-particles-js';
import FaceRecognition from './components/FaceRecognition/FaceRecognition';
import Navigation from './components/Navigation/Navigation';
import Signin from './components/Signin/Signin';
import Register from './components/Register/Register';
import Logo from './components/Logo/Logo';
import ImageLinkForm from './components/ImageLinkForm/ImageLinkForm';
import Rank from './components/Rank/Rank';
import './App.css';
const particlesOptions = {
//customize this to your liking
particles: {
number: {
value: 30,
density: {
enable: true,
value_area: 800
}
}
}
}
const initialState = {
input: '',
imageUrl: '',
box: {},
route: 'signin',
isSignedIn: false,
user: {
id: '',
name: '',
email: '',
entries: 0,
joined: ''
}
}
class App extends Component {
constructor() {
super();
this.state = initialState;
}
loadUser = (data) => {
this.setState({user: {
id: data.id,
name: data.name,
email: data.email,
entries: data.entries,
joined: data.joined
}})
}
calculateFaceLocation = (data) => {
const clarifaiFace = data.outputs[0].data.regions[0].region_info.bounding_box;
const image = document.getElementById('inputimage');
const width = Number(image.width);
const height = Number(image.height);
return {
leftCol: clarifaiFace.left_col * width,
topRow: clarifaiFace.top_row * height,
rightCol: width - (clarifaiFace.right_col * width),
bottomRow: height - (clarifaiFace.bottom_row * height)
}
}
displayFaceBox = (box) => {
this.setState({box: box});
}
onInputChange = (event) => {
this.setState({input: event.target.value});
}
onButtonSubmit = () => {
this.setState({imageUrl: this.state.input});
fetch('https://warm-earth-96837.herokuapp.com/imageurl', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
input: this.state.input
})
})
.then(response => response.json())
.then(response => {
if (response) {
fetch('https://warm-earth-96837.herokuapp.com/image', {
method: 'put',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
id: this.state.user.id
})
})
.then(response => response.json())
.then(count => {
this.setState(Object.assign(this.state.user, { entries: count}))
})
.catch(console.log)
}
this.displayFaceBox(this.calculateFaceLocation(response))
})
.catch(err => console.log(err));
}
onRouteChange = (route) => {
if (route === 'signout') {
this.setState(initialState)
} else if (route === 'home') {
this.setState({isSignedIn: true})
}
this.setState({route: route});
}
render() {
const { isSignedIn, imageUrl, route, box } = this.state;
return (
<div className="App">
<Particles className='particles'
params={particlesOptions}
/>
<Navigation isSignedIn={isSignedIn} onRouteChange={this.onRouteChange} />
{ route === 'home'
? <div>
<Logo />
<Rank
name={this.state.user.name}
entries={this.state.user.entries}
/>
<ImageLinkForm
onInputChange={this.onInputChange}
onButtonSubmit={this.onButtonSubmit}
/>
<FaceRecognition box={box} imageUrl={imageUrl} />
</div>
: (
route === 'signin'
? <Signin loadUser={this.loadUser} onRouteChange={this.onRouteChange}/>
: <Register loadUser={this.loadUser} onRouteChange={this.onRouteChange}/>
)
}
</div>
);
}
}
export default App;
Register Handler Code
const handleRegister = (req, res, db, bcrypt) => {
const { email, name, password } = req.body;
if (!email || !name || !password) {
return res.status(400).json('incorrect form submission');
}
const hash = bcrypt.hashSync(password);
db.transaction(trx => {
trx.insert({
hash: hash,
email: email
})
.into('login')
.returning('email')
.then(loginEmail => {
return trx('users')
.returning('*')
.insert({
email: loginEmail[0],
name: name,
joined: new Date()
})
.then(user => {
res.json(user[0]);
})
})
.then(trx.commit)
.catch(trx.rollback)
})
.catch(err => res.status(400).json('unable to register'))
}
module.exports = {
handleRegister: handleRegister
};
I am getting error 400 when i am trying to register a user.
Failed to load resource: the server responded with a status of 400 (Bad Request)
i have attached my register.js file
Register.js:26 POST https://warm-earth-96837.herokuapp.com/register 400 (Bad Request)
Register.onSubmitSignIn # Register.js:26
The 400 Bad Request Error is an HTTP response status code that indicates that the server was unable to process the request sent by the client due to invalid syntax. As with the dozens of potential HTTP response codes, receiving a 400 Bad Request Error while accessing your own application can be both frustrating and challenging to fix. Such HTTP response codes represent the complex relationship between the client, a web application, a web server, and often multiple third-party web services, so determining the cause of a particular status code can be a difficult, even within a controlled development environment
The 400 error happens when, for example, your route signup needs a field "name" and you did not send this field, or when you send a field that, for example, should be a string but you sent an Integer. That is, your request is wrong. Please put here what your route request to sign up the user so we can conclude what field is wrong or what is missing.
Thx and waiting for your response :).

React + Express sending data?

I'm working on a login/register system with React front-end and Node/Express back-end.
When the registration fails, i want to reload the registration page and return the error msgs to my react front end.
Instead of refreshing the page, it renders the JSON data.
How can you go about re-rendering the registration form, while sending the data behind the scenes?
router.post("/register", (req, res) => {
const { name, email, password, password2 } = req.body;
let errors = [];
...
...
...
if (errors.length > 0) {
res.send({
errors,
name,
email,
password,
password2
});
You need to receive the response from express in your react app, and perform your logic inside your submit function in react.
One way you can do this is to create a state variable for the error message. Make the initial value null or ''. When user registration fails catch the error and assign it your error variable in state. Here is an example of user registration system:
//RegistrationForm.js
import React, { useState } from 'react';
import AuthApiService from '../../services/auth-api-service';
import { Input } from '../Utils/Utils';
import { Button } from '#material-ui/core';
import './RegistrationForm.css';
export default function RegistrationForm(props) {
const [error, setError] = useState(null)
const errorDiv = error
? <div className="error">
<i class="material-icons error-icon">error_outline</i>
{error}
</div>
: '';
const handleSubmit = e => {
e.preventDefault();
setError(null);
const { full_name, user_name, password } = e.target;
AuthApiService.postUser({
full_name: full_name.value,
user_name: user_name.value,
password: password.value
})
.then(user => {
full_name.value = '';
user_name.value = '';
password.value = '';
props.onRegistrationSuccess();
})
.catch(res => {
setError(res.error);
})
};
return(
<form className='RegistrationForm'
onSubmit={handleSubmit}
>
<div className='full_name'>
<label htmlFor='RegistrationForm__full_name'>
Full name
</label>
<Input
name='full_name'
type='text'
required
id='RegistrationForm__full_name'>
</Input>
</div>
<div className='user_name'>
<label htmlFor='RegistrationForm__user_name'>
User name
</label>
<Input
name='user_name'
type='text'
required
id='RegistrationForm__user_name'>
</Input>
</div>
<div className='password'>
<label htmlFor='RegistrationForm__password'>
Password
</label>
<Input
name='password'
type='password'
required
id='RegistrationForm__password'
>
</Input>
</div>
<div className='confirm-password'>
<label htmlFor="LoginForm__confirm-password">
Retype Password
</label>
<Input
name='confirm-password'
type="password"
required
id="LoginForm__confirm-password">
</Input>
</div>
{errorDiv}
<Button type='submit' variant='contained' color='default'>
Register
</Button>
</form>
)
}
//AuthApiService.js
import config from '../config';
import TokenService from './token-service';
import IdleService from './idle-service';
const AuthApiService = {
postUser(user) {
return fetch(`${config.API_ENDPOINT}/users`, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify(user)
})
.then(res =>
(!res.ok)
? res.json().then(e => Promise.reject(e))
: res.json()
)
.then(res => {
TokenService.saveAuthToken(res.authToken)
IdleService.registerIdleTimerResets()
TokenService.queueCallbackBeforeExpiry(() => {
AuthApiService.postRefreshToken()
})
return res
})
},
postLogin({user_name, password }) {
return fetch(`${config.API_ENDPOINT}/auth/login`, {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({user_name, password}),
})
.then(res =>
(!res.ok)
? res.json().then(e => Promise.reject(e))
: res.json()
)
.then(res => {
TokenService.saveAuthToken(res.authToken)
TokenService.queueCallbackBeforeExpiry(() => {
AuthApiService.postRefreshToken()
})
return res
})
},
postGuestLogin() {
return fetch(`${config.API_ENDPOINT}/auth/guest-login`, {
method: 'POST',
headers: {
'content-type': 'application/json'
},
})
.then(res =>
(!res.ok)
? res.json().then(e => Promise.reject(e))
: res.json()
)
.then(res => {
TokenService.saveAuthToken(res.authToken)
TokenService.queueCallbackBeforeExpiry(() => {
AuthApiService.postRefreshToken()
})
return res
})
},
postRefreshToken() {
return fetch(`${config.API_ENDPOINT}/auth/refresh`, {
method: 'POST',
headers: {
'authorization': `Bearer ${TokenService.getAuthToken()}`,
},
})
.then(res =>
(!res.ok)
? res.json().then(e => Promise.reject(e))
: res.json()
)
.then(res => {
TokenService.saveAuthToken(res.authToken)
TokenService.queueCallbackBeforeExpiry(() => {
AuthApiService.postRefreshToken()
})
return res
})
.catch(err => {
TokenService.clearAuthToken()
console.log('refresh token request error')
console.log(err)
})
}
}
export default AuthApiService;
//TokenService.js
import jwtDecode from 'jwt-decode';
import config from '../config';
let _timeoutId;
const _TEN_SECONDS_IN_MS = 10000;
const TokenService = {
saveAuthToken(token) {
window.localStorage.setItem(config.TOKEN_KEY, token);
},
getAuthToken() {
return window.localStorage.getItem(config.TOKEN_KEY);
},
clearAuthToken() {
window.localStorage.removeItem(config.TOKEN_KEY);
},
hasAuthToken() {
return !!TokenService.getAuthToken()
},
makeBasicAuthToken(userName, password) {
return window.btoa(`${userName}:${password}`);
},
parseJwt(jwt) {
return jwtDecode(jwt);
},
readJwtToken() {
return TokenService.parseJwt(TokenService.getAuthToken());
},
_getMsUntilExpiry(payload) {
return (payload.exp * 1000) - Date.now();
},
queueCallbackBeforeExpiry(callback) {
const msUntilExpiry = TokenService._getMsUntilExpiry(
TokenService.readJwtToken()
);
_timeoutId = setTimeout(callback, msUntilExpiry - _TEN_SECONDS_IN_MS);
},
clearCallbackBeforeExpiry() {
clearTimeout(_timeoutId);
}
};
export default TokenService;
EDIT:
Here is an example of what the router can look like:
//users-router.js
const express = require('express')
const path = require('path')
const UsersService = require('./users-service')
const AuthService = require('../auth/auth-service')
const usersRouter = express.Router()
const jsonBodyParser = express.json()
usersRouter.post('/', jsonBodyParser, (req, res, next) => {
const { password, user_name, full_name } = req.body
for (const field of ['password', 'full_name', 'user_name'])
if (!req.body[field])
return res.status(400).json({
error: `Missing ${field} in request body`
})
const passwordError = UsersService.validatePassword(password)
if (passwordError)
return res.status(400).json({ error: passwordError })
UsersService.hasUserWithUserName(
req.app.get('db'),
user_name
)
.then(hasUserWithUserName => {
if(hasUserWithUserName)
return res.status(400).json({ error: 'Username already taken' })
return UsersService.hashPassword(password)
.then(hashedPassword => {
const newUser = {
user_name,
full_name,
password: hashedPassword,
date_created: 'now()'
}
return UsersService.insertUser(
req.app.get('db'),
newUser
)
.then(user => {
const serializedUser = UsersService.serializeUser(user)
const { user_name, user_id } = serializedUser
const sub = user_name
const payload = {user_id: user_id}
res
.status(201)
.location(path.posix.join(req.originalUrl, `/${user.id}`))
.send({
authToken: AuthService.createJwt(sub, payload),
user: serializedUser
})
})
})
})
.catch(next)
})
module.exports = usersRouter
//users-service.js
const bcrypt = require('bcryptjs')
const xss = require('xss')
const REGEX_UPPER_LOWER_NUMBER_SPECIAL = /(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!##\$%\^&])[\S]+/
const UsersService = {
hasUserWithUserName(db, user_name) {
return db('askify_users')
.where({ user_name })
.first()
.then(user => !!user)
},
insertUser(db, newUser) {
return db
.insert(newUser)
.into('askify_users')
.returning('*')
.then(([user]) => user)
},
validatePassword(password) {
if (password.length < 8) {
return 'Password must be longer than 8 characters'
}
if (password.length > 72) {
return 'Password must be less than 72 characters'
}
if (password.startsWith(' ') || password.endsWith(' ')) {
return 'Password must not start or end with empty spaces'
}
if (!REGEX_UPPER_LOWER_NUMBER_SPECIAL.test(password)) {
return 'Password must contain one upper case, lower case, number and special character'
}
return null
},
hashPassword(password) {
return bcrypt.hash(password, 12)
},
serializeUser(user) {
return {
id: user.id,
full_name: xss(user.full_name),
user_name: xss(user.user_name),
nickname: xss(user.nick_name),
date_created: new Date(user.date_created),
}
},
}
module.exports = UsersService
// auth-service.js
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const config = require('../config')
const AuthService = {
getUserWithUserName(db, user_name) {
return db('askify_users')
.where({user_name})
.first()
},
comparePasswords(password, hash) {
return bcrypt.compare(password, hash)
},
createJwt(subject, payload) {
return jwt.sign(payload, config.JWT_SECRET, {
subject,
expiresIn: config.JWT_EXPIRY,
algorithm: 'HS256',
})
},
verifyJwt(token) {
return jwt.verify(token, config.JWT_SECRET, {
algorithms: ['HS256'],
})
},
parseBasicToken(token) {
return Buffer
.from(token, 'base64')
.toString()
.split(':')
},
}
module.exports = AuthService

undefined is not a function in React Native

I'm trying to make an API call in React Native to handle user authentication. I'm passing this.state.email and this.state.password (both bound to text inputs) to a function in my services/ folder, where the call is made. Afterwards, the screen should navigate to the home stack or return an error. This is my login screen code:
import AuthService from ...
export default class LoginScreen extends Component {
constructor(props) {
super(props);
this.login = this.login.bind(this);
this.state = {
email: '',
password: '',
};
}
login() {
AuthService.login(this.state.email, this.state.password)
.then(this.props.navigation.navigate('Main')) //Move to home screen
.catch(console.error('Error')); //Handle error
}
render() {
return (
<View>
<TextInput
onChangeText={email => this.setState({ email })}
value={this.state.email}
/>
<TextInput
onChangeText={password => this.setState({ password })}
value={this.state.password}
/>
<TouchableOpacity onPress={this.login}>
<Text style={styles.text}>Submit</Text>
</TouchableOpacity>
</View>
);
}
}
And this is my AuthService function:
login(email, password) {
// Check if credentials exist
if (!email || !password) {
return undefined;
}
return fetch(
`${AUTH_ROOT}/login`,
{
method: 'POST',
body: { email, password },
}
.then(
res => {
const data = { ...res.data };
if (!data) {
throw new Error('No user returned from auth service');
}
},
res => {
context.error = 'Could not login';
console.log(res);
}
)
);
},
But I'm getting the error:
> undefined is not a function (near '...{
> method: 'POST',
> body: {
> email: email,
> password: password,
> } }.then...')
What does this mean? Is my call not done correctly?
login(email, password) {
// Check if credentials exist
if (!email || !password) {
return undefined;
}
return fetch(
`${AUTH_ROOT}/login`,
{
method: 'POST',
body: { email, password },
}
)
.then(
res => {
const data = { ...res.data };
if (!data) {
throw new Error('No user returned from auth service');
}
},
res => {
context.error = 'Could not login';
console.log(res);
}
)
},
The right syntax for fetch is
fetch(url, params).then()
instead you had
fetch(url, params.then())

Passing data from fetch to another component

I have a Login component, which has form with inputs for user's data, and I have a method onFormSubmit with fetch. The problem is that I have no idea, how to pass token to another component ( it is there, I can console.log it ). The reason why I want to pass token to another component is that the other component is validating if user has logged in and by detecting token ( null = user didn't log in and redirect him to login page, otherwise go to protected pages )
My login.js component
class Login extends React.Component() {
constructor() {
super();
this.state = {
email: '',
password: '',
};
}
onInputChange = (e) => {
this.setState({
[e.target.id]: e.target.value
});
};
onFormSubmit = (e) => {
e.preventDefault();
fetch('http://localhost:3001/user/login', {
method: 'POST',
body: JSON.stringify({
email: this.state.email,
password: this.state.password
}),
headers: {
'Content-Type': 'application/json'
}
})
.then( res => {
if( res.status === 200){
this.props.history.push('/MyPlaces');
} else {
const error = new Error(res.error);
throw error;
}
})
.catch(err => {
console.error(err);
alert('Error login in please try again!');
});
};
render() {
return (
<div className="loginPanel">
<form onSubmit={this.onFormSubmit}>
<label>Email
<input type="text"
id="email"
value={this.state.email}
onChange={this.onInputChange}
/>
</label>
<label>Password
<input type="text"
id="password"
value={this.state.password}
onChange={this.onInputChange}/>
</label>
<input type="submit" value="Submit" />
</form>
</div>
);
};
}
export default Login;
My authentication component
import React, {Component} from 'react';
import { Redirect } from 'react-router-dom';
export default function withAuth(ComponentToProtect, props) {
return class extends Component {
constructor() {
super();
this.state = {
loading: true,
redirect: false
};
}
componentDidMount() {
fetch('')
.then(res => {
if( res.status === 200) {
this.setState({ loading: false});
} else {
const error = new Error(res.error);
throw error;
}
})
.catch(err => {
console.error(err);
this.setState({ loading: false, redirect: true });
})
}
render() {
const { loading, redirect } = this.state;
if( loading ){
return null;
}
if( redirect ){
return <Redirect to="/Login" />;
}
return (
<React.Fragment>
<ComponentToProtect {...this.props}/>
</React.Fragment>
);
}
}
}
I know that there is nothing in fetch in authentication component, I thought that I should've make another api request ( same as in login component, then after fetch just invoke
.then(res => res.json()).then(res => {
let token = res.token;
console.log("token: ", token);
});
but it just doesn't seem to be good idea I think. Could you please give me some guide how may I do that?
You can simply use localStorage.setItem('token-name', token); to store the token after fetch. Then you can retrieve it using localStorage.getItem('token-name') across all the component. If the getItem returns null then you can simply redirect to login.
For logout, you can simply update the token value to null.
Login Component
fetch('http://localhost:3001/user/login', {
method: 'POST',
body: JSON.stringify({
email: this.state.email,
password: this.state.password
}),
headers: {
'Content-Type': 'application/json'
}
})
.then(res => {
if( res.status === 200){
localStorage.setItem('token', res.token); //storing the token in localStorage.
this.props.history.push('/MyPlaces');
} else {
const error = new Error(res.error);
throw error;
}
})
.catch(err => {
console.error(err);
alert('Error login in please try again!');
});
Authentication Component
componentDidMount() {
let token = localStorage.getItem('token'); //retriving the token from localStorage
if(token === null){
this.setState({ loading: false, redirect: true });
}
}
Hope this will help you.

React authentication with JWT

I am trying to add an authentication system to my application in React / Laravel. For that I make a request for the theory recovers a token as on Passport. The problem is that it returns me a token undefined ... Yet when I look at the console of my browser I see in preview the token in question ...
Can someone please guide me to solve this problem?
Here is the code of my Auth service
import decode from 'jwt-decode';
export default class AuthService {
// Initializing important variables
constructor(domain) {
this.domain = domain || 'http://127.0.0.1:8000' // API server
domain
this.fetch = this.fetch.bind(this) // React binding stuff
this.login = this.login.bind(this)
this.getProfile = this.getProfile.bind(this)
}
login(username, password) {
// Get a token from api server using the fetch api
return this.fetch(`${this.domain}/oauth/token`, {
method: 'POST',
body: JSON.stringify({
username,
password,
grant_type: "password",
client_id:"2",
client_secret : "Wu07Aqy9pU5pLO9ooTsqYDBpOdzGwrhvw5DahcEo"
})
}).then(res => {
this.setToken(res.token) // Setting the token in localStorage
return Promise.resolve(res);
})
}
loggedIn() {
// Checks if there is a saved token and it's still valid
const token = this.getToken() // GEtting token from localstorage
return !!token && !this.isTokenExpired(token) // handwaiving here
}
isTokenExpired(token) {
try {
const decoded = decode(token);
if (decoded.exp < Date.now() / 1000) { // Checking if token is
expired. N
return true;
}
else
return false;
}
catch (err) {
return false;
}
}
setToken(token) {
// Saves user token to localStorage
localStorage.setItem('access_token', token)
}
getToken() {
// Retrieves the user token from localStorage
return localStorage.getItem('access_token')
}
logout() {
// Clear user token and profile data from localStorage
localStorage.removeItem('access_token');
}
getProfile() {
// Using jwt-decode npm package to decode the token
return decode(this.getToken());
}
fetch(url, options) {
// performs api calls sending the required authentication headers
const headers = {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
// Setting Authorization header
// Authorization: Bearer xxxxxxx.xxxxxxxx.xxxxxx
if (this.loggedIn()) {
headers['Authorization'] = 'Bearer ' + this.getToken()
}
return fetch(url, {
headers,
...options
})
.then(this._checkStatus)
.then(response => response.json())
}
_checkStatus(response) {
// raises an error in case response status is not a success
if (response.status >= 200 && response.status < 300) { // Success
status lies between 200 to 300
return response
} else {
var error = new Error(response.statusText)
error.response = response
throw error
}
}
}
Here of my form
import React, { Component } from 'react';
import AuthService from './AuthService';
import { Router, Route, Switch, Link } from 'react-router-dom'
class Login extends Component {
constructor(){
super();
this.handleChange = this.handleChange.bind(this);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
this.Auth = new AuthService();
}
handleFormSubmit(e){
e.preventDefault();
this.Auth.login(this.state.username,this.state.password)
.then(res =>{
this.props.history.replace('/Localisations');
})
.catch(err =>{
alert(err);
})
}
componentWillMount(){
if(this.Auth.loggedIn())
this.props.history.replace('/');
}
render() {
return (
<div className="center">
<div className="card">
<h1>Login</h1>
<form onSubmit={this.handleFormSubmit}>
<input
className="form-item"
placeholder="Username goes here..."
name="username"
type="text"
onChange={this.handleChange}
/>
<input
className="form-item"
placeholder="Password goes here..."
name="password"
type="password"
onChange={this.handleChange}
/>
<input
className="form-submit"
value="Submit"
type="submit"
/>
</form>
</div>
</div>
);
}
handleChange(e){
this.setState(
{
[e.target.name]: e.target.value
}
)
}
}
export default Login;
And here of of my with Auth
import React, { Component } from 'react';
import AuthService from './AuthService';
export default function withAuth(AuthComponent) {
const Auth = new AuthService('http://127.0.0.1:8000');
return class AuthWrapped extends Component {
constructor() {
super();
this.state = {
user: null
}
}
componentWillMount() {
if (!Auth.loggedIn()) {
this.props.history.push('/Localisations')
}
else {
try {
const profile = Auth.getProfile()
this.setState({
user: profile
})
}
catch(err){
Auth.logout()
this.props.history.push('/')
}
}
}
render() {
if (this.state.user) {
return (
<AuthComponent history={this.props.history} user= .
{this.state.user} />
)
}
else {
return null
}
}
};
}

Resources