Csrf token post in React Native - react-native

I've made a website using Node and Express as a framework. Now we are shifting to a React Native Mobile Application. While making the login page I have made a post request as given below
index.js
import React, { Component } from 'react'
import {
View,
TextInput,
Text,
Button,
Alert,
} from 'react-native';
import styles from './styles'
class Home extends Component {
constructor(props){
super(props)
state = {email: "", password: ""}
}
checkLogin(){
const { email, password } = this.state;
if(email ==="admin" || password === "admin" || true){
fetch('http://localhost:3021/user/signin', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
password: password,
}),
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.error(error);
})
}
else{
Alert.alert('Error', 'Email/Password mismatch', [{
text: 'Okay',
}])
}
}
render(){
const {heading, input, parent} = styles
return (
<View style={parent}>
<Text style={heading}> Login into the Application </Text>
<TextInput style={input} placeholder="Email" onChangeText={text => this.setState({email: text})} underlineColorAndroid='black'/>
<TextInput style={input} secureTextEntry={true} placeholder="Password" onChangeText={text => this.setState({password: text})} underlineColorAndroid='black'/>
<Button title={"Login"} onPress = {() => this.checkLogin()} />
</View>
);
}
}
export default Home
When I sent this request, I got no response and checked it on Postman for the response and it was coming as an invalid csrf token and 403 error. Initially in my web app while logging in, the form consisted of a CSRF token which was passed as given below:
<input type = "hidden" name="_csrf" value="{{ csrfToken }}">
How do I replicate this on the React Native App? I tried searching online, however, could not find any such method discussed.

You can
1. Either add CSRF token in the request headers
OR 2. Disable CSRF on in your back-end.
export const login = (user) => {
fetch('http://localhost:3000/api/session', {
method: 'POST',
credentials: 'include',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-TOKEN': token
},
body: JSON.stringify({user})
})
// promise handling
}

Related

How to set headers in axios, ReactNative

