How to enable CORS (Access-Control-Allow-Origin.*)

2,659 views
Skip to first unread message

Amir Mousavi

unread,
Oct 20, 2016, 4:46:17 PM10/20/16
to Lagom Framework Users
I want to enable my micro-services to be accessible from any origin.
I have an Angular app which runs on port:3000 and for accessing urls of my services at port:9000 I face;
XMLHttpRequest cannot load http://localhost:9000/api/users/list. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
how should I fix it? 

James Roper

unread,
Oct 20, 2016, 8:03:44 PM10/20/16
to Amir Mousavi, Lagom Framework Users
Hi Amir,

The simplest way to get CORS working in Lagom is to use Play's CORS support (Lagom is built on top of Play):


Regards,

James

--
You received this message because you are subscribed to the Google Groups "Lagom Framework Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lagom-framework+unsubscribe@googlegroups.com.
To post to this group, send email to lagom-framework@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lagom-framework/9edf5766-8f4f-43c0-99c6-f871f142eb6d%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
James Roper
Software Engineer

Lightbend – Build reactive apps!
Twitter: @jroper
Message has been deleted

Jules Ivanic

unread,
Oct 26, 2016, 8:32:37 AM10/26/16
to Lagom Framework Users
Did you manage to handle CORS with Lagom ?

Amir Mousavi

unread,
Oct 26, 2016, 1:28:56 PM10/26/16
to Lagom Framework Users
Not yet, I do not know that much about PlayFramework, it is bit complex for me. 


James Roper

unread,
Oct 26, 2016, 6:40:48 PM10/26/16
to Amir Mousavi, Lagom Framework Users
You don't need to know much about Play Framework, you just need to follow the instructions here:


If you have trouble, just ask.

On 27 October 2016 at 04:28, Amir Mousavi <ah62m...@gmail.com> wrote:
Not yet, I do not know that much about PlayFramework, it is bit complex for me. 


--
You received this message because you are subscribed to the Google Groups "Lagom Framework Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lagom-framework+unsubscribe@googlegroups.com.
To post to this group, send email to lagom-framework@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Amir Mousavi

unread,
Oct 27, 2016, 1:29:10 PM10/27/16
to Lagom Framework Users, ah62m...@gmail.com
Hello James,

I fallowed the instruction but I still recive the same error, so my questions are:
  1. "The Filters class can either be in the root package..." the root package of service-api or service-impl ?  I have it in service-impl
  2. also there are two .java files  one  is  
@Inject public Filters(CORSFilter corsFilter) {
        super(corsFilter);
    }
the other one is
@Inject public Filters(AllowedHostsFilter allowedHostsFilter) {
        super(allowedHostsFilter);
    }

        3. Lagom does not generate "application.conf" file so I copied from seeds as it is like => path: service-impl\src\main\resources\application.conf  which only contains  "play.modules.enabled += com.sample.module"  so here I added 
play.filters.cors {
  pathPrefixes = ["/some/path", ...]
  allowedOrigins = ["http://www.example.com", ...]
  allowedHttpMethods = ["GET", "POST"]
  allowedHttpHeaders = ["Accept"]
  preflightMaxAge = 3 days
}

Amir Mousavi

unread,
Oct 27, 2016, 1:42:57 PM10/27/16
to Lagom Framework Users, ah62m...@gmail.com
mistype fix :) 
play.filters.cors {
  pathPrefixes = ["/"]
  allowedOrigins = ["http://localhost:3000"]
  allowedHttpMethods = ["GET", "POST","PUT","DELETE"]

  allowedHttpHeaders = ["Accept"]
  preflightMaxAge = 3 days
}
Also I should mention that I have  libraryDependencies += filters  in   build.sbt

James Roper

unread,
Oct 31, 2016, 10:00:47 PM10/31/16
to Amir Mousavi, Lagom Framework Users
On 28 October 2016 at 04:29, Amir Mousavi <ah62m...@gmail.com> wrote:
Hello James,

I fallowed the instruction but I still recive the same error, so my questions are:
  1. "The Filters class can either be in the root package..." the root package of service-api or service-impl ?  I have it in service-impl
  2. also there are two .java files  one  is  
@Inject public Filters(CORSFilter corsFilter) {
        super(corsFilter);
    }
