ReactJS How To Set Cookie From Fetch Request to Back End - reactjs

I have a react front end that is talking to a Node Back End. I am able to make requests and such . However, I noticed that I cannot set the cookie that I am getting back. My back end will respond upon logging in, with a message and a cookie. How should I be doing this?
Relevant code:
import React from "react";
import Fetch from 'react-fetch';
export class Loginform extends React.Component{
constructor(){
super();
this.state = {message : ""};
this.state = {cookie : ""};
}
Login(e){
e.preventDefault();
var Email_Address = this.refs.Email.value;
var Password = this.refs.Password.value;
fetch("http://localhost:5000/api/form", {
method: "POST",
headers: {
"Content-Type":"application/json",
"Accept":"application/json"
},credentials: "include",
body: JSON.stringify({
Email_Address: Email_Address,
Password: Password
})
}).then(response=>response.json())
.then(response => this.setState({message: response.Message, cookie :response['x-access-token']}));
}
render(){
return(
<div className="LoginContainer">
<form name="Loginform" method="post" action="http://localhost:5000/api/tavern" onSubmit={this.Login.bind(this)}>
<div className="block">
<label><i className="fa fa-envelope"></i></label>
<input ref="Email" type="email" placeholder="E-Mail" required title="Enter Valid E-Mail Address"/>
<i className="fa fa-check" aria-hidden="true"></i>
</div>
<div className="block">
<label><i className="fa fa-lock"></i></label>
<input ref="Password" type="password" placeholder="Enter Your Password" pattern=".{9,}" required title="9 Characters Minimum"/>
<i className="fa fa-check" aria-hidden="true"></i>
</div>
<div className="returnmessage"> {this.state.message}</div>
<div className="buttons"> <button type="submit" value="Submit">Login</button></div>
</form>
</div>
);
}
}
I had to add this to make the answer below applicable :
npm install react-cookies --save
import cookie from 'react-cookies'
Here is my code after.
fetch("http://localhost:5000/api/tavern", {
method: "POST",
headers: {
"Content-Type":"application/json",
"Accept":"application/json"
},credentials: "include",
body: JSON.stringify({
Email_Address: Email_Address,
Password: Password
})
}).then(response=>response.json())
.then(function (data){
console.log(data);
cookie.save('x-access-token', data['x-access-token']);
this.setState({message: data.Message, cookie :data['x-access-token']})
}.bind(this)
)
}

What you are doing is not setting the cookie. You are just creating a variable in state called cookie.
Install this package.
The correct syntax is
Cookies.set('access_token', response.headers['x-access-token'])
Now it is actually stored in to your browser cookies. You can go ahead and access it back using
Cookies.get('access_token')

For react you can also use react-cookie package. And if the React version >16.8.0 you can use React Hooks.
import { useCookies } from 'react-cookie';
const [cookies, setCookie] = useCookies(['name']); // getting react hooks
cookie2.set('access_token', 'content of cookie');
cookie = cookies.get('access_token');
console.log(cookie)

Related

React JS: problem in receiving cookie with axios, which is received from JWT Django