i build an application, React Native as Frontend and Django as Backend,
i use axios to take data from user then send it to backend it show error Request failed with status code 400
i have used Restful API that build with django and run the server locally,
so i think when i add headers to axios then the API request response without errors
so,How to set headers in axios
the user enter the data through form and send it to the backend
Add.js page with form take data from user send it to the backend
import * as React from "react";
import {View, Text, Image, StyleSheet, Button, TextInput} from "react-native";
import { COLORS, SIZES,FONTS} from '../styles/theme.js';
import { FieldArray, Formik} from "formik";
import axios from 'axios';
const AddScreen =()=>{
const radioopt = [{},{},{},{}];
const submit = (val) => {
if(val.type == "" || val.category == "" || val.amount == ""){
alert("Please Enter all details");
return;
}
// 'http://192.168.8.143:8000/transactions/'
axios.post('http://192.168.8.143:8000/transactions/', {
"id": "1",
"type": val?.type,
"category": val.category,
"amount": val?.amount,
// "owner" : "",
"date" : Date.now(),
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
return(
<View style={{flex: 1, backgroundColor:COLORS.gray}}>
<Formik
initialValues={{type:'',category:'', amount:''}}
onSubmit={(values)=>{submit(values)}}
>
{(props)=>(
<View style={styles.whitecard}>
<TextInput
style={styles.inputstyle}
placeholder='type'
onChangeText={props.handleChange('type')}
value={props.values.type}
/>
<TextInput
style={styles.inputstyle}
placeholder='category'
onChangeText={props.handleChange('category')}
value={props.values.category}
/>
<TextInput
style={styles.inputstyle}
placeholder='amount'
onChangeText={props.handleChange('amount')}
value={props.values.amount}
keyboardType='numeric'
/>
<View style={{margin:10,padding:0, backgroundColor:COLORS.pink, borderRadius:6}}>
<Button title='Submit' color='white' onPress={props.handleSubmit}></Button>
</View>
</View>
)}
</Formik>
</View>
);
}
...
export default AddScreen;
You must pass an object with headers like documentation says: https://axios-http.com/docs/req_config
so your request will be:
axios.post('http://192.168.8.143:8000/transactions/',{formData}, {
//example with bearer token
headers: {
'Authentication': 'Bearer 89324u2jhjwe98'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
You can pass options on third argument. There you can add headers on post method like following:
axios.post('https://example.com', formData, { headers: 'content-type': 'text/json',...otherHeaders })

How to store API response in state And pass this response value to another screen as params in react native

I am new to react native. I have created A screen. Where I am getting response from API. but now I want to store that response in state. and I want to send that value to another screen by navigation params.
my response is like this ->
Array [
Object {
"phpid": 10,
},
]
here is my code
constructor(props) {
super(props);
this.state={
};
}
fetch('https://xuz.tech/Android_API_CI/uploaddata/t_details?query=', {
method: 'POST',
headers: {'Accept': 'application/json, text/plain, */*', "Content-Type": "application/json" },
body: JSON.stringify([{"==some values=="}])
})
.then((returnValue) => returnValue.json())
.then(function(response) {
console.log(response)
return response.json();
render(){
return (
<View style={{flex: 1}}>
color="black" onPress={() => this.props.navigation.navigate("FormItems",{i want to send value to formitems})} />
</View>
)}
Set your state once you receive your response, then use your state as params when navigating. Once your fetch has been resolved:
this.setState({ response: response.json() });
Sending params to another screen is fairly simple, you just need to pass an object as the second parameter to navigate.
this.props.navigation.navigate('FormItems', {
form: this.state.response,
});
The receiving component will then need to read those params:
class DetailsScreen extends React.Component {
render() {
const { navigation } = this.props;
return (
<Text>{JSON.stringify(navigation.getParam('form', 'some default'))}</Text>
}
}
A full explanation on how to use params with react-navigation v4 can be found here: https://reactnavigation.org/docs/4.x/params
Use it like this. first initialise the state and when you get data from api set the data in state and when button press pass the data to new screen in params.
import React, { Component } from 'react';
import { Text, View } from 'react-native';
export default class Example extends Component {
state = {
data: [], // initialize empty state
};
componentWillMount() {
this.requestData();
}
requestData = () =>{
fetch('https://xuz.tech/Android_API_CI/uploaddata/t_details?query=', {
method: 'POST',
headers: {'Accept': 'application/json, text/plain, */*', "Content-Type": "application/json" },
body: JSON.stringify([{"==some values=="}])
})
.then((returnValue) => returnValue.json())
.then(function(response) {
this.setState({
data:response //set data in state here
})
})
}
render() {
return (
<View style={{ flex: 1 }}>
<Button
color="black"
onPress={() =>
this.props.navigation.navigate('FormItems', {
data: this.state.data, // pass data to second screen
})
}
/>
</View>
);
}
}

Unable to get data using ReactNative fetch

I'm trying to fetch data from an API(I created my own Rest API using JSON-server). But I'm unable to fetch anything. however, I'm able to see the data when I navigate to localhost:3000/events. There's no other error in my app. I only get this when I run the app it says network request failed. All the components are working fine. Just not getting the data. I've tried some other online APIs still not getting any response. I've tried with async/await. I'm using the app with IOS but have tried with Andriod as well. Same problem occurs. Attaching the code snippets. Any help would be highly appreciated. Thanks
Created the getEvent Function:
const { manifest } = Constants;
const api = manifest.packagerOpts.dev
? manifest.debuggerHost.split(`:`).shift().concat(`:3000`)
: `api.example.com`;
const url = `http://${api}/events`;
export function getEvents() {
return fetch(url)
.then(response => response.json())
.then(events => events.map(e => ({ ...e, date: new Date(e.date) })))
}
Using it inside the componentDidMount
componentDidMount() {
// getEvents().then(events => this.setState({ events }));
setInterval(() => {
this.setState({
events: this.state.events.map(evt => ({
...evt,
timer: Date.now()
}))
});
}, 1000);
this.props.navigation.addListener("didFocus", () => {
getEvents().then(events => this.setState({ events }));
});
}
Data that I'm trying to fetch.
{
"events": [
{
"title": "Demo a new app",
"date": "2020-03-29T13:45:18.000Z",
"id": "001c9b6d-00a9-465c-a2d3-afb7176a0a87"
}
]
}
you can use axios as of fetch , it is also used to hit API's and get response from them , and it is simple and easy way as compare to fetch.
run npm i react-native-axios on your project root floder to install the library and import it and use it , here is an example of axios , in which the user will login to screen and will hit the login API , the user enter their credentials and if they are correct as in API then user will get response or user will login successfully.
import axios from "axios";
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: "",
}
};
onPresssighnin = () => {
var data = {
//parameters to pass API
Email: this.state.email,
Password: this.state.password,
};
axios
.post(" insert API url here", data, {
"Content-Type": "application/json"
})
.then(
response => {
//get response here
alert(JSON.stringify(response))
},
error => {
//get errormessage here
errormessage = error.Message;
alert(errormessage);
}
);
}
};
render() {
return (
<View style={styles.logoContainer}>
<Input
borderless
placeholder="Email"
onChangeText={email => this.setState({ email })}
iconContent={
<Icon
size={16}
color={ditsTheme.COLORS.ICON}
name="ic_mail_24px"
family="DitsExtra"
style={styles.inputIcons}
/>
}
/>
<Input
password
borderless
placeholder="Password"
onChangeText={password =>this.setState({ password })}
iconContent={
<Icon
size={16}
color={ditsTheme.COLORS.ICON}
name="padlock-unlocked"
family="DitsExtra"
style={styles.inputIcons}
/>
}
/>
<Button
color="primary"
style={styles.createButton}
onPress={this.onPresssighnin} >
<Text bold size={14} color={ditsTheme.COLORS.WHITE}>
SIGN IN
</Text>
</Button>
</View>
)
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'rgb(32, 53, 70)',
flexDirection: 'column',
},
buttonText: {
textAlign: 'center',
color: 'rgb(32, 53, 70)',
fontWeight: 'bold',
fontSize: 18
}
})
Feel free for Doubts.

react-native login screen - error when login button is pressed with empty login fields

I have a simple login screen that asks for an email and password.
Login Screen
If the "Sign In" button is pressed and both of the fields are blank I get this error: "null is not an object (evaluating'_this.state.Email')"
Error Screen
Here is the code:
import React, {Component} from 'react';
import {View, Button, ScrollView, AsyncStorage, Alert } from 'react-native';
import colors from '../config/colors';
import { TextInput } from '../components/TextInput';
class SignIn extends Component {
signIn = () => {
const {Email} = this.state;
const {Password} = this.state;
fetch('http://192.168.1.3/Restaurant_App/php/sign_in.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application.json',
},
body: JSON.stringify({
email: Email,
password: Password,
})
}).then((response) => response.json())
.then((responseJson) => {
if (responseJson == Email) {
Alert.alert(responseJson);
AsyncStorage.setItem('email', Email);
this.props.navigation.navigate('Search');
} else {
Alert.alert(responseJson);
}
}).catch((error) => {
console.error(error);
});
};
render() {
return (
<View>
<ScrollView style={{ backgroundColor: colors.background }}>
<TextInput
placeholder="Email..."
onChangeText={Email => this.setState({Email})}
/>
<TextInput
placeholder="Password..."
secureTextEntry={true}
onChangeText={Password => this.setState({Password})}
/>
</ScrollView>
<Button
onPress={() => this.signIn()}
title="Sign In"
/>
</View>
);
}
}
export default SignIn;
I would like it to be so that if the "Sign In" button is pressed with empty fields, I won't get this error. Instead, there should be an alert saying "Please fill in all fields." or something like that.
You should do some validation checks before making the fetch request.
You could do something like this
signIn = () => {
const {Email, Password} = this.state;
if(!this.checkDetails(Email, Password) {
// you could show an alert here, but it is not great UX,
// you should show your user where they have gone wrong,
// by making style changes, a red border around the TextInput,
// text explaining what has gone wrong.
return;
}
fetch('http://192.168.1.3/Restaurant_App/php/sign_in.php', {
...
}).then((response) => response.json())
.then((responseJson) => {
...
}).catch((error) => {
console.error(error);
});
};
checkDetails = (Email, Password) => {
// check that it is a valid email address
// this is a regex that I have used in the past to check email addresses.
const emailIsValid = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(Email);
// if the password has a minimum length then you should use that rather than 0
this.setState({emailIsValid, passwordIsValid: Password.length > 0});
if (emailIsValid && Password.length > 0) return true;
return false;
}
Using these new state values for the email and password being valid you could set additional styles and error text beside the fields that are wrong or missing.
<TextInput
placeholder="Email..."
onChangeText={Email => this.setState({Email})}
styles={this.state.emailIsValid ? styles.validEmail : styles.invalidEmail}
/>
{!this.state.emailIsValid && <Text>Please input a valid email</Text>}
<TextInput
placeholder="Password..."
secureTextEntry={true}
onChangeText={Password => this.setState({Password})}
styles={this.state.passwordIsValid ? styles.validPassword : styles.invalidPassword}
/>
{!this.state.passwordIsValid && <Text>Please input a valid password</Text>}
Don't for get to set up your styles for the different states.
const styles = StyleSheet.create({
validEmail: {},
validPassword: {},
invalidEmail: {},
invalidPassword: {}
});
You'll probably want to add initial state values for the emailIsValid and passwordIsValid so that they are set to true so that the correct styles are shown. Also you should define initial state for the Email and Password.
Add a constructor to your class
constructor (props) {
super(props);
this.state = {
Email: '',
Password: '',
emailIsValid: true,
passwordIsValid: true
}
}
I hope that this helps.
You can do at the top of your sign in function something like this:
If(this.state.email.length === 0 || this.state.password.length === 0) {
alert(“please complete the fields”);
return;}

Why isn't mailchimp API working with fetch?

I'm trying to add an email address to a mailchimp list I have.
This is for a react native app and I'm trying to implement the request using fetch.
This is my code within the component:
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { connect } from 'react-redux';
import { emailChanged, nameChanged, addToWaitingList } from '../actions';
import { Card, CardSection, Input, Button, Spinner } from '../components/Auth';
class addToWaitingListForm extends Component {
onEmailChange(text) {
this.props.emailChanged(text);
}
onButtonPress() {
const { email } = this.props;
this.props.addToWaitingList({ email });
}
renderButton() {
if (this.props.loading) {
return <Spinner size="large" />;
}
return (
<Button onPress={this.onButtonPress.bind(this)}>
Keep me in the loop!
</Button>
);
}
render() {
return (
<View>
<Card>
<CardSection>
<Input
placeholder="your name"
onChangeText={this.onNameChange.bind(this)}
value={this.props.name}
/>
</CardSection>
<CardSection>
<Input
placeholder="email#uni.ac.uk"
onChangeText={this.onEmailChange.bind(this)}
value={this.props.email}
/>
</CardSection>
<Text style={styles.errorTextStyle}>
{this.props.error}
</Text>
<CardSection style={{ borderBottomWidth: 0 }}>
{this.renderButton()}
</CardSection>
</Card>
</View>
);
}
}
const mapStateToProps = ({ auth }) => {
const { email, name, error, loading } = auth;
return { email, name, error, loading };
};
export default connect(mapStateToProps, {
emailChanged,
addToWaitingList
})(addToWaitingListForm);
Add this is my action code for interacting with the mailchimp api:
import Router from '../../navigation/Router';
import { getNavigationContext } from '../../navigation/NavigationContext';
export const addToWaitingList = ({ email }) => {
const emailListID = 'e100c8fe03';
fetch(`https://us13.api.mailchimp.com/3.0/lists/${emailListID}/members/`, {
method: 'POST',
body: JSON.stringify({
'email_address': email,
'status': 'subscribed',
'merge_fields': {
'FNAME': 'Urist',
'LNAME': 'McVankab'
}
})
})
.then(() => addSubscriberSuccess())
.catch(error => console.log(error));
};
const addSubscriberSuccess = () => {
getNavigationContext().getNavigator('root').immediatelyResetStack([Router.getRoute('auth')]);
};
Right now, the error I'm just getting back is ExceptionsManager.js:62 Cannot read property 'type' of undefined and Error: unsupported BodyInit type
What does this mean and how can I fix this?
You need to do two things.
First off you need to send the basic authentication via fetch so you cant do "user:pass" You have to convert it with btoa('user:pass').
Then you have to send it with mode: 'no-cors'
let authenticationString = btoa('randomstring:ap-keyxxxxxxx-us9');
authenticationString = "Basic " + authenticationString;
fetch('https://us9.api.mailchimp.com/3.0/lists/111111/members', {
mode: 'no-cors',
method: 'POST',
headers: {
'authorization': authenticationString,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
email_address: "dude#gmail.com",
status: "subscribed",
})
}).then(function(e){
console.log("fetch finished")
}).catch(function(e){
console.log("fetch error");
})