It was set headers and axios but Why happen cros error? - reactjs

Premise / What you want to achieve
React x Redux (port: 3000)
Go (port: 8080)
I am making a SPA.
I run into a CROS error when hitting the Go API.
I've encountered this problem many times, and every time I think it's solved, I hit a new API.
I should have made the basic settings, but I'm in trouble because I don't know what caused it.
We would appreciate it if you could help us.
Problem / Error message
Access to XMLHttpRequest at'http://localhost:8080/login' from origin'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No'Access-Control -Allow-Origin'header is present on the requested resource.
I encountered this when I hit the login API (post).
However, when I encountered this problem several times, I set cros on the header of api and axios side, and
Another get API avoided the error.
Also, when you hit api with postman, it becomes header
We have also confirmed that the header set in Go such as Allow-Origin is given without any problem.
Applicable source code
Header settings in Go
w.Header (). Set ("Content-Type", "application /json")
w.Header (). Set ("Access-Control-Allow-Origin", "http://localhost:3000")
w.Header (). Set ("Access-Control-Allow-Credentials", "true")
react axios settings
axios.defaults.baseURL ='http://localhost:8080';
axios.defaults.headers.post ['Content-Type'] ='application/json';
Posting code with an error
export const signIn = (email, password) => {
return async (dispatch) => {
try {
const response = await axios.post ('/login', {
email: email,
password: password,
});
const data = response.data;
dispatch (
signInAction ({
isSignedIn: true,
})
);
} catch (error) {
console.log (error);
}
};
};
Code hitting a successful getapi
useEffect (() => {
async function fetchTickers () {
try {
const response = await axios.get (`/ticker?Symbol=^skew`);
const data = response.data;
setChartAry ([... chartAry, [... data.daily]]);
} catch (error) {
console.log (error);
setChartAry ([]);
}
}
fetchTickers ();
}, []);
What I tried
I tried all the solutions that hit with stackoverflow etc. Also, considering the possibility of a problem with the browser itself, we also cleared the cache.
Is it the difference between axios by get and post? And how should I debug it?

I had this problem some time ago but I used Express for the backend, who knows this can solve your problem too.
try adding this to the axios settings axios.defaults.withCredentials = true;
You also need to allow the OPTIONS method for preflight requests
this article might help you solve the CORS problem on the backend: https://flaviocopes.com/golang-enable-cors/

The method was validated in gorilla / mux.
- r.HandleFunc("/login", app.loginHandler).Methods("POST")
+ r.HandleFunc("/login", app.loginHandler).Methods("POST", "OPTIONS")
We also had to deal with preflight.
if r.Method == "OPTIONS" {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "http://localhost:3000")
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.WriteHeader(http.StatusOK)
return
}

Related

csurf with React: Invalid token after changing user