This is for CORS, it's the one you want.  It should be in the root package of the service-impl.

 
the other one is
@Inject public Filters(AllowedHostsFilter allowedHostsFilter) {
        super(allowedHostsFilter);
    }
This is for preventing access for particular hosts, it's probably not what you want.  But, you can use both filters, add both as constructor parameters and pass both of them to the super constructor.

        3. Lagom does not generate "application.conf" file so I copied from seeds as it is like => path: service-impl\src\main\resources\application.conf  which only contains  "play.modules.enabled += com.sample.module"  so here I added 
play.filters.cors {
  pathPrefixes = ["/some/path", ...]
  allowedOrigins = ["http://www.example.com", ...]
  allowedHttpMethods = ["GET", "POST"]
  allowedHttpHeaders = ["Accept"]
  preflightMaxAge = 3 days
}

In your browser debugging tools, can you check the HTTP requests/responses that are made, to see what headers they have?

 

--
You received this message because you are subscribed to the Google Groups "Lagom Framework Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lagom-framework+unsubscribe@googlegroups.com.
To post to this group, send email to lagom-framework@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Matt Sicker

unread,
Nov 25, 2016, 1:23:33 PM11/25/16
to Lagom Framework Users
I'm not sure what I'm doing wrong here. I added the dependency and a filter class:

public class Filters implements HttpFilters {

private final EssentialFilter[] filters;

@Inject
public Filters(final CORSFilter corsFilter) {
filters = new EssentialFilter[]{corsFilter.asJava()};
}

@Override
public EssentialFilter[] filters() {
return filters;
}
}

I've tried various combinations of settings in my application.conf including just trying the defaults. I've tried specifying and not specifying the Filters class in play.http.filters, yet still, I always get a 404 when my browser attempts an OPTIONS call on the REST API. I've also tried returning a new array every time in my filters() method above, still the same issue. Related, now when I go to http://localhost:8000/ I get some sort of Play error page instead of the service locator thing, but I'm not sure if that's supposed to happen.

James Roper

unread,
Nov 27, 2016, 5:33:16 PM11/27/16
to Matt Sicker, Lagom Framework Users
Hi Matt,

You're right, I've just realised it's not going to work through the service gateway because the service gateway only routes calls that match your service calls by method and path, and since your service calls don't define a route for the OPTIONS method, it won't work.

So first of all, this is how to make it work.  You'll need to define explicit ACLs for the OPTIONS method in the service descriptor:

.withAutoAcl(true)
.withServiceAcls(
  ServiceAcl.methodAndPath(Method.OPTIONS, "/foo/[^/]*/bar"),
  ServiceAcl.methodAndPath(Method.OPTIONS, "/foo")
)

The path argument is a regular expression.  In many situations, you may be able to simplify things, lets say your foo service has control over all paths under the "/foo" root path, ie there are no services that expose any calls under the /foo path than your service in question.  In that case, you could simply turn auto acl off, and define a single ACL for the whole service (auto acl tells Lagom to define one ACL for each service call that matches that service call exactly, if you're defining one that covers the whole service you can therefore turn it off):

.withServiceAcls(
  ServiceAcl.path("/foo(?:/.*)?")
)

A broader discussion to be had is whether CORS should be handled by each service individually, or perhaps it should be handled at the service gateway. Also, maybe the service ACLs should define the CORS rules themselves, CORS is a form of ACL anyway.  Finally, maybe it would make sense for Lagom to extend the scope of its auto ACL feature to allow auto CORS handling.  I'm not sure.

Regards,

James

--
You received this message because you are subscribed to the Google Groups "Lagom Framework Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lagom-framework+unsubscribe@googlegroups.com.
To post to this group, send email to lagom-framework@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

mark dufresne

unread,
Dec 18, 2016, 12:24:25 AM12/18/16
to James Roper, Matt Sicker, Lagom Framework Users
I'd like lagom to include a:

.withCors(true)

list of accepted domains configured in application.conf

Andres March

unread,
Feb 2, 2017, 9:37:10 AM2/2/17
to Lagom Framework Users, ah62m...@gmail.com
Note that lagom 1.2.2 depends upon play 2.5.4 which has a bug in the filter base class https://github.com/playframework/playframework/issues/6237 

Running with play 2.5.5+ resolves the issue.

Samuel Sayag

unread,
Mar 26, 2017, 8:42:38 AM3/26/17
to Lagom Framework Users
Hello,

I would like to renew the subject and sum up what can be done to allow CORS because it doesn't work for me despite the fact that I tried to implement what has been advised in the preceding post. And after hours on it I still cannot figure out why...

I use the 1.3.x version of lagom and try to access my API via Service Gateway(9000) -> MyMicroservice.

1) My service contain this definition (*-api project)