First of all, I had made a POST APIView function using Django and added JWT token in it. This api is basically made for the login purpose. I can transfer all the details in it and recieve a cookie in return.
class LoginView(APIView):
def post(self, request):
email = request.data['email']
password = request.data['password']
user = User.objects.filter(email=email).first()
if user is None:
raise AuthenticationFailed('user not found')
if not user.check_password(password):
raise AuthenticationFailed('Incorrect password')
payload = {
'id': user.id,
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=60),
'iat': datetime.datetime.utcnow()
}
token = jwt.encode(payload, 'secret', algorithm='HS256').decode('utf-8')
response = Response()
response.set_cookie(key='jwt', value=token, httponly=True)
response.data = {
'jwt': token
}
return response
I used POST request using axios in react js and trying to recieve cookie too with the help of "withCredentials: true" yet unable to get the cookie.
import React, { Component } from 'react';
import axios from 'axios';
class Login extends Component {
state = {
email: '',
password: '',
};
handleSubmit(event){
event.preventDefault();
axios({
method: 'post',
url: 'http://127.0.0.1:8000/user/login ',
withCredentials: true,
data: {
email: this.state.email,
password: this.state.password
}
})
.then(data => console.log(data));
}
handleChange(event){
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({[name]:value})
}
render() {
return (
<div>
<h1>LOGIN</h1>
<form onSubmit={this.handleSubmit.bind(this)}>
<div>
<label>Email: </label>
<br />
<input
type="text"
name="email"
onChange={this.handleChange.bind(this)}
value={this.state.email}
/>
</div>
<br />
<div>
<label>Password: </label>
<br />
<input
type="password"
name="password"
onChange={this.handleChange.bind(this)}
value={this.state.password}
/>
</div>
<br />
<button type="submit">Submit</button>
</form>
</div>
);
}
}
export default Login;
I am getting this issue in the console.
Rather than using axios. I had used fetch() which worked for me.
event.preventDefault();
const response = await fetch('http://localhost:8000/user/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
credentials: 'include',
body: JSON.stringify({
email: this.state.email,
password: this.state.password
})
});
console.log(response)
}```

React - Secure login using a API with windows authentication

I've created and testing my API which responds with authorized or not-authorized when the credentials have been typed in. I have tested this with postman and works perfectly.
The login I am trying to create is on React and is currently looking like this -
import React, { Component } from "react";
import { Button, Form, FormGroup, Input } from "reactstrap";
import { withRouter } from "react-router-dom";
import auth from "./auth";
export class Login extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
login = () => {
auth.login();
};
handleSubmit(event) {
event.preventDefault();
fetch('http://localhost:5000/api/LoginTest', {
method: 'post',
headers: { 'Content-Type': 'application/json' },
body: {
"username": this.username.value,
"password": this.username.value
}
});
};
render() {
return (
<div className="Login">
<form onSubmit={this.handleSubmit}>
<h2 id="formTitle" className="text-center">
Admin Panel
</h2>
<input
id="inputUsername"
type="text"
placeholder="Username"
name="username"
ref={(ref) => { this.username = ref }}
/>
<input
id="inputPassword"
type="password"
placeholder="Password"
name="password"
ref={(ref) => { this.password = ref }}
/>
<button
id="button"
type="submit"
className="btn btn-block btn-success"
>
Sign-in
</button>
</form>
</div>
);
}
}
export default withRouter(Login);
The 2 errors which I'm currently getting are -
415 Unsupported Media Type
OR
When I use mode: no-cors
Acces to fetch at "" from origin has been blocked by the CORS policy
Any help on this would be perfect!
In your fetch options, try setting:
mode: 'cors'
Also make sure that you stringify() your body data
Take a look at this example on the MDN site

401 ERROR with API sending blank basic auth

I am creating an API to send a basic auth login request to my flask backend, however when sending a request I get
{username: "ww", password: "ww"}
POST http://localhost:5000/login 401 (UNAUTHORIZED)
i have logged the data entered to check is was being set, this response is returned via the js console on the browser, the logging in my flask console is as follows :
127.0.0.1 - - [10/Nov/2019 16:21:07] "OPTIONS /login HTTP/1.1" 200 -
{'username': '', 'password': ''}
127.0.0.1 - - [10/Nov/2019 16:21:07] "POST /login HTTP/1.1" 401 -
My flask login route looks like
#app.route('/login', methods =['POST'])
def login():
if request.method == 'POST':
auth = request.authorization
print(auth)
if not auth.username or not auth.password:
return make_response('Could not verify :(', 401, {'WWW-Authenticate' : 'Basic realm="Login Required"'})
user = User.query.filter_by(username = auth.username).first()
if not user:
return make_response('Could not verify', 401, {'WWW-Authenticate' : 'Basic realm="Login Required"'})
if check_password_hash(user.password, auth.password):
token = jwt.encode({'public_id' : user.public_id, 'exp' : datetime.datetime.utcnow() + datetime.timedelta(minutes=30) }, app.config['SECRET_KEY'])
return jsonify({'token' : token.decode('UTF-8')})
return make_response('Could not verify', 401, {'WWW-Authenticate' : 'Basic realm="Login Required"'})
this is the login component on my react front end
export class Login extends React.Component {
constructor(props){
super(props);
this.state = {
username: '',
password: '',
}
}
changeHandler = e => {
this.setState({[e.target.name]: e.target.value})
}
submitHandler = e => {
const headers = {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json',
}
var username = this.username
var password = this.password
e.preventDefault()
console.log(this.state)
axois.post('http://localhost:5000/login',this.state,{
headers: {
headers
}
,auth: {
username : username,
password: password
}
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})
}
render() {
const {username, password} = this.state
return <div className = "base-container" ref={this.props.containerRef}>
<div className="content">
<div className="logo">
<img src={Logo} alt="Logo"/>
</div>
<form className="form" onSubmit={this.submitHandler}>
<div className="form-group">
<label htmlFor="username"> Username</label>
<input type="text"
name="username"
value ={username}
placeholder="Username"
onChange={this.changeHandler}/>
</div>
<div className="form-group">
<label htmlFor="password"> Password</label>
<input type="password"
name="password"
value={password}
placeholder="Password"
onChange ={this.changeHandler}/>
</div>
<button type="submit" className="btn">Login</button>
</form>
</div>
<div className="footer">
</div>
</div>
}
}
My request works through using postman so im unsure why it doesnt using React? I am using Flask-Cors to prevent CORS errors and storing the user data in auth header so im not sure why flask cant read it.
I am very new to this so any help would be great :) Thanks !

'Uncaught SyntaxError: Unexpected token <' on Login Form

In my NextJS app.I'm developing a login page and now I'm getting the following error.
Uncaught SyntaxError: Unexpected token <
This was not appearing before and it started appearing yesterday.I googled the error message and browsed through many SO answers but none of them were helpful.I removed all form related onSubmit and onChange code but the error is still there.Since which code causes this error,I will post entire Login component here.
import React, { Component } from 'react';
import Heading from '../components/Heading';
class Login extends Component{
constructor(props) {
super(props);
this.onChangeInput = this.onChangeInput.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
date: new Date().toJSON().slice(0,10),
username: '',
password: ''
}
}
onChangeInput(e) {
this.setState({
[e.target.name]: e.target.value
});
}
onSubmit(e) {
e.preventDefault();
const t = {
date: new Date().toJSON().slice(0,10),
username: this.state.username,
password: this.state.password
}
fetch('/server', {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify(this.state)
})
this.setState({
username: '',
password: ''
});
}
render(){
return(
<div>
<div style={{textAlign: "center"}}>
<h1>PackMasters Ceylon (Pvt) Ltd</h1>
<h2>Inventory Management System</h2>
<h3>Login</h3>
</div>
<form onSubmit={this.onSubmit} onChange={this.onChangeInput} className={"col-md-4 col-md-offset-4"}>
<Heading title="Login | PackMasters Ceylon (Pvt) Ltd" />
<div className={"form-group"}>
<label htmlFor="username">Username</label>
<input type="text" name="username" value={this.state.username} className={"form-control"} id="username"/>
</div>
<div className={"form-group"}>
<label htmlFor="passsword">Password</label>
<input type="password" name="password" value={this.state.password} className={"form-control"} id="password" />
</div>
<div className={"form-group"}>
<input type="submit" className={"form-control"} value="Log In"/>
</div>
</form>
</div>
);
}
}
export default Login;
After struggling a lot, I found out that it is caused by the browser cache.The problem was solved after clearing browser cache on Chrome.Still I'm not able to explain the exact reason for that.However I will mention here how to clear cache on Google Chrome.
On your computer, open Chrome.
At the top right, click More.
Click More tools > Clear browsing data.
At the top, choose a time range. To delete everything, select All time.
Next to "Cookies and other site data" and "Cached images and files," check the boxes.
Click Clear data
A few issues:
The change handler should go on each input, not on the form
A bad idea to set the timestamp in the constructor... Seems you were already going in the right direction...
If you convert the handlers into arrow functions (no this context) no need to bind in the constructor (that's just a side note...)
Try this:
import React, { Component } from 'react';
import Heading from '../components/Heading';
class Login extends Component {
state = { username: '', password: '' };
handleChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
handleSubmit = e => {
e.preventDefault();
const user = {
date: new Date().toJSON().slice(0, 10),
username: this.state.username,
password: this.state.password,
};
fetch('/server', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(user),
});
this.setState({ username: '', password: '' });
};
render() {
return (
<div>
<div style={{ textAlign: 'center' }}>
<h1>PackMasters Ceylon (Pvt) Ltd</h1>
<h2>Inventory Management System</h2>
<h3>Login</h3>
</div>
<form
onSubmit={this.handleSubmit}
className={'col-md-4 col-md-offset-4'}
>
<Heading title="Login | PackMasters Ceylon (Pvt) Ltd" />
<div className={'form-group'}>
<label htmlFor="username">Username</label>
<input
type="text"
name="username"
value={this.state.username}
className={'form-control'}
id="username"
onChange={this.handleChange}
/>
</div>
<div className={'form-group'}>
<label htmlFor="passsword">Password</label>
<input
type="password"
name="password"
value={this.state.password}
className={'form-control'}
id="password"
onChange={this.handleChange}
/>
</div>
<div className={'form-group'}>
<input type="submit" className={'form-control'} value="Log In" />
</div>
</form>
</div>
);
}
}
export default Login;
Edit: Add a then and a catch block to fetch:
fetch('/server', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(user),
}).then(res => res.json())
.then(response => console.log('Success:', JSON.stringify(response)))
.catch(error => console.error('Error:', error));
Also, I noticed you are using Next.js... You need to install Isomorphic Unfetch https://github.com/developit/unfetch/tree/master/packages/isomorphic-unfetch
In my case, static files were not being served due to global authentication enabled. which was also authenticating static files. So I had to apply #Public() metadata to that route to allow into JwtAuthGuard.
#Public()
#Get('/_next/static/*')
async getStaticContent(
#Req() req: IncomingMessage,
#Res() res: ServerResponse,
) {
await this.appService.handler(req, res);
}
More details on public metadata below.
https://docs.nestjs.com/security/authentication#enable-authentication-globally
And make sure your "esversion":6 is 6 for that follow below flow
For Mac VSCode : Code(Left top corner) => Prefrences => Settings => USER SETTINGS. and check at right side and write below Code
{
"workbench.colorTheme": "Visual Studio Dark",
"git.ignoreMissingGitWarning": true,
"window.zoomLevel": 0,
// you want to write below code for that
"jshint.options": {
"esversion":6
},
}

fetch request not working with headers

I am working on login page with ReactJs,Spring Boot and rest web services.My Reactjs frontend application is running on port 8080 while my webservice/spring boot application is running on port 9090. I am trying to use the "fetch" method to connect with my backend code, but I am facing error while passing headers in fetch request. If I remove headers property, execution goes into the called backend method. I need to pass Headers in fetch method as it required to access them in web service method.
Please find Snapshot of network requests and responses. Without Headers With headers
Below is my code of React JSX file:
import React, { Component } from 'react';
class App extends Component {
constructor(props){
super(props);
this.state={
email:'',
password:''
}
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
var usernameFieldValue = this.refs.emailField.value;
var passwordFieldValue = this.refs.passwordField.value;
this.setState({email:usernameFieldValue})
this.setState({password:passwordFieldValue})
//var headers = 'Basic bmltZXNoLnBhdGVsQHRhdHZhc29mdC5jb206cGFzc3dvcmQ=';
//alert(headers);
fetch('http://192.168.0.239:9090/ws/login',{
mode: 'cors',
method: 'get',
headers: {
"Content-Type": "application/json",
"Authorization": "Basic bmltZXNoLnBhdGVsQHRhdHZhc29mdC5jb206cGFzc3dvcmQ="
}
}).then((response) => response.json())
.then((responseJson) => {
alert(" responseJson : " + responseJson);
})
.catch((error) => {
alert("Error : " +error);
});
}
render() {
return (
<div id="loginFrame">
<div className="container">
<div id="loginHeader" className="row">
<div className="col-xs-12 text-center">
<img src="" alt="'Logo" />
</div>
</div>
<div id="loginBody" className="row">
<div className="col-xs-6 col-xs-offset-3">
<div className="center-block">
<div id="login-panel">
<form id="loginForm" className="form-horizontal" role="form">
<div className="form-group">
<input type="text" className="form-control input-lg" id="email" name="email" ref="emailField" placeholder="Email address"/>
</div>
<div className="form-group">
<input type="password" className="form-control input-lg" id="password" name="password" ref="passwordField" placeholder="Password"/>
</div>
<div className="form-group">
<button onClick={this.handleClick} className="btn btn-lg btn-success pull-right">Login</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default App;
var url = "https://yourUrl";
var bearer = 'Bearer '+ bearer_token;
fetch(url, {
method: 'GET',
withCredentials: true,
credentials: 'include',
headers: {
'Authorization': bearer,
'X-FP-API-KEY': 'iphone',
'Content-Type': 'application/json'}
}).then((responseJson) => {
var items = JSON.parse(responseJson._bodyInit);
})
.catch(error => this.setState({
isLoading: false,
message: 'Something bad happened ' + error
}));
You don't need mode: cors, this is default.
const headers = new Headers({
"Content-Type": "application/json",
"Authorization": "Basic bmltZXNoLnBhdGVsQHRhdHZhc29mdC5jb206cGFzc3dvcmQ="
});
fetch('http://192.168.0.239:9090/ws/login', {
method: 'GET',
headers,
}).then().then().catch();
Based on your comments, it sounds like the underlying problem is that you're doing a CORS request from your react app, which is being served from a different server than your spring backend. I don't know Spring, but adding a Access-Control-Allow-Origin HTTP header (as well as some other CORS related headers) will clear up the problem. I'm not 100% sure why when you fetch with no headers, it works. There may be a deeper configuration issue or you need to configure it to allow requests with those headers you're passing (Access-Control-Allow-Headers). Note that if you don't plan to allow cross-origin requests in production you may want to add those headers except when in development.
You can also fetch in no CORS mode (pass {mode: 'no-cors'}), but there's a lot of limitations to that and I doubt that's what you want.

Resources