How to fix 'Access-Control-Allow-Origin .Origin 'null' is therefore not allowed access.' in scala as backend - scala

I am using angularjs in my front-end and this is the piece of code where i call my loclhost , todo variable should have the value , but i get error
Failed to load http://localhost:8080/Cart/1: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
When i use it directly i got the json value.
var cartResource = $resource('http://localhost:8080/Cart/:cartId',
{cartId: '#id'});
$scope.cart1 = cartResource.get({cartId: 1},function(todo) {
// success
console.log("k","k")
}, function(errResponse) {
console.log("nooooo",errResponse)
});

You might probably enable the CORS filter on your backend! If your backend server is Play Framework, here is some documentation on how this is done:
https://www.playframework.com/documentation/2.6.x/CorsFilter

For me the problem was that i have to set the origin in my headers beside cors sittings as in back-end code
$resource('http://localhost:8080/cart/:cartId',
{cartId :'#cartId' },
{ update: { method: 'PUT' }},
{ headers : { 'Origin': 'http://localhost:8080' }} );

Related

Can't set Access-Control-Allow-Credentials header for REST API

I'm having the following issues:
I need to allow CORS only on a specific domain
I need to make sure that secure cookies are sent along with the cross-origin request.
API Gateway specifies '*' as the Access-Control-Allow-Origin header and I need to only allow "example.com".
I found that I can do this by adding the following in override.ts in the rest API resource folder:
import { AmplifyApiRestResourceStackTemplate } from '#aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiRestResourceStackTemplate) {
// Change the default CORS response header Access-Control-Allow-Origin from "'*'" to the API's domain
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Origin'] = {
'Fn::Sub': "'https://www.example.com'"
};
}
This seems unreasonably hacky, but whatever.
But I can't seem to solve for the Access-Control-Allow-Credentials header... This doesn't work:
import { AmplifyApiRestResourceStackTemplate } from '#aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiRestResourceStackTemplate) {
// Change the default CORS response header Access-Control-Allow-Origin from "'*'" to the API's domain
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Origin'] = {
'Fn::Sub': "'https://www.example.com'"
};
// ADDING THIS ...
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Credentials'] = "true";
}
I get multiple errors, but it's basically complaining with this error for each of my REST endpoints:
Unable to put integration response on 'OPTIONS' for resource at path '/oauth/hubspot': Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression specified: true]
I get similar errors if I try any of the following:
// with quotes inside quotes
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Credentials'] = "'true'";
// this structure
resources.restApi.body.paths['/v1'].options['x-amazon-apigateway-integration'].responses.default.responseParameters['method.response.header.Access-Control-Allow-Credentials'] = {
'Fn::Sub': "'true'"
};
The thing is, I could easily do all this myself if Amplify would just let me override how I handle the OPTIONS request, and send it to my lambda function....
VICTORY!
I'd still be interested in any suggested approaches, but this worked for me:
// This file is used to override the REST API resources configuration
import { AmplifyApiRestResourceStackTemplate } from '#aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiRestResourceStackTemplate) {
delete resources.restApi.body.paths['/v1'].options;
delete resources.restApi.body.paths['/v1/{proxy+}'].options;
}
Basically, it's me telling Amplify to get out of the way and let me handle the OPTIONS request myself. So this leaves the "ANY" method on the endpoint so that the OPTIONS request flows through to the LAMBDA that's already configured. I already had the code in there to handle OPTIONS requests, so... It. Just. Worked.
I know it's been six months since you asked this question, but it's something i've just been smashing my head against now.
I had exactly the same issue:
I need CORS across several domains, but I can't use Access-Control-Allow-Origin: '*' because in the browser I am calling the api with { withCredentials: true }.
My Api's back into a lambda function which correctly handles the CORS preflight on the OPTION request. (ie. it returns Access-Control-Allow-Origin: https://permitted.origin.goes.here and associated headers).
But I get CORS errors because the AWS API Gateway response for OPTION is using a predefined MOCK response, which does not allow any other value for Access-Control-Allow-Origin than '*'.
(this was all generated by Amplify).
Anyways, I tried your method of deleting the OPTION handler, but that still did not work for me.
Eventually, after configuring it correctly in the AWS API Gateway interface, exporting the swagger and replicating that in the override.ts file, I finally got it cleanly working.
this was my code in override.ts:
import { AmplifyApiRestResourceStackTemplate } from '#aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiRestResourceStackTemplate) {
const { paths } = resources.restApi.body;
Object.keys(paths).forEach((path) => {
if (!!paths[path].options) {
const uri = paths[path]['x-amazon-apigateway-any-method']['x-amazon-apigateway-integration'].uri;
paths[path].options = {
"responses" : {
"200" : {
"description" : "200 response",
"headers" : {
"Access-Control-Allow-Credentials" : {
"type" : "string"
},
"Access-Control-Allow-Origin" : {
"type" : "string"
},
"Access-Control-Allow-Methods" : {
"type" : "string"
},
"Access-Control-Allow-Headers" : {
"type" : "string"
}
}
}
},
"x-amazon-apigateway-integration" : {
"httpMethod" : "POST",
"uri" : uri,
"responses" : {
"default" : {
"statusCode" : "200"
}
},
"passthroughBehavior" : "when_no_match",
"contentHandling" : "CONVERT_TO_TEXT",
"type" : "aws_proxy"
}
}
}
});
}
Now I can return secure cookies to a browser app from the AWS REST API without choking on CORS errors.
good luck!