named("behavioral-event").withCalls(
restCall(Method.GET, "/events/log", event_sourcing)
).withAutoAcl(true).withAcls(
ServiceAcl.forMethodAndPathRegex(Method.OPTIONS, "/events/log.*")
)

2) I used a filter class that is under a specific package

import javax.inject.Inject

import play.api.http.DefaultHttpFilters
import play.filters.cors.CORSFilter


class MyFilters @Inject()(corsFilter: CORSFilter)
extends DefaultHttpFilters(corsFilter)

3) I my application.conf (*-impl project) I set these variable. For the moment I aim to be permissive and just wish to see it work

play.http.filters = "com.myapp.impl.MyFilters"


play.filters.cors {

# The path prefixes to filter.
pathPrefixes = ["/events/log"]

# The allowed origins. If null, all origins are allowed.
allowedOrigins = null

# The allowed HTTP methods. If null, all methods are allowed
allowedHttpMethods = null

# The allowed HTTP headers. If null, all headers are allowed.
allowedHttpHeaders = null

# The exposed headers
exposedHeaders = []

# Whether to support credentials
supportsCredentials = false

# The maximum amount of time the CORS meta data should be cached by the client
preflightMaxAge = 6 hour
}


4) I checked that the service is responding using the tool httpie

$ http GET :9000/events/log < myevent.json

$ HTTP/1.1 200 OK
Content-Length: 52
Content-Type: application/json
Date: Sun, 26 Mar 2017 12:41:16 GMT

{
    "sessionId": "afdb8eef-4bff-4619-8956-5df5f8b10eb8"
}


... and got a correct protocol exchange.

5) Then I try to query my running server by injecting js in a external page (stackoverflow for instance)

function send_demo(myjson) {
$.ajax({
url:'http://localhost:9000/events/log',
type:'GET',
data : JSON.stringify(myjson),
dataType: 'json',
contentType: 'application/json; charset=UTF-8',
success: function(data) {
console.log(data);
},
error: function( jqXHR, textStatus, errorThrown ) {
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
}
});
}


var eventJson = {... building my event as a js object ... };

send_demo(eventJson)

6) The preflight CORS request is then send from the browser




7) On the server side I see an exception and really don't know how to handle this:

