AngularJS - How to connect to Twitter application-only authentication via Oauth2? - angularjs

I try to receive an accessToken from the Twitter application-only authentication but I keep receiving a 405 (Method Not Allowed) response from the twitter api. Anybody knows how to solve this? I'm desperately stuck..
I am aware of the fact that:
- best practice is doing this from serverside, but I wanted to try this out with angular on client side
- X-Requested-With should be deleted from the header
This is the factory I created:
twitterServices.factory('Connect', function($http){
var factory = {};
var baseUrl = 'https://api.twitter.com/';
var bearerToken = function(){
var consumerKey = encodeURIComponent('****');
var consumerSecret = encodeURIComponent('****');
var tokenCredentials = btoa(consumerKey + ':' + consumerSecret);
return tokenCredentials;
};
factory.fetchAccessToken = function(scope){
var oAuthurl = baseUrl + "oauth2/token";
var headers = {
'Authorization': 'Basic ' + bearerToken(),
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
};
$http.defaults.useXDomain = true;
delete $http.defaults.headers.common['X-Requested-With'];
$http({method: 'POST', url: oAuthurl, headers: headers, data: 'grant_type=client_credentials'}).
success(function(data, status){
scope.status = status;
scope.data = data;
}).
error(function(data, status){
scope.status = status;
scope.data = data || "Request failed";
});
};
factory.fetchTimeLine = function(scope){
scope.fetchAccessToken();
//the rest
};
return factory;
});
This is the header request/response in Chrome:
Request URL:`https://api.twitter.com/oauth2/token`
Request Method:OPTIONS
Status Code:405 Method Not Allowed
Request Headersview source
:host:api.twitter.com
:method:OPTIONS
:path:/oauth2/token
:scheme:https
:version:HTTP/1.1
accept:*/*
accept-encoding:gzip,deflate,sdch
accept-language:en-US,en;q=0.8
access-control-request-headers:accept, authorization, content-type
access-control-request-method:POST
origin:`http://localhost`
referer:`http://localhost/test/app/
user-agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.69 Safari/537.36
Response Headersview source
content-length:0
status:405 Method Not Allowed
version:HTTP/1.1
My Console shows the following:
OPTIONS https://api.twitter.com/oauth2/token 405 (Method Not Allowed) angular.js:9312
OPTIONS https://api.twitter.com/oauth2/token Origin http://localhost is not allowed by Access-Control-Allow-Origin. angular.js:9312
XMLHttpRequest cannot load https://api.twitter.com/oauth2/token. Origin http://localhost is not allowed by Access-Control-Allow-Origin. (index):1

Check:
Twitter :Application-only authentication error Origin null is not allowed by Access-Control-Allow-Origin
and:
https://dev.twitter.com/discussions/1291

I ran into a similar issue when working with the google API where in request from localhost are denied even if you register it with the system.
We got around this issue by adding a multipart name to our /etc/hosts file and binding it to 127.0.0.1
for example
127.0.0.1 www.devsite.com
This has resolved the most basic issues that I have had writing angular services for APIs
update by request:
One of the ways that companies control access to their APIs is through whitelisting. When you register an application with the service that platform will typically add the domain you list in your application to its whitelist. This is Generally done to force you in to using separate API keys for separate services. This can make work on the dev side difficult when you are testing locally.
In this case I believe that twitter has specifically banned requests using localhost to prevent the use of 3rd party tools and bots.
Binding the domain you registered with your API key into your hosts file will cause any web requests on your machine to that domain to skip a dns lookup and instead route the request to your local dev server. This means that locally you will test your code by visiting:
www.devsite.com:[what ever port your local server is running on]
This may not be the solution to 100% of api access problems but it is one of the most common that I have experienced.
Note based on other responses:
There are Multiple reasons why you might experience a CORS related error. But just because you have received one doesn't mean that it isn't possible to implement your code on the front end. Generally in Angular CORS is encountered when:
a) you have failed to format your request correctly
-- one example of this might be you have added a header to indicate json is an expected result when infact the response it text.
b) the service or API is configured with a whitelist that needs to include explicitly either "localhost" or some other domain as discussed in this post.

Related

Access to XMLHttpRequest at ''API-URL" from origin localhost has been blocked by CORS policy [duplicate]

I'm trying to fetch some data from the REST API of HP Alm. It works pretty well with a small curl script—I get my data.
Now doing that with JavaScript, fetch and ES6 (more or less) seems to be a bigger issue. I keep getting this error message:
Fetch API cannot load . Response to preflight request doesn't
pass access control check: No 'Access-Control-Allow-Origin' header is
present on the requested resource. Origin 'http://127.0.0.1:3000' is
therefore not allowed access. The response had HTTP status code 501.
If an opaque response serves your needs, set the request's mode to
'no-cors' to fetch the resource with CORS disabled.
I understand that this is because I am trying to fetch that data from within my localhost and the solution should be using Cross-Origin Resource Sharing (CORS). I thought I actually did that, but somehow it either ignores what I write in the header or the problem is something else.
So, is there an implementation issue? Am I doing it wrong? I can't check the server logs unfortunately. I'm really a bit stuck here.
function performSignIn() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
headers.append('GET', 'POST', 'OPTIONS');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
fetch(sign_in, {
//mode: 'no-cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed : ' + error.message));
}
I am using Chrome. I also tried using that Chrome CORS Plugin, but then I am getting another error message:
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://127.0.0.1:3000' is therefore not allowed
access. The credentials mode of requests initiated by the
XMLHttpRequest is controlled by the withCredentials attribute.
This answer covers a lot of ground, so it’s divided into three parts:
How to use a CORS proxy to avoid “No Access-Control-Allow-Origin header” problems
How to avoid the CORS preflight
How to fix “Access-Control-Allow-Origin header must not be the wildcard” problems
How to use a CORS proxy to avoid “No Access-Control-Allow-Origin header” problems
If you don’t control the server your frontend code is sending a request to, and the problem with the response from that server is just the lack of the necessary Access-Control-Allow-Origin header, you can still get things to work—by making the request through a CORS proxy.
You can easily run your own proxy with code from https://github.com/Rob--W/cors-anywhere/.
You can also easily deploy your own proxy to Heroku in just 2-3 minutes, with 5 commands:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
After running those commands, you’ll end up with your own CORS Anywhere server running at, e.g., https://cryptic-headland-94862.herokuapp.com/.
Now, prefix your request URL with the URL for your proxy:
https://cryptic-headland-94862.herokuapp.com/https://example.com
Adding the proxy URL as a prefix causes the request to get made through your proxy, which:
Forwards the request to https://example.com.
Receives the response from https://example.com.
Adds the Access-Control-Allow-Origin header to the response.
Passes that response, with that added header, back to the requesting frontend code.
The browser then allows the frontend code to access the response, because that response with the Access-Control-Allow-Origin response header is what the browser sees.
This works even if the request is one that triggers browsers to do a CORS preflight OPTIONS request, because in that case, the proxy also sends the Access-Control-Allow-Headers and Access-Control-Allow-Methods headers needed to make the preflight succeed.
How to avoid the CORS preflight
The code in the question triggers a CORS preflight—since it sends an Authorization header.
https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Even without that, the Content-Type: application/json header will also trigger a preflight.
What “preflight” means: before the browser tries the POST in the code in the question, it first sends an OPTIONS request to the server, to determine if the server is opting-in to receiving a cross-origin POST that has Authorization and Content-Type: application/json headers.
It works pretty well with a small curl script - I get my data.
To properly test with curl, you must emulate the preflight OPTIONS the browser sends:
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization' \
"https://the.sign_in.url"
…with https://the.sign_in.url replaced by whatever your actual sign_in URL is.
The response the browser needs from that OPTIONS request must have headers like this:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
If the OPTIONS response doesn’t include those headers, the browser will stop right there and never attempt to send the POST request. Also, the HTTP status code for the response must be a 2xx—typically 200 or 204. If it’s any other status code, the browser will stop right there.
The server in the question responds to the OPTIONS request with a 501 status code, which apparently means it’s trying to indicate it doesn’t implement support for OPTIONS requests. Other servers typically respond with a 405 “Method not allowed” status code in this case.
So you’ll never be able to make POST requests directly to that server from your frontend JavaScript code if the server responds to that OPTIONS request with a 405 or 501 or anything other than a 200 or 204 or if doesn’t respond with those necessary response headers.
The way to avoid triggering a preflight for the case in the question would be:
if the server didn’t require an Authorization request header but instead, e.g., relied on authentication data embedded in the body of the POST request or as a query param
if the server didn’t require the POST body to have a Content-Type: application/json media type but instead accepted the POST body as application/x-www-form-urlencoded with a parameter named json (or whatever) whose value is the JSON data
How to fix “Access-Control-Allow-Origin header must not be the wildcard” problems
I am getting another error message:
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://127.0.0.1:3000' is therefore not allowed
access. The credentials mode of requests initiated by the
XMLHttpRequest is controlled by the withCredentials attribute.
For requests that have credentials, browsers won’t let your frontend JavaScript code access the response if the value of the Access-Control-Allow-Origin header is *. Instead the value in that case must exactly match your frontend code’s origin, http://127.0.0.1:3000.
See Credentialed requests and wildcards in the MDN HTTP access control (CORS) article.
If you control the server you’re sending the request to, a common way to deal with this case is to configure the server to take the value of the Origin request header, and echo/reflect that back into the value of the Access-Control-Allow-Origin response header; e.g., with nginx:
add_header Access-Control-Allow-Origin $http_origin
But that’s just an example; other (web) server systems have similar ways to echo origin values.
I am using Chrome. I also tried using that Chrome CORS Plugin
That Chrome CORS plugin apparently just simplemindedly injects an Access-Control-Allow-Origin: * header into the response the browser sees. If the plugin were smarter, what it would be doing is setting the value of that fake Access-Control-Allow-Origin response header to the actual origin of your frontend JavaScript code, http://127.0.0.1:3000.
So avoid using that plugin, even for testing. It’s just a distraction. To test what responses you get from the server with no browser filtering them, you’re better off using curl -H as above.
As far as the frontend JavaScript code for the fetch(…) request in the question:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Remove those lines. The Access-Control-Allow-* headers are response headers. You never want to send them in requests. The only effect of that is to trigger a browser to do a preflight.
This error occurs when the client URL and server URL don't match, including the port number. In this case you need to enable your service for CORS which is cross origin resource sharing.
If you are hosting a Spring REST service then you can find it in the blog post CORS support in Spring Framework.
If you are hosting service using a Node.js server then
Stop the Node.js server.
npm install cors --save
Add following lines to your server.js
const cors=require("cors");
const corsOptions ={
origin:'*',
credentials:true, //access-control-allow-credentials:true
optionSuccessStatus:200,
}
app.use(cors(corsOptions)) // Use this after the variable declaration
The problem arose because you added the following code as the request header in your front-end:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Those headers belong to the response, not request. So remove them, including the line:
headers.append('GET', 'POST', 'OPTIONS');
Your request had 'Content-Type: application/json', hence triggered what is called CORS preflight. This caused the browser sent the request with the OPTIONS method. See CORS preflight for detailed information.
Therefore in your back-end, you have to handle this preflighted request by returning the response headers which include:
Access-Control-Allow-Origin : http://localhost:3000
Access-Control-Allow-Credentials : true
Access-Control-Allow-Methods : GET, POST, OPTIONS
Access-Control-Allow-Headers : Origin, Content-Type, Accept
Of course, the actual syntax depends on the programming language you use for your back-end.
In your front-end, it should be like so:
function performSignIn() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
headers.append('Origin','http://localhost:3000');
fetch(sign_in, {
mode: 'cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed: ' + error.message));
}
In my case, I use the below solution.
Front-end or Angular
post(
this.serverUrl, dataObjToPost,
{
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
)
back-end (I use PHP)
header("Access-Control-Allow-Origin: http://localhost:4200");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header("Access-Control-Allow-Headers: Content-Type, Authorization");
$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
print_r($request);
Using dataType: 'jsonp' worked for me.
async function get_ajax_data(){
var _reprojected_lat_lng = await $.ajax({
type: 'GET',
dataType: 'jsonp',
data: {},
url: _reprojection_url,
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR)
},
success: function (data) {
console.log(data);
// note: data is already json type, you
// just specify dataType: jsonp
return data;
}
});
} // function
Just my two cents... regarding How to use a CORS proxy to get around “No Access-Control-Allow-Origin header” problems
For those of you working with php at the backend, deploying a "CORS proxy" is as simple as:
create a file named 'no-cors.php' with the following content:
$URL = $_GET['url'];
echo json_encode(file_get_contents($URL));
die();
on your front end, do something like:
fetch('https://example.com/no-cors.php' + '?url=' + url)
.then(response=>{*/Handle Response/*})`
If your API is written in ASP.NET Core, then please follow the below steps:
Install the Microsoft.AspNetCore.Cors package.
Add the below line in the ConfigureServices method in file Startup.cs:
services.AddCors();
Add the below line in the Configure method in file startup.cs:
app.UseCors(options =>
options.WithOrigins("http://localhost:8080")
.AllowAnyHeader()
.AllowAnyMethod());
Make sure you add this after - app.UseRouting();
Refer to the below image(from MSDN) to see the middleware order:
https://i.stack.imgur.com/vQ4yT.png
Possible causes of CORS issues
Check your server-side access headers: Refer to this link
Check what request header is received from the server in the browser. The below image shows the headers
If you are using the fetch method and trying to access the cross-origin request make sure mode:cors is there. Refer to this link
Sometimes if there is an issue in the program also you are getting the CORS issue, so make sure your code is working properly.
Make sure to handle the OPTION method in your API.
Adding mode:no-cors can avoid CORS issues in the API.
fetch(sign_in, {
mode: 'no-cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed : ' + error.message));
}
In December 2021, Chrome 97, the Authorization: Bearer ... is not allowed unless it is in the Access-Control-Allow-Headers preflight response (ignores *). It produced this warning:
[Deprecation] authorization will not be covered by the wildcard symbol (*)
See: Chrome Enterprise release notes, Chrome 97
It also appears to enforce the same restriction on * on Access-Control-Allow-Origin. If you want to revive *-like behavior now that it is blocked, you'll likely have to read the requester's origin and return it as the allowed origin in the preflight response.
In some cases, a library may drop the Access-Control-Allow-Origin response header when there is some other invalid credential (example: an expired JWT). Then, the browser shows the "No 'Access-Control-Allow-Origin' header is present" error instead of the actual error (which in this example could be an expired JWT). Be sure that your library doesn't drop the header and confuse the client.
Faced this issue in my react/express app. Adding the below code in server.js (or your server file name) fixed the issue for me. Install cors and then
const cors = require('cors');
app.use(cors({
origin: 'http://example.com', // use your actual domain name (or localhost), using * is not recommended
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Origin', 'X-Requested-With', 'Accept', 'x-client-key', 'x-client-token', 'x-client-secret', 'Authorization'],
credentials: true
}))
Now you can make straightforward API calls from your front-end without having to pass any additional parameters.
With Node.js, if you are using routers, make sure to add CORS before the routers. Otherwise, you'll still get the CORS error. Like below:
const cors = require('cors');
const userRouter = require('./routers/user');
expressApp = express();
expressApp.use(cors());
expressApp.use(express.json());
expressApp.use(userRouter);
In case you are using Node.js and Express.js as the back-end and React & Axios as the front-end within a development environment in macOS, you need to run both sides under HTTPS. Below is what finally worked for me (after many hours of deep dive and testing):
Step 1: Create an SSL certificate
Just follow the steps from How to get HTTPS working on your local development environment in 5 minutes.
You will end up with a couple of files to be used as credentials to run the HTTPS server and React web:
server.key & server.crt
You need to copy them in the root folders of both the front and back ends (in a production environment, you might consider copying them in folder ./ssh for the back-end).
Step 2: Back-end setup
I read a lot of answers proposing the use of 'cors' package or even setting ('Access-Control-Allow-Origin', '*'), which is like saying: "Hackers are welcome to my website". Just do like this:
import express from 'express';
const emailRouter = require('./routes/email'); // in my case, I was sending an email through a form in React
const fs = require('fs');
const https = require('https');
const app = express();
const port = 8000;
// CORS (Cross-Origin Resource Sharing) headers to support Cross-site HTTP requests
app.all('*', (req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://localhost:3000");
next();
});
// Routes definition
app.use('/email', emailRouter);
// HTTPS server
const credentials = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
};
const httpsServer = https.createServer(credentials, app);
httpsServer.listen(port, () => {
console.log(`Back-end running on port ${port}`);
});
In case you want to test if the https is OK, you can replace the httpsServer constant by the one below:
https.createServer(credentials, (req: any, res: any) => {
res.writeHead(200);
res.end("hello world from SSL\n");
}).listen(port, () => {
console.log(`HTTPS server listening on port ${port}...`);
});
And then access it from a web browser: https://localhost:8000/
Step 3: Front-end setup
This is the Axios request from the React front-end:
await axios.get(`https://localhost:8000/email/send`, {
params: { /* Whatever data you want to send */ },
headers: {
'Content-Type': 'application/json',
}
})
And now, you need to launch your React web in HTTPS mode using the credentials for SSL we already created. Type this in your macOS terminal:
HTTPS=true SSL_CRT_FILE=server.crt SSL_KEY_FILE=server.key npm start
At this point, you are sending a request from an HTTPS connection at port 3000 from your front-end, to be received by an HTTPS connection at port 8000 by your back-end. CORS should be happy with this ;)
For those using ASP.NET Core:
In my case, I was using JavaScript to make a blob from an image stored on the API (the server), so the URL was pointing to that resource. In that API's program.cs class, I already had a CORS policy, but it didn't work.
After I read the Microsoft documentation (read the first paragraph) about this issue, it is said that if you want to access a resource on the server, by using JavaScript (which is what I was trying to do), then you must call the app.UseCors(); before the app.UseStaticFiles(); which is typically the opposite.
My program.cs file:
const string corsPolicyName = "ApiCORS";
builder.Services.AddCors(options =>
{
options.AddPolicy(corsPolicyName, policy =>
{
policy.WithOrigins("https://localhost:7212");
});
});
...
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI(settings =>
{
settings.DisplayRequestDuration();
settings.EnableTryItOutByDefault();
});
app.UseHttpsRedirection();
app.UseCors(corsPolicyName); // 👈 This should be above the UseStaticFiles();
app.UseStaticFiles(); // 👈 Below the UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseApiCustomExceptionHandler();
app.MapControllers();
app.Run();
Remove this:
credentials: 'include',
For a Node.js and Express.js backend I use this :)
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "YOUR-DOMAIN.TLD"); // Update to match the domain you will make the request from
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
For more details: CORS on ExpressJS
I have encountered this error several times over the past few years -- seemingly showing up out of the blue in a previously functioning website.
I determined that Chrome (and possibly other browsers) can return this error when there is some unrelated error that occurs on the server that prevents it from processing the CORS request (and prior to returning an HTTP 500 error).
These all occurred in a .NET Core environment, and I am not sure if it would happen in other environments.
Anyway, if your code has functioned before, and seems correct, consider debugging to find if there is some other error that is firing before you go crazy trying to solve an error that isn't really there.
In my case, the web server prevented the "OPTIONS" method
Check your web server for the options method
Apache: https://www-01.ibm.com/support/docview.wss?uid=ibm10735209
web tier: 4.4.6 Disabling the Options Method https://docs.oracle.com/cd/E23943_01/web.1111/e10144/getstart.htm#HSADM174
nginx: https://medium.com/#hariomvashisth/cors-on-nginx-be38dd0e19df
I'm using "webtier"
/www/webtier/domains/[domainname]/config/fmwconfig/components/OHS/VCWeb1/httpd.conf
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^OPTIONS
RewriteRule .* . [F]
</IfModule>
change to
<IfModule mod_rewrite.c>
RewriteEngine off
RewriteCond %{REQUEST_METHOD} ^OPTIONS
RewriteRule .* . [F]
</IfModule>
In my case, the solution was dumb as hell... Your allowed origin shouldn't have a slash at the end.
E.g., https://example.com/ -> https://example.com
In my case, I had to add a custom header middleware below all the existing middleware. I think some middleware might conflict with the Access-Control-Allow-Origin Header and try to set it according to their needs.
So the code would be something like this:
app.use(cors());
....all other middleware here
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:3000");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
...your routes
I make this mistake a lot of times, and because of it, I've made a "check-list" to all of you.
Enable CORS on your project: If you're using Node.js (by example) you can use:
npm install cors;
import cors from 'cors';
app.use(cors());
You can manually set the headers like this (if you want it):
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authortization');
res.setHeader('Acces-Control-Allow-Methods', 'GET, POST, PATCH, DELETE');
Remember to add http:// to your API link in your frontend project, some browsers like Chrome do not accept a request using CORS if the request URL isn't HTTP or HTTPS:
http://localhost:3000/api
Check if your project is using a proxy.config.js file. See Fixing CORS errors with Angular CLI proxy.
When the client used to call our backend service from his host username.companyname.com, he used to get the above error
Two things are required:
while sending back the response, send the header whose key is Access-Control-Allow-Origin and value is *:
context.Writer.Header()["Access-Control-Allow-Origin"] = []string{"*"} // Important to avoid a CORS error
Use the Go CORS library to set AllowCredentials to false and AllowAllOrigins to true.
Use the below npm module. This has virtually saved lives.
https://www.npmjs.com/package/local-cors-proxy
You're getting a CORS error, for example like the below URL
https://www.google.co.in/search/list
After successfully installed(local-cors-proxy) global npm install -g local-cors-proxy and set proxy URL that CORS URL.
For example, here the below CORS issue getting in localhost. So you need to add the domain name(https://www.google.co.in) and port(--port 8010) for the CORS issue domain.
For more please check the link
https://www.npmjs.com/package/local-cors-proxy
lcp --proxyUrl https://www.google.co.in --port 8010
After successfully set, it will generate the local proxy URL like below.
http://localhost:8010/proxy
Use that domain name in your project API URL.
API full URL:
http://localhost:8010/proxy/search/list
To get without a CORS issue response in your local project.
Using WebAPI build in .Net Core 6.0
None of the above worked for me... This did it
// global cors policy
app.UseCors(x => x
.AllowAnyMethod()
.AllowAnyHeader()
.SetIsOriginAllowed(origin => true) // allow any origin
.AllowCredentials());
credit: https://stackoverflow.com/a/70660054/8767516
Try adding all these headers in this code below Before every route, you define in your app, not after the routes
app.use((req, res, next) =>{
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers','Origin, X-Requested-With, Content-Type,Accept, Authortization');
res.setHeader('Acces-Control-Allow-Methods','GET, POST, PATCH, DELETE');
If you are getting this error while deploying React app to netlify, use these steps.
step 1: Create netlify.toml file in the root folder of your react app.
step 2: Copy paste this code:
`[[redirects]]
from = "/cors-proxy/*"
to = ":splat"
status = 200
force = true`
step3: update your fetch/axios api this way:
It took me a while to figure this out.

CSRF Cookie not set when posting request with AngularJs - Django Backend

I'm building a web app with angularjs and django and I'm submitting form via Ajax request.
My problem is that when posting an Ajxa request with angular (ng-file-upload precisely) the csrfmiddlewaretoken expected by django is not set.
From my lectures on angular documentation and other forums I ended up with the following configuration.
In the config part of angular :
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$httpProvider.defaults.withCredentials = true;
and in my controller the code for sending the request is :
Upload.upload({
url: 'http://localhost:8000/image',
headers: {
'X-CSRFToken': $cookies['csrftoken']
},
data: {file: file}
})
With that code the request send has the following headers :
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4,de;q=0.2,fi;q=0.2
Connection:keep-alive
Content-Length:16582
Content-Type:multipart/form-data; boundary=----WebKitFormBoundarybWo821vSwcejTATP
Cookie:csrftoken=bC2UpXurGXAg3AUZgSqMVlUs8TKfussS
Host:localhost:8000
Origin:http://127.0.0.1:8000
Referer:http://127.0.0.1:8000/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36
X-CSRFToken:UeSt4LoqgU9L28JQBdVbS2IJJXOMQK6n
However for django to be able to handle csrf protection correctly the following header is missing
Cookie:_ga=GA1.1.1358238168.1447425523; XSRF-TOKEN=zWIM6q7O2Nz3PLm8TMUJSLFVRF8bKUbr; csrftoken=UeSt4LoqgU9L28JQBdVbS2IJJXOMQK6n
So far and despite having seen a lot of forums about this topic I didn't manage to set this header. if I try to set it programmatically via :
Upload.upload({
url: 'http://localhost:8000/image',
headers: {
'Cookie': 'csrftoken='+$cookies['csrftoken']
},
data: {file: file}
})
I end up with the following error in my console :
Refused to set unsafe header "Cookie"
My problem is really how to configure the cookie header from the client side. My django code is fine.
I have been struggling with this for quite a time now. Any help would be appreciated ! Thanks
If you added in the csrftoken to client headers: {'X-CSRFToken': $cookies['csrftoken']} means your client is most probably ready, but for security matter if you interact with django api from external application he will still block the request returning unsafe header "Cookie".
try the following configuration to allow the cross site request over your app:
pip install django-cors-headers
and then add it to your installed apps in your settings.py:
INSTALLED_APPS = (
...
'corsheaders',
...
)
You will also need to add a middleware class to listen in on responses and make sure you respect the order as follow:
MIDDLEWARE_CLASSES = (
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
)
and finally add this settings variable:
CORS_ORIGIN_ALLOW_ALL = True
This should be enough but for more customized configuration you can check django-cors-headers

Access denied CORs request in IE10+ in angularjs with required Cross Origin Resource Sharing error (info?)

I thought the days of cross browser support were a thing of the past with the various libraries out there insulating from some of the nuance and the purported standardisation of web browsers but....
I am trying to perform a $http get request using angularjs (v1.2.27) thus:
$http({
url: vm.hostName + '/pdf/' + id,
method : 'GET',
responseType : 'arraybuffer',
cache : false})
.success(function (response) {
var file = new Blob([response], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
console.log(fileURL);
console.log(response.data);
window.open(fileURL);
});
which works swimmingly on Chrome, FF and Safari (Mac and Win 7, 8 so far), but not on IE10+, I get this:
SEC7118: XMLHttpRequest for https://[api.domain.com]/pdf/55abc12345613af7946e required Cross Origin Resource Sharing (CORS).
Error: Access is denied.
at Anonymous function (https://[domain.com]/site/scripts/scripts.js:289:6)
at Anonymous function (https://[domain.com]/public/assets/js/angular/angular.js:7736:11)
at wrappedCallback (https://[domain.com]/public/assets/js/angular/angular.js:11106:15)
at wrappedCallback (https://[domain.com]/public/assets/js/angular/angular.js:11106:15)
at Anonymous function (https://[domain.com]/public/assets/js/angular/angular.js:11192:11)
at Scope.prototype.$eval (https://[domain.com]/public/assets/js/angular/angular.js:12181:9)
at Scope.prototype.$digest (https://[domain.com]/public/assets/js/angular/angular.js:12010:15)
at Scope.prototype.$apply (https://[domain.com]/public/assets/js/angular/angular.js:12285:13)
at done (https://[domain.com]/public/assets/js/angular/angular.js:7994:34)
at completeRequest (https://[domain.com]/public/assets/js/angular/angular.js:8196
The response headers returned by the api server are
Key Value
Response HTTP/1.1 200 OK
Server nginx/1.8.0
Date Tue, 25 Aug 2015 13:40:45 GMT
Content-Type application/pdf
Content-Length 86057
Connection keep-alive
Access-Control-Allow-Methods GET, PUT, POST, OPTIONS
Access-Control-Allow-Headers Origin, Content-Type, Accept
Access-Control-Allow-Origin *
Content-Transfer-Encoding binary
and if I look at the response body (in developer tools) I get a message that it can't be rendered (not unreasonably as it is a pdf), but a link to save the content is provided which when saved and opened shows the correct pdf.
The network response appears to show that the content is downloaded given the content-length.
I've looked at a number of CORs related posts but to no avail. The closest one SEC7118: XMLHttpRequest for /socket.io/1/?t=1370206038749 required Cross Origin Resource Sharing (CORS) doesn't help.
The Microsoft blog http://blogs.msdn.com/b/ie/archive/2012/02/09/cors-for-xhr-in-ie10.aspx doesn't give any more clues either (I'm guessing it may have something to do with the 'arraybuffer' and binary data, but am now at a dead end and looking for further inspiration.
Anyone suggest anything else?
ps. I am in control of the server api and it is being services by vert.x (v2.5) as a Java REST service.
Thanks
The resolution posted StackOverflow answer sorted the problem.
The issues wasn't with the response back from the server, the issue was with the opening of the url created by
var file = new Blob([response], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
The IE doesn't support window.open of the generated blob:xxx-yyy url.
See link answer for required javascript for displaying blobs in IE10+ (which was what I wanted).

Angularjs using JWT breaks CORS to Amazon S3 on login

I've got an interesting issue happening on my angularjs app. When I login, all of the template requests in angular made to Amazon S3 stop working, and return a 400 Bad Request. They work completely fine before you login. The only thing that should change when logged in, is a json web token is sent in the headers to verify the person logged in. My thoughts are maybe the interceptor that is sending the jwt in the headers is somehow affecting CORS on Amazon S3. Seems strange.
Here is the interceptor code:
.factory('TokenInterceptor', function ($q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
}
return config;
},
response: function (response) {
return response || $q.when(response);
}
};
});
EDIT: It was giving me an Access Origin error but I changed my CORS file on Amazon and it seemed to change to a 400 error now. My CORS file looks like:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
EDIT: Including a sample of the response when trying to access the file after logging in:
Remote Address:1.2.3.4:443
Request URL:https://s3.amazonaws.com/bucket/path/to/file/template.html
Request Method:GET
Status Code:400 Bad Request
Request Headersview source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-GB,en;q=0.8,en-US;q=0.6,fr;q=0.4,es;q=0.2
Authorization:Bearer xxxXXXxxxXXXxxXXxxxXXXXxxXXxx
Connection:keep-alive
Host:s3.amazonaws.com
Origin:http://domain.com
Referer:http://domain.com/
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Response Headersview source
Access-Control-Allow-Methods:GET
Access-Control-Allow-Origin:*
Access-Control-Max-Age:3000
Connection:close
Content-Type:application/xml
Date:Sun, 21 Dec 2014 01:49:16 GMT
Server:AmazonS3
Transfer-Encoding:chunked
Vary:Origin, Access-Control-Request-Headers, Access-Control-Request-Method
x-amz-id-2:xxxXXXxxxXXXxx
x-amz-request-id:xxxXXXxxxXXxxxXXXxx
Just for the record. I was also having the same problem (or a very similar one which is: None files would be found after i did the login on my AngularJS app) and after hours digging on the problem i found what was the issue.
On my specific case it was nothing really related to S3 or CORS but in fact the cookies (and I'm still not really sure how it did cause the problem of not finding the files, but it did). As i saw on my application, i've drastically increased the information stored on my user after i did the login and it was exceeding the 4kb limit for the cookies and for some reason it was breaking down my whole website.
I'm checking the possibility to change from cookies to localStorage, but that is another history. the main thing is that after i reduce the number of information stored on the cookie it started working as it was supposed to.
You need to add transformRequest to http post to delete the Authorization header for that specific request.
transformRequest: function (data, headersGetter) {
//Headers change here
var headers = headersGetter();
delete headers['Authorization'];
return data;
},
Got the same problem on uploading to Amazon S3 the same issue so i added this and it worked.

Cross Domain HTTP request fails in AngularJS

I have a REST backend with Spring (CORS enabled running on Apache Tomcat 7) and an AngularJS client. Both running on different domains (as far as CORS is concerned).
I'm trying to implement Basic Auth but it only works when both the client and the service are on the same host/port number even after I verified that CORS is working fine on the server side. (I tested it by disabling basic auth impl and simply checking if the client is able to pull data from service. It works as long as the CORS filter on the service is working - as expected).
Here is the client configuration
Enabling Cross domain request for Angular (I heard that it's not needed for Angular 1.2+ but it doesn't seem to work either way)
myApp.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);
HTTP Call
$http({method: 'GET', url: url + userId, headers: {'Authorization': 'Basic ' + Base64.encode('admin' + ':' + 'password')}}).
success(function(data, status, headers, config) {
//
}).
error(function(data, status, headers, config) {
//
});
Backend CORS Filter
FilterRegistration corsFilter = container.addFilter("CORS", CORSFilter.class);
corsFilter.setInitParameter("cors.supportedMethods", "GET, HEAD, POST, PUT, DELETE, OPTIONS");
corsFilter.setInitParameter("cors.supportedHeaders", "Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
corsFilter.setInitParameter("cors.supportsCredentials ", "false");
corsFilter.setInitParameter("cors.allowOrigin ", "*");
corsFilter.addMappingForUrlPatterns(null, false, "/*");
Spring Security for Basic Auth
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.anyRequest().anonymous()
.and()
.httpBasic();
}
}
Error I get (The whole error as-is per request made by the client to the service while running on another domain)
Failed to load resource: the server responded with a status of 403 (Forbidden) (11:53:44:206 | error, network)
at http://localhost:8081/myApp-service/user/6
Failed to load resource: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8383' is therefore not allowed access. (11:53:44:209 | error, network)
at http://localhost:8081/myApp-service/user/6
XMLHttpRequest cannot load http://localhost:8081/myApp-service/user/6. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8383' is therefore not allowed access. (11:53:44:211 | error, javascript)
at app/index.html
Chrome Request header
Request URL:http://localhost:8081/myApp-service/user/6
Request Method:OPTIONS
Status Code:403 Forbidden
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, authorization
Access-Control-Request-Method:GET
Connection:keep-alive
Host:localhost:8081
Origin:http://localhost:8383
Referer:http://localhost:8383/myApp-client/app/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36
Response Headersview source
Content-Length:93
Content-Type:text/plain;charset=ISO-8859-1
Date:Wed, 26 Feb 2014 18:55:00 GMT
Server:Apache-Coyote/1.1
So as you can see, Angular is unable to deal with the CORS pre-flight OPTIONS even afte the appropriate config is written. Everything works fine in the same domain and the CORS filter in the backend is tested to work independently. So not sure what I'm missing here. Thanks!
I assumed that the problem was with my client but as Ray pointed out, it was with my Service.
Once I knew that I need to debug my service, I downloaded the sources of CORSFilter, put break points appropriately to study the server response.
Doing so, I found out that the CORS filter is throwing an exception when it encountered "Authorization" in the request Headers. This is because I did not add it to the list of supported headers. The problem was resolved soon after I added it to the list.
corsFilter.setInitParameter("cors.supportedHeaders", "Accept, Origin, X-Requested-With, Content-Type, Last-Modified, Authorization");

Resources