I'm working with an ASP.NET 6 app, generated with ASP.NET Core with React.js Visual Studio 2022 template. I've used Individual Accounts as Authentication Type when creating the project, so all Identity stuff has been nicely generated.
Now I have nice Razor views scaffolded by ASP.NET's Identity. However, I'd like to build my whole UI as React SPA application, using react-router. It means that I don't want to use Razor views, but still use ASP.NET's Identity backend.
Firstly, I wanted to implement a React form to submit changing the user password. Razor view generated for that is Identity/Pages/Account/ManageChangePassword.cshtml. It looks like that:
As soon as I submit this Razor form, the request looks as follows:
with the following payload:
So now, I basically rebuilt this form in React:
import React, { useState } from "react";
import Button from "react-bootstrap/Button";
import Form from "react-bootstrap/Form";
export const ChangePassword = () => {
const [currentPassword, setCurrentPassword] = useState<string>("");
const [newPassword, setNewPassword] = useState<string>("");
const [newPasswordConfirm, setNewPasswordConfirm] = useState<string>("");
const onChangePasswordFormSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData();
formData.append("Input.OldPassword", currentPassword);
formData.append("Input.NewPassword", newPassword);
formData.append("Input.ConfirmPassword", newPasswordConfirm);
fetch("Identity/Account/Manage/ChangePassword", {
method: "POST",
body: formData,
});
};
return (
<Form onSubmit={onChangePasswordFormSubmit}>
<Form.Group className="mb-3" controlId="currentPassword">
<Form.Label>Current password</Form.Label>
<Form.Control
type="password"
placeholder="Current password"
value={currentPassword}
onChange={(e) => setCurrentPassword(e.target.value)}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="newPassword">
<Form.Label>New password</Form.Label>
<Form.Control
type="password"
placeholder="New password"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="newPasswordConfirm">
<Form.Label>Confirm new password</Form.Label>
<Form.Control
type="password"
placeholder="Confirm new password"
value={newPasswordConfirm}
onChange={(e) => setNewPasswordConfirm(e.target.value)}
/>
</Form.Group>
<Button variant="primary" type="submit">
Change password
</Button>
</Form>
);
};
However, when submitting this form, I'm getting a HTTP 400 error:
the payload looks good at the first sight:
but I noticed that I'm missing the __RequestVerificationToken in this payload.
I guess it's coming from the fact that Identity controllers (to which I have no access) must be using [ValidateAntiForgeryToken] attribute.
If I change my form's submit code to add this payload parameter manually:
const formData = new FormData();
formData.append("Input.OldPassword", currentPassword);
formData.append("Input.NewPassword", newPassword);
formData.append("Input.ConfirmPassword", newPasswordConfirm);
formData.append(
"__RequestVerificationToken",
"CfDJ8KEnNhgi1apJuVaPQ0BdQGnccmtpiQ91u-6lFRvjaSQxZhM6tj8LATJqWAeKFIW5ctwRTdtQruvxLbhq2EVR3P1pATIyeu3FWSPc-ZJcpR_sKHH9eLODiqFPXYtdgktScsOFkbnnn5hixMvMDADizSGUBRlSogENWDucpMgVUr3nVMlGwnKAQDH7Ck4cZjGQiQ"
);
fetch("Identity/Account/Manage/ChangePassword", {
method: "POST",
body: formData,
});
};
It works fine and the request arrives correctly.
My question is: where to get __RequestVerificationToken from? How can I send it to the ASP.NET's Identity controller from a purely React form?
I noticed that when submitting my React form, this value is visible in cookies:

so the React form/browser must somehow know this value? Where does it come from? Maybe my approach is somehow wrong here? Thanks for advising :)




