I'm building a frontend app with React and Redux and I'm using axios to perform my requests. I would like to get access to all the fields in the header of the response. In my browser I can inspect the header and I can see that all the fields that I need are present(such as token, uid, etc...), but when I call
const request = axios.post(`${ROOT_URL}/auth/sign_in`, props);
request.then((response)=>{
console.log(response.headers);
});
I get just
Object {content-type: "application/json; charset=utf-8", cache-control: "max-age=0, private, must-revalidate"}
Here my browser network tab,as you can see all the other fields are present.
Bests.
In case of CORS requests, browsers can only access the following response headers by default:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
If you would like your client app to be able to access other headers, you need to set the Access-Control-Expose-Headers header on the server:
Access-Control-Expose-Headers: Access-Token, Uid
This really helped me, thanks Nick Uraltsev for your answer.
For those of you using nodejs with cors:
...
const cors = require('cors');
const corsOptions = {
exposedHeaders: 'Authorization',
};
app.use(cors(corsOptions));
...
In the case you are sending the response in the way of res.header('Authorization', `Bearer ${token}`).send();
I was facing the same problem. I did this in my WebSecurity.java, it's about the setExposedHeaders method in the CORS configuration.
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.setAllowedOrigins(Arrays.asList(FRONT_END_SERVER));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
configuration.setAllowedHeaders(Arrays.asList("X-Requested-With","Origin","Content-Type","Accept","Authorization"));
// This allow us to expose the headers
configuration.setExposedHeaders(Arrays.asList("Access-Control-Allow-Headers", "Authorization, x-xsrf-token, Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, " +
"Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
I hope it works.
Faced same problem in asp.net core
Hope this helps
public static class CorsConfig
{
public static void AddCorsConfig(this IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.WithExposedHeaders("X-Pagination")
);
});
}
}
According to official docs:
This may help if you want the HTTP headers that the server responded with. All header names are lower cased and can be accessed using the bracket notation. Example: response.headers['content-type'] will give something like: headers: {},
There is one more hint that not in this conversation.
for asp.net core 3.1
first add the key that you need to put it in the header, something like this:
Response.Headers.Add("your-key-to-use-it-axios", "your-value");
where you define the cors policy (normaly is in Startup.cs) you should add this key to WithExposedHeaders like this.
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.AllowAnyHeader()
.AllowAnyMethod()
.AllowAnyOrigin()
.WithExposedHeaders("your-key-to-use-it-axios"));
});
}
you can add all the keys here.
now in your client side you can easily access to the your-key-to-use-it-axios by using the response result.
localStorage.setItem("your-key", response.headers["your-key-to-use-it-axios"]);
you can after use it in all the client side by accessing to it like this:
const jwt = localStorage.getItem("your-key")
Custom HTTP headers can not be accessed on client-side due to CORS restrictions. You need to add Access-Control-Expose-Headers setting on the server-side.
What are Access-Control-Expose-Headers?
Please go to https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
By default only these HTTP headers are exposed:
Cache-Control
Content-Language
Content-Length
Content-Type
Expires
Last-Modified
Pragma
For custom HTTP headers, you need to customize Access-Control-Expose-Headers in response headers.
If you are using Django on the server side you can use django-cors-headers (https://pypi.org/project/django-cors-headers/) for CORS settings management.
For example, with django-cors-headers you can add a list of HTTP headers that are to be exposed to the browser by CORS_ALLOW_HEADERS setting
from corsheaders.defaults import default_headers
CORS_ALLOW_HEADERS = list(default_headers) + [
'my-custom-header',
]
In case you're using Laravel 8 for the back-end side with CORS properly configured, add this line to config/cors.php:
'exposed_headers' => ['Authorization'],
In axios CORS requests, browsers can access only few headers by default.
But if you need to access a custom header from response, you have to send response with Access-Control-Expose-Headers form your backend server.
Hare is a example for Nodejs backend and Reactjs front end:
res.header('Access-Control-Expose-Headers', 'x-xsrf-token');
return res.header("x-xsrf-token", token).status(200)
.send({
id: user.id,
email: user.email,
});
res.header('Access-Control-Expose-Headers', 'x-xsrf-token');
for this line I can log my custom header like
axios.post("/login", {
email: emailInput.current.value,
password: passwordInput.current.value,
})
.then(function (response) {
console.log(response.headers["x-xsrf-token"]);
});
Without Access-Control-Expose-Headers in your response you will get undefine in console log. Check your response header in network tab that it contains the header with your custom name with it.
For the SpringBoot2 just add
httpResponse.setHeader("Access-Control-Expose-Headers", "custom-header1, custom-header2");
to your CORS filter implementation code to have whitelisted custom-header1 and custom-header2 etc
try like this
.then(res =>{
console.log(res);
console.log(res.headers['x-total-count']);
setTotalRecords(res.headers['x-total-count']);
setTableData(res.data);
});
for django help
CORS_EXPOSE_HEADERS = [
'your header'
]
For Spring Boot 2 if you don't want to use global CORS configuration, you can do it by method or class/controller level using #CrossOrigin adnotation with exposedHeaders atribute.
For example, to add header authorization for YourController methods:
#CrossOrigin(exposedHeaders = "authorization")
#RestController
public class YourController {
...
}
If you are using Django without django-cors-headers, you can write custom middleware.
class CustomCorsMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response['Access-Control-Expose-Headers'] = 'MY-HEADER, ANOTHER-HEADER'
return response
You can also set other CORS heades here.
Then you should register your middleware by inserting it at the beggining of the MIDDLEWARE list in your project's settings.py file.
MIDDLEWARE = [
'myapp.middleware.CustomCorsMiddleware',
...
]
[expanding on what #vladimir said]
if you're using Django
and django-cors-headers to allow/control CORS,
you should set the following, in your settings.py
CORS_EXPOSE_HEADERS = ['yourCustomHeader']
Related
I'm writing a full stack app. I have a python backend using flask that sends a file and a Vue client that receives. Its been working fine up until the point when I try to send the filename over using a Content-Disposition header.
On the backend I've tried:
return send_file(base_path + filename, as_attachment=True, download_name=filename)
And to set the headers manually,
response = make_response(send_file(base_path + filename))
response.headers['Content-Disposition'] = f"attachment; filename=\"{filename}\""
return response
I've also tried to put in headers that would not be blocked by CORS just to see if the request would receive the header but to no avail,
response = make_response(send_file(base_path + filename))
response.headers['Content-Type'] = "sample/info"
return response
I'm printing the header to the console by doing
fetch('http://localhost:4999/rdownload/' + this.$route.params.id, {
method: 'GET'
}).then(res =\> {
if (res.status == '500') { }
console.log(res.headers)
//const header = res.headers.get('Content-Disposition');
//console.log(header)
res.blob().then((blob) => {
/* ... */
})
})
Any help would be appreciated! Thanks :)
Research
In the interest of logging the solution I found and helping out anyone in the future who may be interested in knowing the answer here's what I discovered:
There is a restriction to access response headers when you are using Fetch API over CORS.
https://stackoverflow.com/a/44816592/20342081
So, no matter what using the JS fetch-api you will be unable to access all headers (outside of Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, and Pragma) unless you expose them by specifying them in a request header. That would look something like this:
fetch('https://myrequest/requestend/', {
headers: {
'Access-Control-Expose-Headers': 'Content-Disposition'
}
})
When a cross-origin source accesses your API you will have to expose the header from the back end as well. https://stackoverflow.com/a/66291644/20342081
I was also confused about how the differences between Access-Control-Expose-Headers and Access-Control-Allow-Headers. In my case the solution was use "expose headers" on both the frontend and the backend (and allow wouldn't work). However, Allow has its own applications which I have yet to understand fully. For those endeavoring check out: https://stackoverflow.com/a/28108431/20342081
Solution
I implemented these things in my code by doing:
class RequestResult(Resource):
def get(self, index):
base_path = f"Requests/{index}/"
filename = os.listdir(base_path)[0]
response = make_response(send_file(base_path + filename, as_attachment=True, download_name=filename))
response.headers['Access-Control-Expose-Headers'] = "Content-Disposition"
return response
And on the front end exposing the header as well on the fetch request:
fetch('http://localhost:4999/rdownload/' + this.$route.params.id, {
method: 'GET',
mode: 'cors',
headers: {
'Access-Control-Expose-Headers': 'Content-Disposition'
}
})
I hope this is helpful for the next 5 people who open this in the next 10 years!
I have an application based FastAPI Which serves as the backend for a website And currently deployed on a server with an external IP. The frontend is situated at another developer, temporarily in local hosting.
At the beginning of the work we encountered a CORS problem, which was solved by using the following code I found on the Internet:
from fastapi.middleware.cors import CORSMiddleware
...
app.add_middleware(
CORSMiddleware,
allow_origins=['http://localhost:3000'],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
The addition allowed Frontend to make requests properly, but for some reason, cookies that are set to send (and work properly in the Swagger UI) are not set in Frontend.
The client side look like:
axios({
method: 'POST',
baseURL: 'http://urlbase.com:8000',
url: '/login',
params: {
mail: 'zzz#zzz.com',
password: 'xxxxxx'
},
withCredentials: true
}).then( res => console.log(res.data) )
.catch( err => console.log(err))
Setting and reading cookies in FastAPI can be done through the use of the Request class:
Setting the cookie refresh_token
from fastapi import Response
#app.get('/set')
async def setting(response: Response):
response.set_cookie(key='refresh_token', value='helloworld', httponly=True)
return True
Setting httponly=True makes sure the cookie can't be accessed by JS. This is great for sensitive data such as a refresh token. But if your data isn't that sensitive then you can just omit it.
Reading the cookie
from fastapi import Cookie
#app.get('/read')
async def reading(refresh_token: Optional[str] = Cookie(None)):
return refresh_token
You can find more information on using cookies as parameters on the FastAPI docs here.
Remove the wildcards since wildcarding is not allowed with allow_credentials=True :
app.add_middleware(
CORSMiddleware,
allow_origins=['http://localhost:3000'],
allow_credentials=True,
allow_methods=["GET", "POST", "OPTIONS"], # include additional methods as per the application demand
allow_headers=["Content-Type","Set-Cookie"], # include additional headers as per the application demand
)
Set samesite to none while setting the cookie:
# `secure=True` is optional and used for secure https connections
response.set_cookie(key='token_name', value='token_value', httponly=True, secure=True, samesite='none')
If client side is using Safari, disable Prevent cros-site tracking in Preferences. That's It!
For Cross-Origin Situation Cookie Setting, Check things below 👇🏻
Pre-requirements
Your FE, BE servers need to talk each other with https protocol. (Set SSL Certificates using let's encrypt or other services)
Make sure your domain doesn't include port
Backend
Server Setup
Add FE Domain to allow_origins
Set allow_credentials True
allowed_methods should not be a wildcard("*")
allowed_headers should not be a wildcard("*")
Cookie Setup
secure = True
httponly = True
samesite = 'none'
List item
Fastapi Example
# main.py
app.add_middleware(
CORSMiddleware,
allow_origins=settings.ALLOWED_ORIGINS,
allow_credentials=True,
allow_methods=["GET", "POST", "HEAD", "OPTIONS"],
allow_headers=["Access-Control-Allow-Headers", 'Content-Type', 'Authorization', 'Access-Control-Allow-Origin'],
)
# cookie
response = JSONResponse(content={"message": "OK"})
expires = datetime.datetime.utcnow() + datetime.timedelta(days=30)
response.set_cookie(
key="access_token", value=token["access_token"], secure=True, httponly=True, samesite='none', expires=expires.strftime("%a, %d %b %Y %H:%M:%S GMT"), domain='.<YOUR DOMAIN>'
)
Frontend
Include header "Access-Control-Allow-Origin": ""
Set withCredentials: true
Axios Example
// post request that sets cookie
const response = await axios.post(
"https://<Target Backend API>",
{
param1: "123",
param2: "456",
},
{
headers: {
"Access-Control-Allow-Origin": "https://<FE DOMAIN>",
},
withCredentials: true,
},
);
Reverse Proxy Server (If you have)
Allow "OPTIONS" method (this is need when browser check server options in preflight request)
Check if any middlewares blocks your preflight requests. (e.g. Nginx Basic HTTP Authentications can block your request)
IMPORTANT
if your FE use subdomain like dev.exmaple.com and your BE also use subdomain like api.example.com, you should set cookie domain to .example.com so the subdomain services can access root domain cookie!!
In FastAPI you can set cookies via response.set_cookie,
from fastapi import FastAPI, Response
app = FastAPI()
#app.post("/cookie-and-object/")
def create_cookie(response: Response):
response.set_cookie(key="fakesession", value="fake-cookie-session-value")
return {"message": "Come to the dark side, we have cookies"}
It should be noted though that these are NOT SECURE SESSIONS you should use something like itsdangerous to create encrypted sessions.
In response to the requests not seeming to not be sent; You should make sure the option for which urls the cookies are valid for are being set.
By default they are typically / which means everything however your system might be setting them to a specific case with CORS setup.
Yes, I know what you are thinking - yet another CORS question, but this time I'm stumped.
So to start off, the actual error message:
XMLHttpRequest cannot load http://localhost/Foo.API/token. The
value of the 'Access-Control-Allow-Origin' header in the response must
not be the wildcard '*' when the request's credentials mode is
'include'. Origin 'http://localhost:5000' is therefore not allowed
access. The credentials mode of requests initiated by the
XMLHttpRequest is controlled by the withCredentials attribute.
I'm not sure what is meant by credentials mode is 'include'?
So when I perform the request in postman, I experience no such error:
But when I access the same request through my angularjs web app, I am stumped by this error. Here is my angualrjs request/response. As you'll see the response is OK 200, but I still receive the CORS error:
Fiddler Request and Response:
The following image demonstrates the request and response from web front-end to API
So based on all the other posts I've read online, it seems like I'm doing the right thing, that's why I cannot understand the error. Lastly, here is the code I use within angualrjs (login factory):
CORS Implementation in API - Reference purposes:
Method 1 used:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
EnableCrossSiteRequests(config);
}
private static void EnableCrossSiteRequests(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("*", "*", "*")
{
SupportsCredentials = true
};
config.EnableCors(cors);
}
}
Method 2 used:
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuth(app);
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
The issue stems from your Angular code:
When withCredentials is set to true, it is trying to send credentials or cookies along with the request. As that means another origin is potentially trying to do authenticated requests, the wildcard ("*") is not permitted as the "Access-Control-Allow-Origin" header.
You would have to explicitly respond with the origin that made the request in the "Access-Control-Allow-Origin" header to make this work.
I would recommend to explicitly whitelist the origins that you want to allow to make authenticated requests, because simply responding with the origin from the request means that any given website can make authenticated calls to your backend if the user happens to have a valid session.
I explain this stuff in this article I wrote a while back.
So you can either set withCredentials to false or implement an origin whitelist and respond to CORS requests with a valid origin whenever credentials are involved
If you are using CORS middleware and you want to send withCredentials boolean true, you can configure CORS like this:
var cors = require('cors');
app.use(cors({credentials: true, origin: 'http://localhost:5000'}));
Customizing CORS for Angular 5 and Spring Security (Cookie base solution)
On the Angular side required adding option flag withCredentials: true for Cookie transport:
constructor(public http: HttpClient) {
}
public get(url: string = ''): Observable<any> {
return this.http.get(url, { withCredentials: true });
}
On Java server-side required adding CorsConfigurationSource for configuration CORS policy:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
// This Origin header you can see that in Network tab
configuration.setAllowedOrigins(Arrays.asList("http:/url_1", "http:/url_2"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
configuration.setAllowedHeaders(Arrays.asList("content-type"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()...
}
}
Method configure(HttpSecurity http) by default will use corsConfigurationSource for http.cors()
If you're using .NET Core, you will have to .AllowCredentials() when configuring CORS in Startup.CS.
Inside of ConfigureServices
services.AddCors(o => {
o.AddPolicy("AllowSetOrigins", options =>
{
options.WithOrigins("https://localhost:xxxx");
options.AllowAnyHeader();
options.AllowAnyMethod();
options.AllowCredentials();
});
});
services.AddMvc();
Then inside of Configure:
app.UseCors("AllowSetOrigins");
app.UseMvc(routes =>
{
// Routing code here
});
For me, it was specifically just missing options.AllowCredentials() that caused the error you mentioned. As a side note in general for others having CORS issues as well, the order matters and AddCors() must be registered before AddMVC() inside of your Startup class.
If it helps, I was using centrifuge with my reactjs app,
and, after checking some comments below, I looked at the centrifuge.js library file, which in my version, had the following code snippet:
if ('withCredentials' in xhr) {
xhr.withCredentials = true;
}
After I removed these three lines, the app worked fine, as expected.
Hope it helps!
I am building an app which uses a Lumen API. On the Lumen project I have two files which I found on the internet whilst looking up how to handle CORS in Lumen.
CorsMiddleware.php:
<?php
namespace App\Http\Middleware;
class CorsMiddleware {
public function handle($request, \Closure $next)
{
$response = $next($request);
$response->header('Access-Control-Allow-Methods', 'HEAD, GET, POST, PUT, PATCH, DELETE');
$response->header('Access-Control-Allow-Headers', $request->header('Access-Control-Request-Headers'));
$response->header('Access-Control-Allow-Origin', '*');
return $response;
}
}
CatchAllOptionsRequestsProvider.php:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
/**
* If the incoming request is an OPTIONS request
* we will register a handler for the requested route
*/
class CatchAllOptionsRequestsProvider extends ServiceProvider {
public function register()
{
$request = app('request');
if ($request->isMethod('OPTIONS'))
{
app()->options($request->path(), function() { return response('', 200); });
}
}
}
These two files fixed my initial CORS issue. I am able to perform a GET and receive data from the API. But when I try a POST method to the API I once again get the following error: "No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8100' is therefore not allowed access."
Upon inspecting the network tab in chrome, There are two requests. The first is an OPTIONS request, which I believe is just to get the allowed headers from the server. The second request is my POST request with the correct payload. They both return a status code of 200 OK but I still get the Access-Control error mentioned above.
It works when using POSTMAN to send data to my API, but not when I use Ionic Serve in the browser
For those who are wondering, I am using Ionic's $http method for the call:
MORE CODE.......
var req = {
method: 'POST',
url: APIUrl + 'register',
timeout: timeout.promise,
data: {"name": "Michael"}
}
$http(req).then(function(res) {
.......MORE CODE
Might it be something to do with the server apache config? I have mod_rewrite enabled.
Any help on this would be greatly appreciated. Thanks
If you are in control of the server, you might need to set the required headers there. Depending on which server, this might help:
http://enable-cors.org/server.html
I have a setup involving
Frontend server (Node.js, domain: localhost:3000) <---> Backend (Django, Ajax, domain: localhost:8000)
Browser <-- webapp <-- Node.js (Serve the app)
Browser (webapp) --> Ajax --> Django(Serve ajax POST requests)
Now, my problem here is with CORS setup which the webapp uses to make Ajax calls to the backend server. In chrome, I keep getting
Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.
doesn't work on firefox either.
My Node.js setup is:
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:8000/');
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
};
And in Django I'm using this middleware along with this
The webapp makes requests as such:
$.ajax({
type: "POST",
url: 'http://localhost:8000/blah',
data: {},
xhrFields: {
withCredentials: true
},
crossDomain: true,
dataType: 'json',
success: successHandler
});
So, the request headers that the webapp sends looks like:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: "Origin, X-Requested-With, Content-Type, Accept"
Access-Control-Allow-Methods: 'GET,PUT,POST,DELETE'
Content-Type: application/json
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Cookie: csrftoken=***; sessionid="***"
And here's the response header:
Access-Control-Allow-Headers: Content-Type,*
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE
Content-Type: application/json
Where am I going wrong?!
Edit 1: I've been using chrome --disable-web-security, but now want things to actually work.
Edit 2: Answer:
So, solution for me django-cors-headers config:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
'http://localhost:3000' # Here was the problem indeed and it has to be http://localhost:3000, not http://localhost:3000/
)
This is a part of security, you cannot do that. If you want to allow credentials then your Access-Control-Allow-Origin must not use *. You will have to specify the exact protocol + domain + port. For reference see these questions :
Access-Control-Allow-Origin wildcard subdomains, ports and protocols
Cross Origin Resource Sharing with Credentials
Besides * is too permissive and would defeat use of credentials. So set http://localhost:3000 or http://localhost:8000 as the allow origin header.
If you are using CORS middleware and you want to send withCredential boolean true, you can configure CORS like this:
var cors = require('cors');
app.use(cors({credentials: true, origin: 'http://localhost:3000'}));
Expanding on #Renaud idea, cors now provides a very easy way of doing this:
From cors official documentation found here:
"
origin: Configures the Access-Control-Allow-Origin CORS header.
Possible values:
Boolean - set origin to true to reflect the request origin, as defined by req.header('Origin'), or set it to false to disable CORS.
"
Hence we simply do the following:
const app = express();
const corsConfig = {
credentials: true,
origin: true,
};
app.use(cors(corsConfig));
Lastly I think it is worth mentioning that there are use cases where we would want to allow cross origin requests from anyone; for example, when building a public REST API.
try it:
const cors = require('cors')
const corsOptions = {
origin: 'http://localhost:4200',
credentials: true,
}
app.use(cors(corsOptions));
If you are using express you can use the cors package to allow CORS like so instead of writing your middleware;
var express = require('express')
, cors = require('cors')
, app = express();
app.use(cors());
app.get(function(req,res){
res.send('hello');
});
If you want to allow all origins and keep credentials true, this worked for me:
app.use(cors({
origin: function(origin, callback){
return callback(null, true);
},
optionsSuccessStatus: 200,
credentials: true
}));
This works for me in development but I can't advise that in production, it's just a different way of getting the job done that hasn't been mentioned yet but probably not the best. Anyway here goes:
You can get the origin from the request, then use that in the response header. Here's how it looks in express:
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', req.header('origin') );
next();
});
I don't know what that would look like with your python setup but that should be easy to translate.
(Edit) The previously recomended add-on is not available any longer, you may try this other one
For development purposes in Chrome, installing
this add on will get rid of that specific error:
Access to XMLHttpRequest at 'http://192.168.1.42:8080/sockjs-node/info?t=1546163388687'
from origin 'http://localhost:8080' has been blocked by CORS policy: The value of the
'Access-Control-Allow-Origin' header in the response must not be the wildcard '*'
when the request's credentials mode is 'include'. The credentials mode of requests
initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
After installing, make sure you add your url pattern to the Intercepted URLs by clicking on the AddOn's (CORS, green or red) icon and filling the appropriate textbox. An example URL pattern to add here that will work with http://localhost:8080 would be: *://*
Though we have many solutions regarding the cors origin, I think I may add some missing part. Generally using cors middlware in node.js serves maximum purpose like different http methods (get, post, put, delete).
But there are use cases like sending cookie response, we need to enable credentials as true inside the cors middleware Or we can't set cookie. Also there are use cases to give access to all the origin. in that case, we should use,
{credentials: true, origin: true}
For specific origin, we need to specify the origin name,
{credential: true, origin: "http://localhost:3000"}
For multiple origins,
{credential: true, origin: ["http://localhost:3000", "http://localhost:3001" ]}
In some cases we may need multiple origin to be allowed. One use case is allowing developers only. To have this dynamic whitelisting, we may use this kind of function
const whitelist = ['http://developer1.com', 'http://developer2.com']
const corsOptions = {
origin: (origin, callback) => {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error())
}
}
}
Had this problem with angular, using an auth interceptor to edit the header, before the request gets executed. We used an api-token for authentification, so i had credentials enabled. now, it seems it is not neccessary/allowed anymore
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
req = req.clone({
//withCredentials: true, //not needed anymore
setHeaders: {
'Content-Type' : 'application/json',
'API-TOKEN' : 'xxx'
},
});
return next.handle(req);
}
Besides that, there is no side effects right now.
CORS ERROR With NETLIFY and HEROKU
Actually, if none of the above solutions worked for you then you might wanna try this.
In my case, the backend was running on Heroku and the frontend was hosted on netlify.
in the .env file, of the frontend, the server_url was written as
REACT_APP_server_url = "https://ci-cd-backend.herokuapp.com"
and in the backend, all my api calls where written as,
app.get('/login', (req, res, err) => {});
So, Only change you need to do is, add /api at the end of the routes,
so, frontend base url will look like,
REACT_APP_server_url = "https://ci-cd-backend.herokuapp.com/api"
and backend apis should be written as,
app.get('/api/login', (req, res, err) => {})
This worked in my case, and I believe this problem is specifically related when the front end is hosted on netlify.