I've had csrf protection with the csurf module working for a while now on my React SPA. I am also using passport for authentication. I do not do any server-side rendering, so the server sends a csrf token in the response body to the client when it hits the /users/current endpoint, which is protected with csrfProtection, something like this:
import csrf from 'csurf';
const csrfProtection = csrf();
router.get("users/current", csrfProtection, async function(req, res)
{
.....
res.write(JSON.stringify({ ..., csrfToken: req.csrfToken() }));
res.end();
}
On the client side I then add the token to all subsequent request headers, a bit like this:
axiosInstance.get("/users/current")
.then(resJson =>
{
axiosInstance.interceptors.request.use(config =>
{
config.headers["x-csrf-token"] = resJson.data.csrfToken;
return config;
});
}
My first question is how the first request even manages to pass the csrfProtection without a token in its header. Yet since the token can only be accessed on the server to send to the client if the route is csrf protected, I don't see a way around this, and it does work somehow.
However, recently I have been getting "ForbiddenError: invalid csrf token" when a user logs in or deletes their account. This has only started happening after I upgraded all my node packages to the latest versions. First the client makes a request to /users/login to submit the username & password, and then makes a request to /users/current to get the new csrf token:
axiosInstance.post("/users/login", {
"username": login.username,
"password": login.password
})
.then(async resJson =>
{
// *code to update user details in redux store*
// ......
axiosInstance.interceptors.request.use(config =>
{
config.headers["x-csrf-token"] = undefined;
return config;
});
return resJson;
})
.then(async resJson =>
{
const { csrfToken } = await axiosInstance.get("/users/current")
.then(resJson => resJson.data);
axiosInstance.interceptors.request.use(config =>
{
config.headers["x-csrf-token"] = csrfToken;
return config;
});
return resJson.data;
}
I suspect it's something to do with subsequent requests coming from a different userId (which I obtain from req.user[0].userId), with which csurf will not accept the previously issued token. But I have no idea how to issue the new token csurf does expect, to the client. And it still doesn't explain why what I had before has suddenly stopped working since none of my logic has changed. This isn't the kind of error I'd typically expect after package updates.
Here someone mentions you can just set any header on the client and have the server check for that. atm I am adding the csrf token to all the client's request headers and using the csurf module's request handler function to check it, but there is nothing stopping me from writing my own. If this is true, the value of the header doesn't even matter, just that it exists. I am holding off on this option though because I feel there is something basic I'm not understanding about my current setup, which once rectified will mean this can be easily fixed.
Would appreciate any help or explanation! Thanks 🤍

react-jsonp giving a CORB error in a React App

Edit
based on suggestions tried doing it with fetch, now I am getting this
I am trying to get data from gnews.io/api in a simple react app.I am learning React and the solution might have been to easy but I am stuck here and cant figure out what is wrong and I keep getting this error
fetch-jsonp.js:88 Cross-Origin Read Blocking (CORB) blocked cross-origin response https://gnews.io/api/v4/top-headlines?country=us&token=myapi with MIME type application/json.
funny thing is that if I copy this url https://gnews.io/api/v4/top-headlines?country=us&token=MYAPI&callback=jsonp_1642257010280_37644
and paste it in the browser I am getting the desired response.
Would really appreciate any sort of help
this is the useEffect function that is making this api call
React.useEffect(()=> {
async function getNewsdata(country){
try {
let url = `https://www.gnews.io/api/v4/top-headlines?country=pk&token=${API2}`
let response = await fetchJsonp(url)
let result = await response.json()
console.log("News Data:", result)
} catch (error) {
console.log("error loading news data: ", error)
}
}
getNewsdata(props.country.trim())
},[])
Resorting to JSONP is frowned upon nowadays; there are safer alternatives, such as CORS, for cross-origin communication. As the response's content type is application/json, using JSONP will not work anyway because it causes Chrome's CORB feature to kick in.
Why not try to solve whatever CORS issue you seem to be having? I'd be very surprised if the API you're using weren't configured for CORS... A casual inspection of their documentation reveals that you're using the wrong domain, www.gnews.io, instead of gnews.io. The former redirects to the latter, but is not configured for CORS, which explains your CORS troubles.
Once you use the right domain (gnews.io), all your CORS troubles go away. And because there's no longer any need to reach for dirty tricks like JSONP, you can use good old reliable fetch rather than some third-party tool.
React.useEffect(()=> {
async function getNewsdata(country){
try {
let url = `https://gnews.io/api/v4/top-headlines?country=pk&token=${API2}` // gnews.io, not www.gnews.io
let response = await fetch(url) // fetch, not fetchJsonp
let result = await response.json()
console.log("News Data:", result)
} catch (error) {
console.log("error loading news data: ", error)
}
}
getNewsdata(props.country.trim())
},[])

What's the best way to store a HTTP response in Ionic React?

I'm developing an app with Ionic React, which performs some HTTP requests to an API. The problem is I need to store the response of the request in a local storage so that it is accessible everywhere. The way I'm currently doing it uses #ionic/storage:
let body = {
username: username,
password: password
};
sendRequest('POST', '/login', "userValid", body);
let response = await get("userValid");
if (response.success) {
window.location.href = "/main_tabs";
} else if (!response.success) {
alert("Incorrect password");
}
import { set } from './storage';
// Handles all API requests
export function sendRequest(type: 'GET' | 'POST', route: string, storageKey: string, body?: any) {
let request = new XMLHttpRequest();
let payload = JSON.stringify(body);
let url = `http://localhost:8001${route}`;
request.open(type, url);
request.send(payload);
request.onreadystatechange = () => {
if (request.readyState === 4 && storageKey) {
set(storageKey, request.response);
}
}
}
The problem is that when I get the userValid key the response hasn't come back yet, so even awaiting will return undefined. Because of this I have to send another identical request each time in order for Ionic to read the correct value, which is actually the response from the first request. Is there a correct way of doing this other than just setting timeouts everytime I perform a request?
You are checking for the results of storage before it was set. This is because your sendRequest method is calling an asynchronous XMLHttpRequest request, and you are checking storage before the sendRequest method is complete. This can be fixed by making sendRequest async and restructuring your code a bit.
I would suggest you instead look for examples of ionic react using hooks or an API library - like fetch or Axios. This will make your life much easier, and you should find lots of examples and documentation. Check out some references below to get started:
Example from the Ionic Blog using Hooks
Example using Fetch using React
Related Stack Overflow leveraging Axios

AXIOS request method changes to 'OPTIONS' instead of 'GET'

I am trying to call and API with react app(TSX) using Axios(this the first time I am using Axios) every time I run the app the method changes to 'OPTIONS' and the request becomes invalid. Help will be appreciated. Sharing my code sorry I am hiding the Auth Token for security reasons.
Code
import React, { useState, useEffect } from 'react';
import axios from 'axios';
interface Brands {
BrandId: number;
Name: string;
}
const AUTH_TOKEN = Something hiden for security;
var baseUrl = axios.defaults.baseURL = 'https://fppdirectapi-prod.fuelpricesqld.com.au/Subscriber/GetCountryBrands?countryId=21';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.get['Content-Type'] = 'application/json';
axios.defaults.method = 'get';
const FetchFuelType = () => {
const [brands, setPosts] = useState<Brands[]>([]);
useEffect(() => {
axios.get(baseUrl)
.then(res => {
console.log(res)
setPosts(res.data)
})
.catch(err => {
console.log(err)
})
}, [])
return (
<div>
<ul>
{brands.map(Brand => (<li key={Brand.BrandId}>{Brand.Name}</li>))}
</ul>
</div>
);
};
export default FetchFuelType;
Attached image of response
OPTIONS request is part of the so-called preflight request which is needed to figure out the CORS headers to know what needs/is allowed to be sent to the server with the actual GET request. Thats why you normally see two requests in your network tab (depending on your setting)
In your example it seems you have not configured anything CORS related on your server (thus the 405) or specifically have forbidden anything other than GET/POST requests. Or potentially the site has forbidden others to access its data
Usually, options request is sent before get automatically by axios, to get some preliminary data before firing get call. Check this https://github.com/axios/axios/issues/475.
The OPTIONS request is an inherent request generated by browser.
Browser uses the OPTIONS call to find out what methods are allowed by the server.
The API server meant for supporting requests from browser must allow OPTIONS in addition to the actual method (GET / POST / etc).
If the server does not support OPTIONS, then it may not support browser.
A server that does not support OPTIONS can only support non-browser clients
(Examples: REST client in Java / nodejs)
How to solve the problem?
The problem of '405 - OPTIONS method not allowed' can be solved in one of these 2 ways:
Update the server to support OPTIONS method (Recommended for server that is supposed to support browsers)
Develop an 'Intermediary REST client' which will request data from the server, on behalf of the browser
Browser <--> REST client (supports OPTIONS, POST) <--> Actual web service (does not support OPTIONS)

Error when sending POST request from React app to Rocket backend returns failure

I'm writing a simple web with Rocket as backend and React as frontend.
The code snippet looks like this for login page
#[post("/login", data = "<data>")]
pub fn login(
conn: DbConn,
mut cookies: Cookies<'_>,
data: Form<LoginForm>,
) -> Result<JsonValue, NotFound<String>> {
let valid_account = match Account::find_by_email(&*conn, data.email.as_str()) {
Ok(account) => {
if account.password == data.password {
account
} else {
return Err(NotFound("Incorrect email or password!".to_string()));
}
}
Err(_) => return Err(NotFound("Incorrect email or password!".to_string())),
};
cookies.add_private(
Cookie::build(AUTH_COOKIE, valid_account.id.to_string())
.same_site(rocket::http::SameSite::Strict)
.finish(),
);
Ok(json!({
"email": valid_account.email,
"name": valid_account.name,
}))
}
Code for main.rs
fn main() {
rocket::ignite()
.mount("/", routes![
account::login::login,
],
)
.register(catchers![errors::unauthorized])
.attach(rocket_cors::CorsOptions::default().to_cors().unwrap())
.manage(establish_connection())
.launch();
}
and code for React when trying to send the post request
export const postForm = async (
pathUrl: string,
postInfo: { [name: string]: any }
) => {
let axiosConfig = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Access-Control-Allow-Origin': '*',
},
};
try {
const response = await axios.post(
baseUrl + pathUrl,
querystringify.stringify(postInfo),
axiosConfig
);
return response.data as CurrentUser;
} catch (err) {
console.log(err);
return Promise.reject(err.response);
}
};
The code works fine it I enter the correct email and password.
However, it cannot capture the error message if I enter the wrong credentials.
Rocket log are the same between successful login and failure login which are
OPTIONS /login:
=> Error: No matching routes for OPTIONS /login.
=> Warning: Responding with 404 Not Found catcher.
=> CORS Fairing: Turned missing route OPTIONS /login into an OPTIONS pre-flight request
=> Response succeeded.
POST /login application/x-www-form-urlencoded:
=> Matched: POST /login (login)
=> Outcome: Success
=> Response succeeded.
and the error log in browser I captured was Error: "Request failed with status code 404" which was not the expected error message hard coded inside post function.
I believe it has something to do with Option or preflight processed inside Rocket which maybe in the purpose of security. But how can I suppress the system error and let my code to take over?
I have read previous SO post like state undefined: while sending post request from react app and GitHub issues like https://github.com/SergioBenitez/Rocket/issues/25. And still cannot find answer for my problem.
Thanks in advance!
Apparently I made several mistakes here due to unfamiliar with Rocket and React.
List here in case someone made the similar mistakes.
The 404 status code is from the first code snippets Result<JsonValue, NotFound<String>>. So if we write the return type as Result<JsonValue, Unauthorized<String>>, it would return 401 as unauthorized user.
Second, axios only receives json type and cannot parse string (correct me if I'm wrong). So we need to change the return type in server to Result<JsonValue, Unauthorized<JsonValue>>.

Resources