Axios sending OPTIONS instead GET

I'm trying to make api calls locally in a react app using axios.
I've already added django-cors-headers and followed the documentation, but it does not seem to be working.
I always get the error:
localhost/:1 Access to XMLHttpRequest at 'http://127.0.0.1:8000/api/todos/' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.
my base.py:
INSTALLED_APPS = [
# ...
"corsheaders",
"rest_framework",
"todo",
"api",
]
MIDDLEWARE = [
# ...
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
# ...
]
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = False
In my react app:
const [todos, setTodos] = useState({})
useEffect(
() => {
axios.get(
api_url, {
headers: {
"Access-Control-Allow-Origin": "*",
}
}
).then(
res => {
setTodos(res.data);
console.log(res.data)
}
).catch(
err => {
console.log(err)
}
)
}, []
)
Note, even without configuring a whitelist and reverting the CORS settings to:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ALLOW_CREDENTIALS = True
I still manage to get the data in a get call using httpie, just running http + url.
Note 2: When the axios tries to get the data, I get this on the terminal running the Django app:
[04/Jun/2019 18:15:29] "OPTIONS /api/todos/ HTTP/1.1" 200 0
IMPORTANT EDIT:
The problem does not seem to be with my server, I used fetch instead of Axios and everything occurred normally. With Axios, my server was getting an OPTIONS method, and, I do not know why, I was giving this problem with CORS.

Using cors across two independently running local apps

