CORS Error trying to access API gateway that triggers a Lambda function from NextJS App with Axios - axios

I have this Lambda function that can be triggered by API Gateway configured with the Serverless framework. The error I get on Access to XMLHttpRequest at '<THE_ENDPOINT>' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response This is how I use Axios in the Next App:
const handleSignUp = async (email, password) => {
const response = await Axios.post(
`${API}/signup`,
{
email,
password,
},
{
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
}
);
console.log(response);
};
This is my serverless.yml config file. I have tried to enable CORS manually from API Gateway console, but this is what it looks like.. When I make request with POSTMAN, it works normally.

Access-Control-Allow-Origin doesn't belong on the request header. It belongs on the response from the server, not part of the request from the browser. Adding it to the request is trying to tell the server what origins are allowed, but it's the server's job to say from where it will accept requests.
The Preflight Response is a clue that it's erroring out on the Options method.
I believe it's failing because you are trying to pass a header to the Options method that it's not looking for / isn't allowed. Try removing that header from the axios request and adding it to the APIGW response instead.
Under the Options method, check the Method Response and make sure you have Access-Control-Allow-Origin added to the Response Headers. Still on the Options method, check the Integration Response Header Mappings and add your allowed origin '*' (or a specific domain).
Don't forget to deploy your changes and wait a few moments for the change to propagate before testing.

Related

How my browser extension can periodically refresh file from GitHub rawcontent?

