Formik setting errors on submission - reactjs

I have 2 questions
I am trying to handle a submission in Formik. I would like to handle the authentication in my backend and then depending on what my backend returns, set an error "Invalid email/password combo" or redirect to a new page (let's say index). Here is the code handling the submission:
handleSubmit(
{email, password}: LoginFormValues,
{props, setSubmitting, setErrors}
){
fetch(backendURL, {
method: "POST",
body: JSON.stringify({username: email, password: password}),
headers: {
'Content-Type': 'application/json'
},
})
.then(response => response.json())
.then(data => {
if(data.token) {
localStorage.setItem("token", data.token)
props.history.push("/")
}else{
//TODO
}
});
}
If the response contains a token then I'll redirect to index however if doesn't then I'd like to display some errors. Is there a way I can do this with Formik or do I need to redirect to the page that contains my form and print an error message there? (If so, how would I do that anyway because I cannot return <Redirect /> (I have to use history.push(...) right?
I am aware that most of the times when you submit a form (and get redirected to a new page), if you try to navigate backwards it'll say something along the lines of "form needs to be resubmitted". However, when I go back in my application it simply renders the form again. Is that something I should be worried about? (What is the motivation in the first place?)

You can handle authentication failure easily with Formik without having to redirect. Following is an example.
handleSubmit(
{email, password}: LoginFormValues,
{props, setSubmitting, setFieldError}
){
fetch(backendURL, {
method: "POST",
body: JSON.stringify({username: email, password: password}),
headers: {
'Content-Type': 'application/json'
},
})
.then(response => response.json())
.then(data => {
if(data.token) {
localStorage.setItem("token", data.token)
props.history.push("/")
}else{
setFieldError("authentication", "Authentication Failed!");
setSubmitting(false);
}
});
}
After this, the error message will be available in errors.authentication. You can replace authentication with whatever name you like because errors is an object. You can now display your error message this way.
{errors.authentication && <div>{errors.authentication}</div>}
You can also use setErrors instead of setFieldError but it will replace the entire error object with a new object.
As for your second question, you do not need to worry about it as long as you ensure no secret or private information is revealed on the form. You can also probably set up a boolean flag in your application to prevent user from seeing the form if the user has logged in by redirecting to a different page, but that is entirely up to you.

Related

Firebase sendPasswordResetEmail in JS SDK, doesn't send confirmation code

I am trying to do the following:
User asks to reset his password
Email is sent with a CODE and an URL to visit to reset his password
User visits the URL inputs the code and the new password and I call the confirmPasswordReset
But this doesn't work, the docs, their examples and also their functionality differs. Here's what happens
Greeting,
Follow this link to reset the example#gmail.com account password for the Example Dev app.
the URL
No Code, nothing, if I follow the URL it will take me to Firebase hosted app that will handle the reset with an ugly looking UI and THEN redirect me to the specified URL in the settings for sendResetEmail...
While the docs specify expected behavior, it differs from the actual one.
Sends a password reset email to the given email address.
#remarks
To complete the password reset, call confirmPasswordReset with the code supplied in the email sent to the user, along with the new password specified by the user.
#example
const actionCodeSettings = {
url: 'https://www.example.com/?email=user#example.com',
iOS: {
bundleId: 'com.example.ios'
},
android: {
packageName: 'com.example.android',
installApp: true,
minimumVersion: '12'
},
handleCodeInApp: true
};
await sendPasswordResetEmail(auth, 'user#example.com', actionCodeSettings);
// Obtain code from user.
await confirmPasswordReset('user#example.com', code);
The docs specify my intended behavior, but when used, it's totally different. What is happening here?
const onSubmit = (data: PasswordResetData) => {
setIsLoading(true);
sendPasswordResetEmail(getAuth(), data.email, {
url: "http://localhost:3002/en/auth/reset/confirm?email=" + data.email,
handleCodeInApp: true,
})
.then(() => {
})
.catch((err) => {
console.error(err);
})
.finally(() => {
setIsLoading(false);
});
};

react submit form then redirect issue

I have a form that must serve 2 tasks after submission:
send the form data to the server
redirect to another page
I'm having difficulties making both things happen;
The first one is easily accomplished using <Form action='/blabla'>, but then I get a blank page with the returned information from the server side as text.
The second one is also easily accomplished using <Form onSubmit={handleSubmit}> with the function:
const handleSubmit = (e) => {
e.preventDefault()
fetch('/blabla', {method: 'POST'})
.then(res => res.json())
.then(data => {
history.push('/nextPage')
})
.catch(error => {
alert(error)
})
}
And it works fine, except no data is sent from the form to the server :(
So, can someone explain me please how to get both tasks above done?
Thanks in advance :)
Would be more clear if you can post the as well.
Anyway, only from the snippet I say your fetch doesnot have body field in configuration, like:
fetch('/blabla', {
method: 'POST',
headers: {
'Content-Type': 'application/json' // or 'application/x-www-form-urlencoded'
},
body: JSON.stringify(data), // adjust this according to Content-Type header
})
that might be the reason why there was no data sent to server.

Form handling in ReactJS with functional component

I have following code.
my code
What I want to is when I click on "SEND" button it show error or success messages. I tried:
.then(() =>
setAfterSendSuccess("Thank you. We will contact you shortly.")
)
.catch(() =>
setAfterSendError("Something went wrong. Please try again later")
);
But it always show green success message.
Also I have "Loading" component which should start load when I click on Send button.
For that one I tried:
{!!setFormLoading(true) && <Loading />}
The issue is with your use of the fetch api. You're expecting fetch to reject the promise if there's a 4xx or 5xx http response code, but fetch doesn't do that. It only rejects on network failures or other things that prevent the fetch from occurring at all.
So you'll need to modify your code something like the following:
fetch(`real link`, {
method: "POST",
body: JSON.stringify({ email }),
})
.then((response) => {
if (!response.ok) {
throw response;
}
return response.json(); // if you don't care about the data, you can leave this out
})
.then(() => setAfterSendSuccess("Thank you. We will contact you shortly."))
.catch(() =>
setAfterSendError("Something went wrong. Please try again later")
);
Also I have "Loading" component which should start load when I click on Send button.
Your jsx needs to be this: {formLoading && <Loading />}, and you'll need to call setFormLoading with true at the start of the submit function, and with false in the .then and .catch.

CSRF Protection with Flask/WTForms and React

Has anyone successfully implemented CSRF protection for a form submitted with React (as a controlled component) to a Flask back-end (ideally with WTForms)? I've seen a lot of partial answers, and one with Django, but couldn't find anything definitive for Flask. My big issue seems to be that I don't know how to send the csrf token to my react front end, store it as a header before submitting my form, then submit my form with the correct token. Any direction would be really helpful.
So, essentially what I did is I set up a route in Flask that can receive both GET and POST requests. React sends a GET request when the component mounts, and Flask responds with the csrf token as a header (done manually). Then React stores this value in state. When the form is submitted, the csrf token from state is sent as a field, similar to the way it is sent in a pure Flask app, where it would be a hidden field. While this technically works, I am curious if this is still vulnerable to CSRF. I think the next best option is to set up CSRF protection on all endpoints, so can try that if this isn't secure.
Flask route:
#app.route('/api/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
print(request.method)
if request.method == 'GET':
return ('', {'csrf_token': form.csrf_token._value()})
elif form.validate_on_submit():
return { 'message': 'Login successful' }, 200
else:
return { 'errors': form.errors }
GET request in componentDidMount:
componentDidMount() {
axios.get('/api/login',{data: null, headers: {'Content-Type': 'application/json'}})
.then(res => {
console.log(res)
this.setState({
csrf: res.headers.csrf_token
});
})
}
POST request when form is submitted:
onSubmitLogin = e => {
e.preventDefault();
const userData = {
username: this.state.username,
password: this.state.password,
csrf_token: this.state.csrf
};
axios({
method: 'post',
url: '/api/login',
data: userData,
headers: {
'content-type': 'application/json'
}
})
.then(res => {
console.log(res);
});
}
Maybe you need flask-security-too lib
https://flask-security-too.readthedocs.io/en/stable/patterns.html#csrf

React Native Formik handleSubmit does not read return values from function

Good day!
Im having a weird experience using formik today,
I am currently working on an app that uses formik to handle forms and will do an API request inside the onSubmit() function of formik.
Every thing went well except when i use API request and wait for it's callback.
Somehow the things inside the function of onSubmit will work properly but the API callback value does not return unless i perform a UI Change in the app itself (like pressing random spots on my screen to trigger ui change).
Here is a look of my onSubmit function of formik
onSubmit={values => {
console.log("before")
let response = FunctionWithApiRequest(values);
console.log("after")
response.then((res) => {
console.log(res)
})
}}
and here is my function with api request inside
const FunctionWithApiRequest = (credentials) => {
return fetch(`${AppConfig.HOSTNAME}/v2/auth/signup`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(credentials)
})
.then((response) => response.json())
.then((responseJson) => {
return responseJson
})
.catch((error) => {
console.log(error)
});
}
The return "responseJson" will only appear inside the onsubmit function when i perform a UI Change (like clicking random spots in my react native screen)
i was wondering what is the problem and what cause the bug.
Thank you for your response in advance.
Possibly you can do this in a separate function with await and async.For instance
async handleSubmit(){
let {credentials} = this.state
let data = await this.props.FunctionWithApiRequest(credentials)
this.setState({returnedData: data})
}
And now in your textInput/formik
onSubmit={()=>this.handleSubmit()}
I assume you have made the request api function in actions.file, not in the same file.Am i right?So what i have done is just put await before call.Which means next line will execute only when you have response returned.Comment down if you have any issue.
It was caused by the haul bundler, when you enable dugging mode.

Resources