I'm trying to hit an API from the browser using a AJAX call, and I see this inside my browser.
Access to XMLHttpRequest at 'https://.......us-east-1.amazonaws.com/...' from origin 'https://....cloudfront.net' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
The back-end was an actually a AWS lambda. So should I fix this on the client side or the server side?
Set headers to your LAMBDA response.
var response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Headers" : "*",
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify(data)
};
You can set Access-Control-Allow-Headers specific headers you want to allow instead of * (ALL) and domain also.
I have my micro-service developed using spring-boot and spring security and frontend is designed on react-hooks.
Now, while I am send some data to my micro-service using axios.post method, it send CORS preflight method i.e. options method because axios by default send content-type as application/json and application.json leads to send options request to server before any other request.
I have tried sending my request with different headers and content types as 'application/x-www-form-urlencoded' also I have used #cross-origin(*) at my server end.
const config = {
headers: {
'Content-Type': 'application/json'
}
}
const response = await axios.post(ps.user_ms_url+ps.user_login,
{
username:values.email,
password:values.password
// headers:{'tokenvalue':'token'}
},
config);
I expect my browser to send only post request to the server, for that I am ready to change my headers as well.
Any help will be appreciated. Thanks in advance!
I found the solution for my query. As I mentioned above, our browser sends preflight request (means options request) before any other request if our request is not simple (here simple means: if request contains content-type : application/json or custom headers etc) and if we are sending this request to some other domain/ URL.
And our axios.post method carries content-type as application/json by default, that's why, my browser was sending multiple requests (means preflight request before any other request).
Now, I have changed my request content-type to application/x-www-form-urlencoded by sending data as params, as shown below:
var params = new URLSearchParams();
params.append('username', values.email);
params.append('password', values.password);
const response = await axios.post(ps.user_ms_url+ps.user_login,
params);
And handling this request at backend using #ModelAttribute annotation (Spring-boot). So, keeping request simple can stop preflight requests.
You can avoid CORS preflight request by proxying the request. Add this in your webpack development config
devServer: {
port: process.env.PORT || 3000,
proxy: {
'/api': {
target: 'http:localhost:8080',
pathRewrite: { '^/api': '' },
changeOrigin: true,
},
},
}
This means your request to /api/users will forwarded to http://localhost:8080/users.
If you are using create-react-app. just add "proxy": "http://localhost:8080" to your package.json. Check more info here
This looks to be server side CORS issue. You have to allow domains to access resources by providing correct response headers.
You can look at adding CORS headers in spring boot. Refer to this link
Hope that helps!!!
I encounter a problem when I try to call the Teamcity REST service through a TFS extension.
I configured TeamCity as well:
rest.cors.origins = "http://my.tfsserver"
rest.cors.optionsRequest.allowUnauthorized = true
In the TFS extension, I call the following url:
http: //my.teamcity.server:80/app/rest/latest/projects using "XMLHttpRequest"
const pair :string=this.settings.username+":"+this.settings.password;
const encodedCreds:string = btoa(pair);
const basicAuthValue:string = "Basic "+ encodedCreds;
const apiurl:string="/app/rest/latest/projects";
const completeUrl:string = this.settings.urlTeamCity+apiurl;
const xhr = new XMLHttpRequest();
xhr.open("GET",completeUrl,true);
xhr.setRequestHeader('Authorization', basicAuthValue);
xhr.setRequestHeader("Access-Control-Allow-Origin" ,"http://my.tfsserver");
xhr.onload=function(){
console.log(xhr.responseText);
}
xhr.onerror=function(){
console.log(xhr.response);
}
xhr.send();
I'm getting the following error in the console:
Failed to load http://my.teamcity.server:80/app/rest/latest/projects:
Response for preflight is invalid (redirect)
In the TeamCity rest log, i have the following two lines:
[2018-10-01 14:12:49,891] DEBUG [p-nio-80-exec-9] -
er.rest.APIController/rest-api - Got CORS request from origin 'null',
but this origin is not allowed. Add the origin to 'rest.cors.origins'
internal property (comma-separated) to trust the applications hosted
on the domain. Current allowed origins are: Enabled CORS Origins:
[http://my.tfsserver]
[2018-10-01 14:12:49,892] DEBUG [p-nio-80-exec-9] -
er.rest.APIController/rest-api - REST API request processing finished
in 1ms, status code: 302, request: OPTIONS
'/app/rest/latest/projects', from client 10.69.152.71:59256, no auth
Based on the last line, i modify my code to:
...
xhr.open("GET",completeUrl,true,this.settings.username,this.settings.password)
xhr.withCredentials=true;
...
but, i'm still getting the same error in both chrome console and team city rest log.
in the chrome console, on the network tab, i can see that "origin" header is null but i don't understand why?
Thanks by adavance for any help :)
I'm trying the javascript framework react and I need to fetch a token from an api off this service: https://api.monetizze.com.br/2.1/apidoc/#api-Security-Token. For that, I need to send along with the request my X_CONSUMER_KEY. That's the way I'm trying to do with the axios library:
axios.request('https://api.monetizze.com.br/2.1/token', {
headers: {
'X-Requested-With' : 'XMLHttpRequest',
'X_CONSUMER_KEY': 'here is my key'
}
});
The response I'm getting on the browser console is as follows:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at https://api.monetizze.com.br/2.1/token.
(Reason: CORS preflight channel did not succeed).
Have you experienced that issue and have solved it? Sorry about my very poor English and thank you very much.
http.get({
host: 'api.monetizze.com.br',
path: '/2.1/token',
headers: {
X_CONSUMER_KEY: 'your_consumer_key',
}
}, (result) => {
console.log(req.headers);
res.send(result.statusCode)
});
That piece of code above in a server side application did the job, thank you very much.
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.