In background.js, my browser extension periodically fetches a JSON file published in a GitHub public repository.
Now I want it to be nicer to GitHub and its bandwidth limits, and only fetch file again if it was modified since last update:
url='https://raw.githubusercontent.com/LearnWebCode/json-example/master/pets-data.json';
fetch(url, {
headers: {'If-Modified-Since': 'Wed, 15 Aug 2022 18:30:00 GMT'}})
.then(response => response.json())
.then(json => console.log('Loaded: ', json));
However I get CORS error I don't understand how to deal with:
Access to fetch at
'https://raw.githubusercontent.com/LearnWebCode/json-example/master/pets-data.json'
from origin 'chrome-extension://...'
has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
It does not have HTTP ok status.
Adding either combination of other headers doesn't make difference:
'Content-Type': 'text/plain;charset=UTF-8'
'Accept': 'application/vnd.github.v3.raw'
'User-Agent': 'my_github_username/my_github_repository (Chrome 104.0.5112.79)'
Neither does using GitHub Pages as an alternative way to access the file.
Update: I easily eliminated CORS error adding raw.githubusercontent.com to host_permissions in manifest.json (thanks #wOxxOm). However now If-Modified-Since doesn't seem to be affect server behavior in the way I expect, see followup question with details.
Because your request contains an If-Modified-Since header, the browser triggers CORS preflight. However, the resource, despite responding to GET requests with Access-Control-Allow-Origin: *, doesn't seem to support preflight: if you try to spoof a preflight request, it invariably (according to my tests) replies with a 403 status, which is sufficient for CORS preflight to fail.
The resource does respond with an ETag header. One approach would consist in sending a simple HEAD request first, read the value of the response's ETag header, and conditionally send a GET request after that. Unfortunately, because ETag is not a CORS-safelisted response-header name and the response doesn't contain any Access-Control-Expose-Headers header, the browser won't expose the response's ETag header to JavaScript. Very sad.
Short of pressuring GitHub into adding support for CORS preflight on https://raw.githubusercontent.com, a viable, albeit annoying, alternative would be to proxy your original GET request (containing the If-Modified-Since header) to a server you control, which would be unconstrained by the Same-Origin Policy.

Flutter Web - Request Headers missing

I run the exact same code on Android and Web by using Dio for sending requests and what I see is that my backend doesn't get my custom added headers when I send the request from browser, but everything works fine if I do the same from emulator.
CORS is correctly setup on my backend.
Dio dio = Dio();
dio.options.headers[HttpHeaders.authorizationHeader] = "Bearer $token";
final Response response = await dio.get("http://$host:$port/$path", queryParameters: {"searchText": searchQuery, "page": 0, "pageSize": 100});
Additional information
post request works fine, the header is only missing from get requests. Either I use the http or dio packages.
However I can see in my server logs the following line when I log out all the headers of the request:
headerName: access-control-request-headers
header: authorization
Has anyone seen something similar?
As it seems I had to enable cors in spring security separatelly.
httpSecurity.csrf().disable()
.cors().and()
.authorizeRequests()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/support/**").hasRole("SUPPORT")
.antMatchers("/**").permitAll()
.and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter::class.java)
Once I did so everything started to work.
So to sum up,
I used my custom headers in other places those were handled by my global CorsFilter but headers related to spring-security like Authorization are handled by spring-security so cors has to be enabled there as well regardles if I added Authorization to my global CorsFilter or not.

axios causing an unintended OPTIONS request on HERE Autocomplete api

I am getting a preflight error 405: Method not allowed from the HERE API when I request autocomplete as per the documentation.
UPDATE 2:
I have since determined that Axios was adding my default.common authentication headers from my app's API client onto the HERE API client. Axios is supposed to keep those defaults separate per-client, but it seems that it doesn't ... at least not the version I have. I replaced the defaults with a per-client request interceptor and it worked fine. The request no longer triggers an OPTION pre-flight. No issue with HERE's API other than that it doesn't support OPTION method.
UPDATE:
The reason it fails is because HERE does not support the OPTIONS method, only the GET. So now the question is: Why does axios trigger an OPTIONS request when I don't set any headers? An XMLHttpRequest() based GET request does not trigger OPTIONS for the same URL. Something is happening with axios but I don't know what and I can't seem to investigate the headers that axios is sending.
ORIGINAL:
I've tried to find information about this error, as well as HTTP vs HTTPS. I haven't seen others having this problem so I feel like I must be making a simple error. The URL is generated correctly because it works when pasted directly into the browser for example.
const hereClient = axios.create({
baseURL: 'https://autocomplete.geocoder.api.here.com/6.2/'
})
async function searchHere (query) {
let searchTerms = query.split(' ').join('+')
let result = await hereClient.get('suggest.json', {
params: {
app_id: '<APPID>',
app_code: '<APPCODE>',
query: searchTerms
}
})
return processHereSearchResults(result.data)
}
The GET request fails on the OPTION preflight with a 405: Method not allowed. But if I paste the generated URL into a browser then it returns the expected results. For example:
https://autocomplete.geocoder.api.here.com/6.2/suggest.json?app_id=APPID&app_code=APPCODE&query=8131
returns:
{"suggestions":[{"label":"Česko, Brandýs nad Orlicí, 3123","language":"cs","countryCode":"CZE","locationId":"N . . .
Same result whether http or https.
I have since determined that Axios was adding my default.common authentication headers from my app's API client onto the HERE API client. Axios is supposed to keep those defaults separate per-client, but it seems that it doesn't ... at least not the version I have. I replaced the default header setting with a per-client request interceptor to set my authentication and it worked fine. The request no longer triggers an OPTION pre-flight. No issue with HERE's API other than that it doesn't support OPTION method.

Cors in Ajax Meet 302 Redirect

I have a front-end server with port 8081
a background server with port 8080(Spring MVC + shiro)
When I send a request to 8080, I have to set the cors headers on 8080
If the request is a simply request which only returns some json datas, it works
But When the response status is 302, Chrome shows
Redirect from 'http://localhost:8080/' to 'http://localhost:8080/' has
been blocked by CORS policy: No 'Access-Control-Allow-Origin' header
is present on the requested resource.
I thought there are two reasons to occur this problem:
① if I intercept this 302 status, and deal this response.headers.Location,
I will solve this. But I can't intercept this response(with axios)
② Maybe some settings is wrong with 8080 server, when 302 occurs, the serve haven't set the cors Headers for this page. But I don't understand the backend code.
So, ① is feasible? or I need to change the settings on 8080 server?
CORS cross-domain will send a request to the OPTIONS in advance, this request does not attach tokens, this leads to shiro intercepted request to determine the current user is not logged in, causing problems, the solution is to inherit FormAuthenticationFilter.
#Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
boolean allowed = super.isAccessAllowed(request, response, mappedValue);
if (!allowed) {
String method = WebUtils.toHttp(request).getMethod();
if (StringUtils.equalsIgnoreCase("OPTIONS", method)) {
return true;
}
}
return allowed;
}

CORS response for request with unsupported methods

I am wondering how server should respond for CORS request that asks for unsupported method.
I have server endpoint, lets say server.com/endpoint which supports only GET. But client is sending CORS OPTIONS request with headers:
Origin: another.com
Access-Control-Request-Method: POST
How proper response should look? Should it return some error message about unsupported POST method, or just return 200 OK with typical CORS response headers like:
Access-Control-Allow-Methods: GET
Access-Control-Allow-Origin: another.com
Or maybe I should treat it as request without CORS headers?
Also what should be returned in case of some random origin in request? Should i reveal which origins are allowed or keep it hidden and return no "Allow" headers?
I am wondering how server should respond for CORS request that asks for unsupported method.
I have server endpoint, lets say server.com/endpoint which supports only GET. But client is sending CORS OPTIONS request with headers:
Origin: another.com
Access-Control-Request-Method: POST
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests explains what’s happening: That OPTIONS is an expected request that browsers on their own automatically send as part of the CORS protocol.
How proper response should look? Should it return some error message about unsupported POST method
No, supporting the CORS protocol as expected on your server side doesn’t require you to send any special error response for this case. The browser just interprets the lack of "Allow" headers in the normal response as meaning that the server doesn’t allow the type of request it’s received.
or just return 200 OK with typical CORS response headers like:
Access-Control-Allow-Methods: GET
Access-Control-Allow-Origin: another.com
That would be the right way to respond to it as far as supporting CORS as expected for the case where you get a request from the allowed origin another.com but for an unsupported method (e.g., POST, if you don’t support that). That enables the browser to log a specific CORS error on the client side to let the developer know the non-allowed method is the problem, not the origin.
Also what should be returned in case of some random origin in request? Should I reveal which origins are allowed or keep it hidden and return no "Allow" headers?
You can just return no "Allow" headers in the case of a non-allowed origin. There’s never any need to reveal what origins are allowed, except to allowed origins. (Anyway, the Access-Control-Allow-Origin value is always just going to contain either a single origin, or else the * wildcard, so no random origin making a request is going to be able to sniff out all the allowed origins.)
And to be clear, the CORS protocol in no way requires servers to respond to random non-allowed origins with any CORS headers at all. The semantics of the protocol are such that to a browser, a response with no "Allow" headers at all means, “This server does not allow cross-origin requests from your origin”. A random non-allowed origin doesn’t need any more information than just that.