I have two applications running indepepently, one taking care of my backend (written in Scala Play) then other one being my frontend (Angular with a static Node server).
I try to request data on my frontend through a form from my Scala Play app.
this.insertionOrder = function(){
$http({
method: 'POST',
url: '//localhost:9000/insertsupplier',
header: {
'Content-type': 'application/json',
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods' : 'POST, GET, OPTIONS'
},
data:{
'supplier_id': 1,
'suppliername': 'xxx',
'supplier_address': 'xxx xxx xxx xxx',
'contact': 'xxx#xxx.com',
'datecreated': '2017-10-15T09:45:00.000UTC+00:00'
}
}).then(function(response){
console.log(response);
return response.data
}, function(err){
console.log(err)
});
};
and my play app looks like this:
Controller:
def insertsupplier = Action(parse.json) { implicit request =>
val json = request.body
val sup: Supplier = json.as[Supplier]
sup.insertSql(con)
Ok("test")
}
my build.sbt contains filters:
libraryDependencies ++= Seq(
cache ,
ws,
jdbc,
filters
)
and the MyFilters.scala
class MyFilters (implicit inj:Injector) extends HttpFilters with Injectable {
implicit val as = inject[ActorSystem]
implicit val mat = ActorMaterializer()
val gzip = new GzipFilter()
val csrf = inject[CSRFFilter]
val cors = inject[CORSFilter]
//println(s"csrf: ${csrf.tokenProvider}")
//println(s"csrf: ${csrf.tokenProvider.generateToken}")
def filters = Seq(gzip,cors,csrf)
}
and finally my application.conf
play.filters.cors {
pathPrefixes = ["*"]
allowedOrigins = ["http://localhost:3000","https://localhost:3000","http://localhost:3000/*","https://localhost:3000/*"]
allowedHttpMethods = ["GET", "POST", "OPTIONS"]
allowedHttpHeaders = ["Accept"]
# preflightMaxAge = 1 hour
}
play.filters.csrf {
cookie.name = "XSRF-TOKEN"
header.name = "X-XSRF-TOKEN"
}
play.http.filters = "filters.MyFilters"
I keep getting the error "XMLHttpRequest cannot load http://localhost:9000/insertsupplier. 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:3000' is therefore not allowed access. The response had HTTP status code 500."
I feel that first my CORS setup is wrong anyway --> What needs to be changed? I am new to this.
And am I even able to use cors in order to access data from localhost?
It may be that there’s nothing wrong at all with your CORS setup, because the “The response had HTTP status code 500” part of the error message indicates that the actual immediate problem is that an OPTIONS request to your server caused some unexpected failure on the server side.
From just the code snippets in the question, it’s not possible to tell what might be causing that 500 failure in the server side. It may be completely unrelated to your CORS config.
But regardless, you should drop the parts of your frontend code that are adding the header 'Access-Control-Allow-Origin' : '*', and 'Access-Control-Allow-Methods'. Those headers are response headers that must be sent from the server side, not from frontend code.
But the 'Content-type': 'application/json' part of your frontend code is valid, and assuming it’s actually necessary in order to get the expected response from the server, there’s no way you can make your request without triggering browsers to do a CORS preflight OPTIONS request.
But if the CORS preflight OPTIONS request fails, the browser never gets around to trying the POST request your code is actually attempting to send. And if your backend responds to that OPTIONS request with a 500 response, then the preflight fails. It must instead respond with a 200 or 204.

How to handle Header "Access-Control-Allow-Origin" using ampersand-rest-collection?

Trying to request cors request with code:
export default Collection.extend({
model: person,
url () {
return 'http://127.0.0.1:5000/person/'
},
ajaxConfig: function () {
return {
headers: {
'Access-Control-Allow-Origin': 'http//:127.0.0.1:3000'
},
xhrFields: {
withCredentials: false
}
};
},
})
I'm sending request with http//:127.0.0.1:3000 but if use * i still get error below
XMLHttpRequest cannot load http://127.0.0.1:5000/person/. 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:3000' is therefore not allowed access.
How to handle this kind of request?
Rather than your Collection sending the 'Access-Control-Allow-Origin': 'http//:127.0.0.1:3000' in its request headers, your server at http://127.0.0.1:5000 needs to send it in its response headers to the pre-flight request.
If you can give some details about the server setup, I can help you to figure out how to add the header to the response.

AngularJS ngResrouce REST Authentication

I'm trying to learn AngularJS. I'm try to make a simple authenticated get request to a REST api. At this point, i'm just trying to get a response back. I keep getting invalid key because I can't seem to send the headers properly.
angular.module('App', ['ngResource']);
function AppCtrl($scope, $resource){
$scope.app = $resource('https://theapiurl.com/parameter=:action',
{action:'My Parameter works fine!'},
{method: 'GET'},
{headers: 'auth-key' : 'key'});
$scope.app.get();
}
I just can't seem to get the header to send. Thanks for reading.
If you are using angular-resource 1.1.x+ the following should work:
angular.module('App', ['ngResource']);
function AppCtrl($scope, $resource){
$scope.app = $resource('https://theapiurl.com/parameter=:action',
{
action:'My Parameter works fine!'
},
{
get: {
method: 'GET',
headers : { 'auth-key' : 'key' }
}
});
$scope.app.get();
}
If you are using 1.0.x branch this won't work. I believe the only alternative is to set global default headers in $httpProvider, or to user $http directly (not using $resource). Here's how you would set the headers globally:
$httpProvider.defaults.headers.get['auth-key'] = 'key';
To avoid setting the header in every resource you could use an interceptor:
app.config(function($httpProvider) {
$httpProvider.interceptors.push(function($q) {
return {
'request': function(config) {
config.headers['auth-key'] = 'key';
return $q.when(config);
}
};
});
});