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.
Related
I'm using Node to get an presignedRUL for S3 in order to PUT an image to an S3 bucket.
var aws = require('aws-sdk');
// Request presigned URL from S3
exports.S3presignedURL = function (req, res) {
var s3 = new aws.S3();
var params = {
Bucket: process.env.S3_BUCKET,
Key: '123456', //TODO: creat unique S3 key
//ACL:'public-read',
ContentType: req.body['Content-Type'], //'image/jpg'
};
s3.getSignedUrl('putObject', params, function(err, url) {
if(err) console.log(err);
res.json({url: url});
});
};
This successfully retrieves a presigned url of form...
https://[my-bucket-name].s3.amazonaws.com/1233456?AWSAccessKeyId=[My-ID]&Expires=1517063526&Signature=95eA00KkJnJAgxdzNNafGJ6GRLc%3D
(Do I have to include an expires header?)
Back on the client side (web app) I use angular to generate an HTTP request. I have used both $http and ngFileUpload, with similar lack of success. Here is my ngFileUpload code.
Upload.upload({
url: responce.data.url, //S3 upload url including bucket name
method: 'PUT',
'Content-Type': file.type, //I have tried putting the ContentTyep header all over
headers: {
//'x-amz-acl':'public-read',
'Content-Type': file.type,
},
data: {
file: file,
headers:{'Content-Type': file.type,}
},
})
However, seemingly regardless of how I format my header I always get a 403 error. In the XML of the error it says,
SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.
I don't think CORS is an issue. Originally I was getting some CORS errors but they looked different and I got them to go away with some changes to the S3 bucket CORS settings. I've tried a lot of trial and error setting of the headers for both the request for the presignedURL and PUT request to S3, but I can't seem to find the right combo.
I did notice that when I console.log the 403 response error, the field
config.headers:{Content-Type: undefined, __setXHR_: ƒ, Accept: "application/json, text/plain, */*"}
Is this saying that the Content-Type head isn't set? How can that be when I've set that header everywhere I can think possible? Anyways, been banging my head against the wall of this for a bit...
EDIT: as requested, my Current CORS. (I threw everything in to get rid of the CORS warnings I had earlier. I will pare it down to the essentials only after I get my uploads working.)
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedOrigin>http://localhost:9500</AllowedOrigin>
<AllowedOrigin>https://localhost:9500</AllowedOrigin>
<AllowedOrigin>http://www.example.com</AllowedOrigin>
<AllowedOrigin>https://www.example.com</AllowedOrigin>
<AllowedOrigin>http://lvh.me:9500</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<ExposeHeader>ETag</ExposeHeader>
<AllowedHeader>*</AllowedHeader>
<AllowedHeader>Content-Type</AllowedHeader>
<AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Faced the same issue. Found out that the content-type that I used to create the pre-signed URL was not matching the content-type of the object I was sending to S3. I would suggest you add Expiration header when creating the pre-signed URL (I did too) and check in the console exactly what the content-type is being sent when you do a put to S3. Also, the data just needs to be the file, and not the struct you've created there.
I was having 403 errors with signature not matching and for the life of me could not figure out why. Reading some other examples one of them said it had to be run in us-east-1 because it was not supported in other regions. I was in us-east-2, switched and same exact code worked.
Try using us-east-1
I'm trying to update some articles on a drupal site using React axios. GET and POST requests work, but I can't get PATCH to work. Sending the PATCH request through Postman works just fine. I get the following error using axios:
Method PATCH is not allowed by Access-Control-Allow-Methods in
preflight response.
What am I doing wrong?
Here's my code:
editState(nid, value){
let node = {
"type":[{"target_id":"article","target_type":"node_type"}],
"body":[{"value": value}]
}
let config = {
headers: { 'Content-Type': 'application/json' }
}
axios.patch('http://localhost:8888/d8restapi/node/' + nid + '?_format=json',node,config)
.then((success) => {
console.log(success);
}).catch((error) => {
console.log(error);
});
}
Here are my OPTIONS request Headers:
Request URL:http://localhost:8888/d8restapi/node/16?_format=json
Request Method:OPTIONS
Status Code:200 OK
Remote Address:[::1]:8888
Referrer Policy:no-referrer-when-downgrade
Response Headers
view source
Allow:GET, POST, DELETE, PATCH
Cache-Control:must-revalidate, no-cache, private
Connection:Keep-Alive
Content-language:en
Content-Length:0
Content-Type:application/json
Date:Fri, 03 Nov 2017 21:08:24 GMT
Expires:Sun, 19 Nov 1978 05:00:00 GMT
Keep-Alive:timeout=5, max=98
Server:Apache/2.2.31 (Unix) mod_wsgi/3.5 Python/2.7.12 PHP/7.0.10
mod_ssl/2.2.31 OpenSSL/1.0.2h DAV/2 mod_fastcgi/2.4.6 mod_perl/2.0.9
Perl/v5.24.0
X-Content-Type-Options:nosniff
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Generator:Drupal 8 (https://www.drupal.org)
X-Powered-By:PHP/7.0.10
X-UA-Compatible:IE=edge
Request Headers
view source
Accept:/
Accept-Encoding:gzip, deflate, br
Accept-Language:en,en-US;q=0.8,sv;q=0.6,fi;q=0.4
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:PATCH
Connection:keep-alive
Host:localhost:8888
Origin:http://evil.com/
Referer:http://localhost:3000/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100
Safari/537.36
Query String Parameters
view source
view URL encoded
_format:json
Edit: Tested with Firefox and it works, but it doesn't work in Chrome! Have emptied caches and restarted and done a hard reload to no avail.
Edit 2: Problem solved. I installed another CORS plugin in Chrome. The following works in case anyone is facing the same problem with other CORS plugins:
https://chrome.google.com/webstore/detail/moesif-origin-cors-change/digfbfaphojjndkpccljibejjbppifbc
I've experienced exactly the same thing. Like you, just the combination of react, axios and chrome didn't work.
I solved the issue by changing my CORS chrome extension to this one:
https://chrome.google.com/webstore/detail/access-control-allow-cred/hmcjjmkppmkpobeokkhgkecjlaobjldi
I've similar experience on serverless and reactjs. First I thought the issue is on serverless CORS configuration but it's actually I forgot to put
e.preventDefault()
when submitting the form. As a result, the request is cancelled because the page is loaded although the response is not returned yet.
I'm getting CSRF token missing or incorrect error while doing a POST request to a remote django api from my localhost machine.
My settings on AngularJS:
.config(['$httpProvider', function($httpProvider){
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);
but im still getting the CSRF token missing or incorrect error.
I check what headers are being sent and apparently angular is not sending HTTP_X_CSRFTOKEN.
But I can see that the cookie csrftoken=something is sent.
Does anyone know what is going on?
Request Header
POST /s/login/ HTTP/1.1
Host: server.somewhere.io:8000
Connection: keep-alive
Content-Length: 290
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/plain, */*
Origin: http://localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
Content-Type: application/json;charset=UTF-8
Referer: http://localhost/thesocialmarkt/
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6,pt-BR;q=0.4,pt;q=0.2
Cookie: csrftoken=hiYq1bCNux1mTeQuI4eNgi97qir8pivi; sessionid=1nn1phjab5yd71yfu5k8ghdch2ho6exc
As #Chris Hawkes pointed to this stackoverflow answer given by #Ye Liu
Since the angular app isn't served by django, in order to let the
cookie to be set, angular app needs to do a GET request to django
first.
I verified that as long as you don't make http get request, csrftoken cookie doesn't get set. So only
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
would not work. You first need to make if not real then mock http get request to django rest_framework.
Update: Your comments pushed me to further study it, Please read this blog where is has mentioned as,
CLIENT-SIDE GENERATED CSRF-TOKENS. Have the clients generate and send
the same unique secret value in both a Cookie and a custom HTTP
header. Considering a website is only allowed to read/write a Cookie
for its own domain, only the real site can send the same value in both
headers
So lets try with this single request first.
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
where you are injecting $cookies to the controller/service.
If it works then may be writing interceptors would be good choice, and would help you to debug as well.
I am sure you are using AngularJs version at least 1.2, See this changeset
and in recent commit Angular http service checking csrf with this code,
var xsrfValue = urlIsSameOrigin(config.url)
? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
: undefined;
if (xsrfValue) {
reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
}
So it's necessary that you are sending same token which is present in cookie.
Further to analyse use developer tool of your browser to see request/response with the http request and analyse headers and cookies.
if you are using $http in AngularJS for ajax request and if you are facing any CSRF token issue then use this:
$http.defaults.xsrfCookieName = 'csrftoken';
$http.defaults.xsrfHeaderName = 'X-CSRFToken';
I have zuul server implemented which does the routing to all my microservices. I have a seperate UI project which is in angular. I am trying to make an AJAX call from the UI app to a specific microservices which routes through Zuul but I am getting this error.
XMLHttpRequest cannot load http://localhost:8006/user/v1/userassociations. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access. The response had HTTP status code 403.
But When I directly try to hit the api in local host which is hosted at http://localhost:4444/user/v1/userassociations it works perfectly fine. I have the below CORS configuration added to the actual api.
#Override
public void addCorsMappings(final CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("PUT", "GET", "DELETE", "OPTIONS", "PATCH", "POST");
}
The problem is only happening when i try to hit the api via zuul I tried to add the same configuration to Zuul but it is not working.
I know it is the same origin issue but there must be a solution our microservices are suppose to go public so anyone can make the request from any domain.
Below is the Working AJAX call:- if i change the url to http://localhost:8006/user/v1/userassociations which is via zuul i get the cross origin.
var service = {};
service.userContextCall = function()
{
return $http({
url:'http://localhost:4444/user/v1/userassociations',
method: 'GET',
headers: {'Content-Type':'application/json',
'userContextId':'1234567890123456'}
}).success(function(response){
return response;
}).error(function(error){
return error;
});
};
return service;
Header that Iam receiving for when i hit the api via Zuul.
Request URL:http://localhost:8006/user/v1/userassociations
Request Method:OPTIONS
Status Code:403 Forbidden
Remote Address:[::1]:8006
Response Headers
view source
Allow:GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length:20
Date:Tue, 23 Feb 2016 18:51:15 GMT
Server:Apache-Coyote/1.1
X-Application-Context:apigateway:8006
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, usercontextid
Access-Control-Request-Method:GET
Connection:keep-alive
Host:localhost:8006
Origin:http://localhost:63342
Referer:http://localhost:63342/icpAccountHolder/app/index.html
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
Header when i direclty hit the api the working one.
Request URL:http://localhost:4444/user/v1/userassociations
Request Method:GET
Status Code:200 OK
Remote Address:[::1]:4444
Response Headers
view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:http://localhost:63342
Content-Type:application/json;charset=utf-8
Date:Tue, 23 Feb 2016 18:54:19 GMT
Server:Apache-Coyote/1.1
Transfer-Encoding:chunked
Vary:Origin
X-Application-Context:userassociations-v1
Request Headers
view source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Host:localhost:4444
Origin:http://localhost:63342
Referer:http://localhost:63342/icpAccountHolder/app/index.html
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
userContextId:1234567890123456
Can anyone help me with this.
The fix seems to be using the ANGEL.SR6 spring cloud version instead of BRIXTON. But In case you want to use Brixton this is what i wrote to override the CORS filter in Zuul.
#Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource= new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfig = new CorsConfiguration();
corsConfig.setAllowCredentials(true);
corsConfig.addAllowedOrigin("*");
corsConfig.addAllowedHeader("*");
corsConfig.addAllowedMethod("OPTIONS");
corsConfig.addAllowedMethod("HEAD");
corsConfig.addAllowedMethod("GET");
corsConfig.addAllowedMethod("PUT");
corsConfig.addAllowedMethod("POST");
corsConfig.addAllowedMethod("DELETE");
corsConfig.addAllowedMethod("PATCH");
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfig);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
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.