[warn] c.l.l.g.ServiceGateway - Exception caught in client connection
java.lang.IllegalArgumentException: Illegal character in query at index 12: /events/log?{%22userActionLog%22:{%22minEventDateTime ...


I somebody has an idea about the problem and a possible answer I would be glad to hear it.

Many thanks
Auto Generated Inline Image 1

Tim Moore

unread,
Mar 26, 2017, 8:59:38 PM3/26/17
to Samuel Sayag, Lagom Framework Users
Hi Samuel,

It looks like your JavaScript is trying to send JSON-encoded data in the query string, and the server is expecting this to be a standard set of key=value pairs.

If you need to send a nested data structure in the request, you should do it as a POST request with the JSON content as the request body. You'll need to change both the server and the client to use a POST request instead of a GET.

Cheers,
Tim

--
You received this message because you are subscribed to the Google Groups "Lagom Framework Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lagom-framework+unsubscribe@googlegroups.com.
To post to this group, send email to lagom-framework@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Tim Moore
Senior Engineer, Lagom, Lightbend, Inc.


Samuel Sayag

unread,
Mar 27, 2017, 1:33:57 AM3/27/17
to Lagom Framework Users, samue...@gmail.com
Hi Tim,

Thanks for answering.

So the modify javascript is now (moving content type json)

function send_demo_canal(myjson) {
$.ajax({
url:'http://localhost:9001/events/log',
type:'POST',
data : JSON.stringify(myjson),
success: function(data) {
console.log(data);

}
error: function( jqXHR, textStatus, errorThrown ) {
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
}
});
}

var eventStr = "{...building my event..}";

var eventJson = JSON.parse(eventStr);


Now the POST request is ok.

 

There is still a problem in that that the response from the site is in error in the console i.e no answer is coming (I am suppose to receive a session).
I get this in the javascript console with the successful sending.

08:26:47.009 Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:9001/events/log. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). 1 (unknown)

Isn't the CORS filter suppose to answer this problem by modifying the header and add it the necessary part (Access-Control-Allow-Origin) or whatever may be added ?

Do I have to modify the header of the response through Lagom i.e the header is not just concerning the preflight request ?

Many thanks
To unsubscribe from this group and stop receiving emails from it, send an email to lagom-framewo...@googlegroups.com.
To post to this group, send email to lagom-f...@googlegroups.com.
Auto Generated Inline Image 1

Ignasi Marimon-Clos i Sunyol

unread,
Mar 27, 2017, 11:45:07 AM3/27/17
to Samuel Sayag, Lagom Framework Users
Hi Samuel,

I spoke with Tim earlier and we noticed you were trying to enable the filters using Guice.

class MyFilters @Inject()(corsFilter: CORSFilter)
Lagom Scala differs from Play Scala/Java and Lagom Java in that it doesn't use Guice as it's default Dependency Injection method. Instead, Lagom Scala uses the thin cake pattern and so features are injected via trait composition.

To enable CORS filters in a given Lagom service you then need to mix in Play's CORSComponents and then setup your application filters in your Loader like this:


import play.filters.cors.CORSComponents
// ...
abstract class MyApplication(context: LagomApplicationContext)
extends LagomApplication(context)
with ...
with CORSComponents // 1) mix in
     {
override lazy val httpFilters: Seq[EssentialFilter] = Seq(corsFilter) // 2) enable it

// other stuff for your app here...

}
The final piece of the puzzle is to include the dependency in your build.sbt so that you can import CORSComponents:


lazy val `my-impl` = (project in file("my-impl"))
.enablePlugins(LagomScala)
.settings(
libraryDependencies ++= Seq(
...,
filters, // <--- this is part of PlayImport, brought in by Lagom plugin.
...
)
)
.settings(lagomForkedTestSettings: _*)
.dependsOn(`my-api`)
In this snippet, filters is actually Play's filters project. It is brought in by Lagom's plugin so you don't addanything else on your build.sbt or plugins.sbt. 

Cheers,

  


To unsubscribe from this group and stop receiving emails from it, send an email to lagom-framework+unsubscribe@googlegroups.com.
To post to this group, send email to lagom-framework@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lagom-framework/e6425b71-bbd0-46ba-bdd5-7cf7f4b479ab%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Ignasi Marimon-Clos
Software Developer @ Lagom

Tim Pigden

unread,
Mar 30, 2017, 4:17:04 AM3/30/17
to Lagom Framework Users, boa...@gmail.com
James - I too will hit this problem fairly soon I imagine. On this "broader discussion", given that I have upwards of 10 services by now, is it  a problem enabling each for CORS? Can this cause a clash somehow or is it safe?
To unsubscribe from this group and stop receiving emails from it, send an email to lagom-framewo...@googlegroups.com.
To post to this group, send email to lagom-f...@googlegroups.com.

Ignasi Marimon-Clos i Sunyol

unread,
Mar 30, 2017, 12:25:08 PM3/30/17
to Tim Pigden, Lagom Framework Users, boa...@gmail.com

On Thu, Mar 30, 2017 at 10:17 AM, Tim Pigden <tim.p...@optrak.com> wrote:
James - I too will hit this problem fairly soon I imagine. On this "broader discussion", given that I have upwards of 10 services by now, is it  a problem enabling each for CORS? Can this cause a clash somehow or is it safe?

Hi Tim,

If you setup an ACL for each possible route you need CORS enabled for in the appropriate Service then it should be fine.

Let me review Samuel's code:

named("behavioral-event").withCalls(
   restCall(Method.GET, "/events/log", event_sourcing)
)
.withAutoAcl(true)
.withAcls(
   ServiceAcl.forMethodAndPathRegex(Method.OPTIONS, "/events/log.*")
)

That Service could be deployed with 10 other services and, as long as "/events/log" can be routed without ambiguity it all should work. You are duplicating every ACL'd endpoint to add support for `OPTIONS`.

Cheers,
Reply all
Reply to author
Forward
0 new messages