I´m trying to make a POST request to my API, but the CORS policy is blocking the request in the preflight.
I already configured my back-end to accept requests from the front-end origin and to allow all the methods (including OPTIONS and POST).
Here´s my Spring CORS Configuration:
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("https://brazilnews.herokuapp.com", "http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "TRACE", "CONNECT")
.allowedHeaders("append,delete,entries,foreach,get,has,keys,set,values,Authorization")
.allowCredentials(true);
}
Axios Request:
export const api =
axios.create({
baseURL: "http://localhost:8080",
headers: {
"Content-Type": "application/json"
}
});
export const auth = async (email, senha) => {
const body = {
email: email,
senha: senha
}
const res = await api.post("/auth", body)
.then(res => {
console.log(res.data);
}).catch(err => {
console.error(err);
});
return res;
}
Request/Response details:
Console
Solved it by adding this line in the SecurityConfigurations
antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
Related
I have a REST API in ruby on rails and i'm using it with a React frontend and need to get the Authorization header from request response when a user sign in. However i can't acess it, i've exposed the headers already in the rack-cors config file but it still not coming.
Rack-Cors config:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
expose: %w[access-token expiry token-type uid client Authorization],
methods: %i[get post put delete options]
end
end
Request function:
import axios from "axios";
export const api = axios.create({
baseURL: "http://localhost:3000/api/v1",
withCredentials: false,
headers: {
"Content-type": "application/json",
'X-Requested-With': 'XMLHttpRequest',
"Accept": "*/*",
}
});
export const createSession = async (email, password) => {
return api.post('/auth/sign_in', {email, password})
};
Calling the request:
const login = async (email, password, logar) => {
const response = await createSession(email, password);
console.log(response);
const loggedUser = {
"id": response.data.data.id,
"nome": response.data.data.nome,
"email": response.data.email
};
localStorage.setItem("user", JSON.stringify(loggedUser));
setUser(loggedUser);
logar();
navigate('/principal');
};
The response:
I hope somebody could help me, thanks!
I'm posting data to a DynamoDB table with axios in a React front-end.
The API is set up through a serverless configuration with an API Gateway and Lambda on AWS.
While the request goes through and I see the added item on the database I still get a CORS error https://i.stack.imgur.com/m7yMG.jpg
This is the axios method:
import axios from "axios";
export const sendItemToDB = async (_data) => {
if (!_data) { return };
try {
const res = await axios({
method: "POST",
url: process.env.REACT_APP_QUERY_API,
data: _data,
headers: {
"Content-Type": "text/plain"
},
});
console.log("data returned from api", res);
} catch (error) {
console.log("Error sending File to db: ");
console.log(error);
}
};
And the API method on Lambda:
const createRecord = async (event) => {
const response = { statusCode: 200 };
try {
const body = JSON.parse(event.body);
const params = {
TableName: process.env.DYNAMODB_TABLE_NAME,
Item: marshall(body || {}),
};
const createResult = await db.send(new PutItemCommand(params));
response.body = JSON.stringify({
message: "Successfully created record.",
createResult,
});
} catch (e) {
console.error(e);
response.statusCode = 500;
response.body = JSON.stringify({
message: "Failed to create record.",
errorMsg: e.message,
errorStack: e.stack,
});
}
return response;
};
I based this configuration on this tutorial : https://github.com/jacksonyuan-yt/dynamodb-crud-api-gateway
I solved this following amazon documentation and reconfiguring the serveless deployment yml.
Serverless documentation on api gateway and lambda proxy integration here
Adding the missing headers to all lambda functions was essential.
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Headers" : "Content-Type",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
},
};
Also testing that OPTIONS is working for the preflight:
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-test-cors.html
Just as Stavros noticed, the problem is that this is not a simple cross-origin POST method request (because it contains custom headers), so you need to tweak CORS settings of AWS API Gateway by adding
"POST, GET & OPTIONS" for Access-Control-Allow-Methods
"content-type" for Access-Control-Allow-Headers
You can do it through console like this
You also might need to add those headers in lambda like this
and it will work.
I am trying to set up authentication with Remix as my pure frontend and a django backend.
When the user signs in successfully, the backend sends a cookie with the response and this is set in the browser redirect with remix
const signIn = async (credentials: LoginCreds) => {
try {
const response = await fetch(generateFullBackendUrl('/auth/signin'), {
method: 'POST',
body: JSON.stringify(credentials),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
credentials: 'include'
});
return response;
} catch (e) {
console.log(e);
}
}
const response = await authService.signIn({
email,
password
})
const cookies = response?.headers.get('set-cookie');
if(cookies){
return redirect('profile', {
headers: {
'Set-Cookie': cookies
}
});
However when I try to make subsequent fetch calls in my loader the cookies are not sent to the backend as I would expect the browser would
await fetch(generateFullBackendUrl('api/users/me'), {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
credentials: 'include'
})
Front end is running on port 3000
Backend running on port 4000
Im wondering why the fetch request in the loader does not send the cookies with the request
You need to read the cookie header from the loader request and pass it to your fetch headers.
There’s no way Fetch can automatically know what headers to send when used server side.
There is a quick workaround but not so elegant solution:
in your loader use this:
export const loader: LoaderFunction = async({request}) => {
const response = await fetch(`/api/books?${new URLSearchParams({
limit: '10',
page: '1',
})}`, {
headers: {
'Cookie': request.headers.get('Cookie') || ''
}
});
console.log(response)
if(response.ok) return await response.json();
}
I am trying to write function to Sign in user with Email and Password.
Using Axios and firebase rest API.
So this is how Axios instance looks like, really simple right? ...
const authUrl = `https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${DATABASE_SECRET}`;
const baseURL = "https://beauty-wonderland-e913c-default-rtdb.firebaseio.com";
export const getAxios = (token = null) => {
const config = {
baseURL: baseURL,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "DELETE, POST, GET, OPTIONS",
"Access-Control-Allow-Headers":
"Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With",
},
timeout: 10000,
};
if (token !== null) {
// config.headers.Authorization = `Bearer ${token}`;
config.baseURL = authUrl;
config.withCredentials = true;
}
let instance = axios.create(config);
instance.interceptors.request.use(
(request) => {
return request;
},
(error) => {
console.log("axios error: ", error);
return Promise.reject(error);
}
);
instance.interceptors.response.use((response) => {
return response;
});
return instance;
};
This code works fine, flexible and can send any kind of request, but when it comes to authentication, there is problem with sending user data: email and password.
const loginHandler = async () => {
const response = await getAxios("/").post("", {
body: JSON.stringify({
email: "example#example.com",
password: "password",
returnSecureToken: true,
}),
});
const outPut = processResponse(response);
console.log(outPut);
}
so as i guess There is problem with this part
{
body: JSON.stringify({
email: "a#a.com",
password: "123456",
returnSecureToken: true,
}),
});
}
if fetch function works this way
fetch(
`https://identitytoolkit.googleapis.com/v1/accounts:signInWithPasswordkey=${DATABASE_SECRET}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: "example#example.com",
password: "password",
returnSecureToken: true,
}),
}
);
why do axios gives following error:
XMLHttpRequest at ... from origin 'http://localhost:19006' 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.
Please note other get and post request with axios works, and alo authentication works with fetch, only axios shows such an error, please post additional resourses to learn more about firebase rest API and Axios usecases.
This is how error looks like
The baseURL in the axios instance returned by "getAxios" function is https://beauty-wonderland-e913c-default-rtdb.firebaseio.com and not the Auth REST API url. It should be authUrl instead. While in fetch you have hard-coded the URL so the URL is correct for sure.
Edit:
Remove those extraneous headers. You just need content-type as per the docs. I got the same CORS error when I had those.
const config = {
baseURL: baseURL,
headers: {
"Content-Type": "application/json",
},
timeout: 10000,
};
I am using react as a front-end and asp.net core as a back-end. I am using fetch API for API request but I am getting Cors error on the browser console saying: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://localhost:44316/api/auth/register. (Reason: CORS request did not succeed).
My ConfigureServices method is:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("myPolicy", builder =>
{
builder.WithOrigins("http://localhost:3000")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
services.AddSignalR();
services.AddDbContext<UserContext>(options => options.UseSqlServer(Configuration.GetConnectionString(name: "Default")));
services.AddControllers();
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IJwtHelper, JwtHelper>();
}
And the Configure method is:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseCors("myPolicy");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<ChatHub>("/chat");
});
}
In react I created a form submit event and its looks like:
const submitRegisterForm = async (e) => {
e.preventDefault();
await fetch(
"https://localhost:44316/api/auth/register",{
method: 'POST',
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
name,
email,
password,
role,
})
});
setRedirectTo(true);
};
This the output I am getting in Brower network tab:
Try as follows
In your ConfigureServices method
services.AddCors(options =>
{
options.AddPolicy("ClientPermission", policy =>
{
policy.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed(_ => true)
.AllowCredentials();
});
});
and in your Configure method
app.UseCors("ClientPermission");
On the client side for localhost request use http and not https
const submitRegisterForm = async (e) => {
e.preventDefault();
try {
const res = await fetch(
"http://localhost:44316/api/auth/register",{
method: 'POST',
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
name,
email,
password,
role,
})
});
setRedirectTo(true);
}
catch(err){
console.log(err)
}
};
The placement order codes in asp.net core v6 should be as follows in program.cs
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.UseAuthentication();
app.UseAuthorization();
Also in front and in jsx you should send the headers as follow:
"Content-Type": "application/json",
"Accept": 'application/json',
"authorization": "Bearer " + token,
"Access-Control-Allow-Origin": "*",